def __init__(self, name, ctype, data, minwidth=2, color=None): self._name = name self._type = ctype self._color = color self._alignleft = ctype in (ltype.str, ltype.time) # May be empty if the column has 0 rows. self._strdata = list(self._stringify_data(data)) self._rmargin = " " if ctype == ltype.real: self._align_at_dot() if self._strdata: self._width = max(term.length(name), minwidth, max(len(field) for field in self._strdata)) else: self._width = max(term.length(name), minwidth)
def __init__(self, name, ctype, data, color=None): self._name = name self._type = ctype self._color = color self._alignleft = ctype in {"str", "enum", "time"} # May be empty if the column has 0 rows. self._strdata = list(self._stringify_data(data)) self._rmargin = " " if ctype == "real": self._align_at_dot() if self._strdata: self._width = max(term.length(name), 2, max(len(field) for field in self._strdata)) else: self._width = max(term.length(name), 2)
def _format(self, value): diff = self._width - term.length(value) if diff >= 0: whitespace = " " * diff if self._alignleft: return value + whitespace else: return whitespace + value else: return value[:self._width - 1] + "…"
def _draw(self): self._fetch_data() columns = [] # Process key columns keynames = self._conn.key_names keydata = self._conn.key_data keyltypes = self._conn.key_ltypes keystypes = self._conn.key_stypes if keydata: for i, colname in enumerate(keynames): if self._show_types and keystypes[i]: colname = term.color("cyan", keystypes[i].name) oldwidth = self._colwidths.get(colname, 2) col = _Column(name=colname, ctype=keyltypes[i], data=keydata[i], color="bright_black", minwidth=oldwidth) self._colwidths[colname] = col.width columns.append(col) if keynames[0]: columns[-1].margin = "" columns.append(_Divider()) # Process data columns viewnames = self._conn.view_names viewltypes = self._conn.view_ltypes viewstypes = self._conn.view_stypes viewdata = self._conn.view_data if viewdata: for i, colname in enumerate(viewnames): if self._show_types: colname = term.color("cyan", viewstypes[i].name) oldwidth = self._colwidths.get(i + self._view_col0, 2) col = _Column(name=colname, ctype=viewltypes[i], data=viewdata[i], minwidth=oldwidth) if self._view_ncols < self._conn.frame_ncols: col.width = min(col.width, _Column.MAX_WIDTH) self._colwidths[i + self._view_col0] = col.width columns.append(col) columns[-1].margin = "" # Adjust widths of columns total_width = sum(col.width + len(col.margin) for col in columns) extra_space = term.width - total_width - DataFrameWidget.RIGHT_MARGIN if extra_space > 0: if self._view_col0 + self._view_ncols < self._conn.frame_ncols: self._view_ncols += max(1, extra_space // 8) self._draw() return elif self._view_col0 > 0: w = self._fetch_column_width(self._view_col0 - 1) if w + 2 <= extra_space: self._view_col0 -= 1 self._view_ncols += 1 self._max_col0 = self._view_col0 self._draw() return else: if self._max_col0 == self._view_col0: self._max_col0 += 1 available_width = term.width - DataFrameWidget.RIGHT_MARGIN for i, col in enumerate(columns): col.width = min(col.width, available_width) available_width -= col.width + len(col.margin) if available_width <= 0: available_width = 0 col.margin = "" else: self._view_ncols = i + 1 # Generate the elements of the display at_last_row = (self._view_row0 + self._view_nrows == self._conn.frame_nrows) grey = lambda s: term.color("bright_black", s) header = ["".join(col.header for col in columns), grey("".join(col.divider for col in columns))] rows = ["".join(col.value(j) for col in columns) for j in range(self._view_nrows)] srows = plural_form(self._conn.frame_nrows, "row") scols = plural_form(self._conn.frame_ncols, "column") footer = ["" if at_last_row else grey("..."), "[%s x %s]" % (srows, scols), ""] # Display hint about navigation keys if self._show_navbar: remaining_width = term.width if self._jump_string is None: nav_elements = [grey("Press") + " q " + grey("to quit"), " ↑←↓→ " + grey("to move"), " wasd " + grey("to page"), " t " + grey("to toggle types"), " g " + grey("to jump")] for elem in nav_elements: l = term.length(elem) if l > remaining_width: break remaining_width -= l footer[2] += elem else: footer[2] = grey("Go to (row:col): ") + self._jump_string # Render the table lines = header + rows + footer term.rewrite_lines(lines, self._n_displayed_lines) self._n_displayed_lines = len(lines) - 1
def draw(self): data = self._fetch_data() colnames = data["names"] coltypes = data["types"] stypes = data["stypes"] coldata = data["columns"] indices = data["indices"] # Create column with row indices oldwidth = self._colwidths.get("index", 3) indexcolumn = _Column(name="", ctype="str", data=indices) indexcolumn.color = term.bright_black indexcolumn.margin = " " indexcolumn.width = max(oldwidth, indexcolumn.width) self._colwidths["index"] = indexcolumn.width # Data columns columns = [indexcolumn] for i in range(self._view_ncols): if self._show_types == 1: name = term.green(coltypes[i]) elif self._show_types == 2: name = term.cyan(stypes[i]) else: name = colnames[i] oldwidth = self._colwidths.get(i + self._view_col0, 0) col = _Column(name=name, ctype=coltypes[i], data=coldata[i]) col.width = max(col.width, oldwidth) if self._view_ncols < self._frame_ncols: col.width = min(col.width, _Column.MAX_WIDTH) self._colwidths[i + self._view_col0] = col.width columns.append(col) columns[-1].margin = "" # Adjust widths of columns total_width = sum(col.width + len(col.margin) for col in columns) extra_space = term.width - total_width - DataFrameWidget.RIGHT_MARGIN if extra_space > 0: if self._view_col0 + self._view_ncols < self._frame_ncols: self._view_ncols += max(1, extra_space // 8) return self.draw() elif self._view_col0 > 0: w = self._fetch_column_width(self._view_col0 - 1) if w + 2 <= extra_space: self._view_col0 -= 1 self._view_ncols += 1 self._max_col0 = self._view_col0 return self.draw() else: if self._max_col0 == self._view_col0: self._max_col0 += 1 available_width = term.width - DataFrameWidget.RIGHT_MARGIN for i, col in enumerate(columns): col.width = min(col.width, available_width) available_width -= col.width + len(col.margin) if available_width <= 0: available_width = 0 col.margin = "" else: self._view_ncols = i + 1 # Generate the elements of the display grey = term.bright_black header = [ "".join(col.header for col in columns), grey("".join(col.divider for col in columns)) ] rows = [ "".join(col.value(j) for col in columns) for j in range(self._view_nrows) ] srows = plural_form(self._frame_nrows, "row") scols = plural_form(self._frame_ncols, "column") footer = ["", "[%s x %s]" % (srows, scols), ""] # Display hint about navigation keys if self._show_navbar: remaining_width = term.width if self._jump_string is None: nav_elements = [ grey("Press") + " q " + grey("to quit"), " ↑←↓→ " + grey("to move"), " wasd " + grey("to page"), " t " + grey("to toggle types"), " g " + grey("to jump") ] for elem in nav_elements: l = term.length(elem) if l > remaining_width: break remaining_width -= l footer[2] += elem else: footer[2] = grey("Go to (row:col): ") + self._jump_string # Render the table lines = header + rows + footer out = (term.move_x(0) + term.move_up * self._n_displayed_lines + (term.clear_eol + "\n").join(lines) + term.clear_eol) print(out, end="") self._n_displayed_lines = len(lines) - 1