Skip to content

Commit

Permalink
updates in doc, add screenshot functions to Table
Browse files Browse the repository at this point in the history
  • Loading branch information
hanjinliu committed Jan 7, 2023
1 parent aa031db commit 4caaa44
Show file tree
Hide file tree
Showing 13 changed files with 200 additions and 77 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@ release:
images:
python ./image/generate_figs.py

images-rst:
python ./rst/fig/generate_figs.py

watch-rst:
watchfiles "sphinx-build -b html ./rst ./_docs_temp" rst
11 changes: 2 additions & 9 deletions image/generate_figs.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,10 @@ def sort_example():
def colormap_example():
viewer = TableViewer()
sheet = viewer.open_sample("iris", type="spreadsheet")
sheet.background_colormap(
"species",
sheet["species"].background_color.set(
{"setosa": "lightblue", "versicolor": "orange", "virginica": "violet"},
)

@sheet.foreground_colormap("petal_width")
def _cmap(v):
v = float(v)
r = (v - 0.1) / 2.4 * 255
b = (1 - (v - 0.1) / 2.4) * 255
return [r, 255, b, 255]
sheet["petal_width"].text_color.set(interp_from=["red", "blue"])

viewer.resize(100, 100)
sheet.move_iloc(53, 4)
Expand Down
Binary file added rst/fig/cell_labels.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified rst/fig/colormap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 0 additions & 43 deletions rst/fig/generage_figures.py

This file was deleted.

79 changes: 79 additions & 0 deletions rst/fig/generate_figs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
from __future__ import annotations

from typing import Callable
from functools import wraps
from pathlib import Path
import numpy as np

from tabulous import TableViewer, commands as cmds
from tabulous.widgets import TableBase

_ALL_FUNCTIONS = []
_DIR_PATH = Path(__file__).parent


def register(f: Callable[[], TableViewer | TableBase]):
@wraps(f)
def wrapped():
if out := f():
out.save_screenshot(_DIR_PATH / f"{f.__name__}.png")
if isinstance(out, TableViewer):
out.close()

_ALL_FUNCTIONS.append(wrapped)
return wrapped


def main():
for f in _ALL_FUNCTIONS:
f()

@register
def colormap():
viewer = TableViewer()
table = viewer.open_sample("iris")

# set a continuous colormap to the "sepal_length" column
lmin = table.data["sepal_length"].min()
lmax = table.data["sepal_length"].max()
lrange = lmax - lmin

@table.text_color.set("sepal_length")
def _(x: float):
red = np.array([255, 0, 0, 255], dtype=np.uint8)
blue = np.array([0, 0, 255, 255], dtype=np.uint8)
return (x - lmin) / lrange * blue + (lmax - x) / lrange * red

# set a discrete colormap to the "sepal_width" column
@table.background_color.set("sepal_width")
def _(x: float):
return "green" if x < 3.2 else "violet"

viewer.resize(100, 100)
table.move_iloc(57, 2)
return viewer

@register
def cell_labels():
viewer = TableViewer()
sheet = viewer.add_spreadsheet(np.arange(4))
sheet.cell[1, 1] = "&=np.mean(df.iloc[:, 0])"
sheet.cell.label[1, 1] = "mean: "
viewer.native.setMinimumSize(1, 1)
viewer.resize(120, 180)
return sheet

@register
def tile_tables():
viewer = TableViewer()
sheet0 = viewer.add_spreadsheet(name="A")
sheet0.cell[0:5, 0:5] = "A"
sheet1 = viewer.add_spreadsheet(name="B")
sheet1.cell[0:5, 0:5] = "B"
viewer.tables.tile([0, 1])
viewer.resize(100, 100)
return viewer


if __name__ == "__main__":
main()
Binary file added rst/fig/tile_tables.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 7 additions & 3 deletions rst/main/columnwise_settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,14 @@ must return a RGBA array (0-255) or a standard color name.
.. code-block:: python
viewer = TableViewer()
viewer.open_sample("iris")
table = viewer.open_sample("iris")
# set a continuous colormap to the "sepal_length" column
@table.foreground_colormap("sepal_length")
lmin = table.data["sepal_length"].min()
lmax = table.data["sepal_length"].max()
lrange = lmax - lmin
@table.text_color.set("sepal_length")
def _(x: float):
red = np.array([255, 0, 0, 255], dtype=np.uint8)
blue = np.array([0, 0, 255, 255], dtype=np.uint8)
Expand All @@ -35,7 +39,7 @@ must return a RGBA array (0-255) or a standard color name.
.. code-block:: python
# set a discrete colormap to the "sepal_width" column
@table.background_colormap("sepal_width")
@table.background_color.set("sepal_width")
def _(x: float):
return "green" if x < 3.2 else "violet"
Expand Down
70 changes: 52 additions & 18 deletions rst/main/table_advanced.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ Field Attributes of Tables
There are several fields that can be used to interact with table state and data.
Operations via table fields are undoable.

``cell``
--------
``cell`` field
--------------

The :attr:`cell` field provides several methods to get access to table cells.

Expand All @@ -94,10 +94,10 @@ for more detail.
- :attr:`loc` and :attr:`iloc` does not check data type.
- Table will not be updated immediately.

The :attr:`cell` field has sub-fields.
The :attr:`cell` field has several sub-fields.

Cell references
^^^^^^^^^^^^^^^
``ref``
^^^^^^^

All the in-cell functions with cell references are accessible via :attr:`ref` sub-field.

Expand All @@ -108,18 +108,45 @@ All the in-cell functions with cell references are accessible via :attr:`ref` su
print(table.cell.ref[0, 1]) # get the slot function at (0, 1)
print(table.cell.ref[1, 1]) # KeyError
Cell labels
^^^^^^^^^^^
``label``
^^^^^^^^^

table.cell.label
Cell labels can be edited programmatically using this sub-field.

.. code-block:: python
print(table.cell.label[0, 1])
table.cell.label[0, 1] = "mean ="
table.cell.label[0, 1] = "mean:"
``text``
^^^^^^^^

Displayed (formatted) text in cells can be obtained using this sub-field.

.. code-block:: python
print(table.cell.text[0, 1])
``text_color``
^^^^^^^^^^^^^^

Displayed text color (8-bit RGBA) in cells can be obtained using this sub-field.

.. code-block:: python
print(table.cell.text_color[0, 1])
``plt``
-------
``background_color``
^^^^^^^^^^^^^^^^^^^^

Displayed background color (8-bit RGBA) in cells can be obtained using this sub-field.

.. code-block:: python
print(table.cell.text_color[0, 1])
``plt`` field
-------------

Since plotting is a common use case for table data analysis, plot canvases are implemented
by default. The basic plot functions are available in :attr:`plt` field with the
Expand All @@ -137,8 +164,8 @@ similar API as ``matplotlib.pyplot`` module.
You can also update plot canvas from the "Plot" tab of the toolbar.


``index`` / ``columns``
-----------------------
``index`` / ``columns`` field
-----------------------------

:attr:`index` and :attr:`column` behaves very similar to :attr:`index` and :attr:`column`
of :class:`pandas.DataFrame`.
Expand All @@ -160,8 +187,8 @@ of :class:`pandas.DataFrame`.
:attr:`index` and `columns` support custom contextmenu registration. See
:doc:`register_action` for more detail.

``proxy``
---------
``proxy`` field
---------------

Proxy includes sorting and filtering, that is, deciding which rows to be shown and
which not to be.
Expand All @@ -174,8 +201,8 @@ which not to be.
See :doc:`sort_filter` for more details.

``dtypes``
----------
``dtypes`` field
----------------

:attr:`dtypes` is a :class:`SpreadSheet`-specific field. Since a spreadsheet has to
determine the data type of each column, you may occasionally want to tell which
Expand Down Expand Up @@ -275,7 +302,14 @@ also returns the same table as before. When tab "A" or "B" is clicked, the tiled
table with "A" and "B" is shown as ``A|B``.

You can tile the current table and the table next to it by shortcut ``Ctrl+K, ^``.
You can also programmatically tile tables by calling ``viewer.tables.tile([0, 1, 2])``.
You can also programmatically tile tables by calling :meth:`viewer.tables.tile`.

.. code-block:: python
viewer.tables.tile([0, 1]) # tile the 0th and 1st tables
viewer.tables.tile([0, 1, 3]) # tile tables at indices [0, 1, 3]
.. image:: ../fig/tile_tables.png

Untiling
^^^^^^^^
Expand Down
24 changes: 24 additions & 0 deletions rst/main/user_interface.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,30 @@ During editing, the text will always be validated. Invalid text will be shown in
table cells, you can set any validation rules (see :doc:`/main/columnwise_settings`). For
the table headers, duplicated names are not allowed and considered to be invalid.

Add cell labels
---------------

People using spreadsheets usually want to name some of the cells. For instance, when you
calculated the mean of a column, you want to name the cell as "mean". Usually, it is done
by editing one of the adjacent cells.

+---+------+
| A | B |
+===+======+
| 1 | mean |
+---+------+
| 2 | 2.5 |
+---+------+
| 3 | |
+---+------+
| 4 | |
+---+------+

In :mod:`tabulous`, however, you can directly name the cell using cell label. You can edit
cell labels by ``F3`` key.

.. image:: ../fig/cell_labels.png

Excel-style data evaluation
---------------------------

Expand Down
16 changes: 16 additions & 0 deletions tabulous/_qt/_table/_base/_table_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,22 @@ def parentViewer(self) -> _QtMainWidgetBase:
"""Return the parent table viewer."""
return self._qtable_view.parentViewer()

def screenshot(self):
"""Create an array of pixel data of the current view."""
import qtpy

img = self.grab().toImage()
bits = img.constBits()
h, w, c = img.height(), img.width(), 4
if qtpy.API_NAME.startswith("PySide"):
arr = np.array(bits).reshape(h, w, c)
else:
bits.setsize(h * w * c)
arr: np.ndarray = np.frombuffer(bits, np.uint8)
arr = arr.reshape(h, w, c)

return arr[:, :, [2, 1, 0, 3]]

def _switch_head_and_index(self, axis: int = 1) -> None:
"""Switch the first row/column data and the index object."""
self.setProxy(None) # reset filter to avoid unexpected errors
Expand Down
8 changes: 4 additions & 4 deletions tabulous/widgets/_mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,10 @@ def close(self):
"""Close the viewer."""
return self._qwidget.close()

def resize(self, width: int, height: int):
"""Resize the table viewer."""
return self._qwidget.resize(width, height)

def _link_events(self):
_tablist = self._tablist
_qtablist = self._qwidget._tablestack
Expand Down Expand Up @@ -664,10 +668,6 @@ def reset_choices(self, *_):
if hasattr(widget, "reset_choices"):
widget.reset_choices()

def resize(self, width: int, height: int):
"""Resize the table viewer."""
return self._qwidget.resize(width, height)


class DummyViewer(_AbstractViewer):
"""
Expand Down
Loading

0 comments on commit 4caaa44

Please sign in to comment.