Skip to content

More table documentation #12880

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 6, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 159 additions & 49 deletions lib/matplotlib/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ def set_text_props(self, **kwargs):

class CustomCell(Cell):
"""
A subclass of Cell where the sides may be visibly toggled.
A `.Cell` subclass with configurable edge visibility.
"""

_edges = 'BRTL'
Expand All @@ -196,6 +196,15 @@ def __init__(self, *args, visible_edges, **kwargs):

@property
def visible_edges(self):
"""
The cell edges to be drawn with a line.

Reading this property returns a substring of 'BRTL' (bottom, right,
top, left').

When setting this property, you can use a substring of 'BRTL' or one
of {'open', 'closed', 'horizontal', 'vertical'}.
"""
return self._visible_edges

@visible_edges.setter
Expand All @@ -216,9 +225,7 @@ def visible_edges(self, value):
self.stale = True

def get_path(self):
"""
Return a path where the edges specified by _visible_edges are drawn.
"""
"""Return a `.Path` for the `.visible_edges`."""
codes = [Path.MOVETO]

for edge in self._edges:
Expand All @@ -239,13 +246,7 @@ def get_path(self):

class Table(Artist):
"""
Create a table of cells.

Table can have (optional) row and column headers.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these points (this line and the following two) not relevant?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. is technically not true for Table. The table is just an arbitrary arrangement of cells. It does not know about headers. The notion of headers is only present in table(), which chooses to optionally specially handle columns and rows with index 0.

  2. Is also not true. Each entry in the table is a Cell (which seems too obvious to mention). Cells are Rectangles with associated Text as written in the cell docstring.

I'm not quite sure about 3) either. Essentially the table is just a 2d array of cells, which don't even have to have the same positions or widths. So the concept of rows and columns is more logical than visual. While there's some size related/position functions like _do_cell_alignment and auto_set_column_width, I would have expected some set_column_width(col, width) and set_row_height(row, height) functions which are clearly not there. Therefore 3) seems an over-statement of the actual capabilities.


Each entry in the table can be either text or patches.

Column widths and row heights for the table can be specified.
A table of cells.

The table consists of a grid of cells, which are indexed by (row, column).

Expand All @@ -255,8 +256,8 @@ class Table(Artist):
You don't have to add a cell to every grid position, so you can create
tables that have holes.

Return value is a sequence of text, line and patch instances that make
up the table
*Note*: You'll usually not create an empty table from scratch. Instead use
`~matplotlib.table.table` to create a table from data.
"""
codes = {'best': 0,
'upper right': 1, # default
Expand All @@ -277,11 +278,31 @@ class Table(Artist):
'top': 16,
'bottom': 17,
}
"""Possible values where to place the table relative to the Axes."""

FONTSIZE = 10
AXESPAD = 0.02 # the border between the axes and table edge

AXESPAD = 0.02
"""The border between the Axes and the table edge in Axes units."""

def __init__(self, ax, loc=None, bbox=None, **kwargs):
"""
Parameters
----------
ax : `matplotlib.axes.Axes`
The `~.axes.Axes` to plot the table into.
loc : str
The position of the cell with respect to *ax*. This must be one of
the `~.Table.codes`.
bbox : `.Bbox` or None
A bounding box to draw the table into. If this is not *None*, this
overrides *loc*.

Other Parameters
----------------
**kwargs
`.Artist` properties.
"""

Artist.__init__(self)

Expand Down Expand Up @@ -314,18 +335,21 @@ def __init__(self, ax, loc=None, bbox=None, **kwargs):

def add_cell(self, row, col, *args, **kwargs):
"""
Add a cell to the table.
Create a cell and add it to the table.

Parameters
----------
row : int
Row index.
col : int
Column index.
*args, **kwargs
All other parameters are passed on to `Cell`.

Returns
-------
`CustomCell`: Automatically created cell
cell : `.CustomCell`
The created cell.

"""
xy = (0, 0)
Expand Down Expand Up @@ -361,6 +385,21 @@ def __getitem__(self, position):

@property
def edges(self):
"""
The default value of `~.CustomCell.visible_edges` for newly added
cells using `.add_cell`.

Notes
-----
This setting does currently only affect newly created cells using
`.add_cell`.

To change existing cells, you have to set their edges explicitly::

for c in tab.get_celld().values():
c.visible_edges = 'horizontal'

"""
return self._edges

@edges.setter
Expand All @@ -374,6 +413,8 @@ def _approx_text_height(self):

@allow_rasterization
def draw(self, renderer):
# docstring inherited

# Need a renderer to do hit tests on mouseevent; assume the last one
# will do
if renderer is None:
Expand Down Expand Up @@ -403,10 +444,7 @@ def _get_grid_bbox(self, renderer):
return bbox.inverse_transformed(self.get_transform())

def contains(self, mouseevent):
"""Test whether the mouse event occurred in the table.

Returns T/F, {}
"""
# docstring inherited
Copy link
Contributor

@anntzer anntzer Dec 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this could additionally return e.g. which cell contained the event (in the dict).
edit: there's already a todo for that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, the behavior is as documented in the parent. I'm just cleaning up the docs within this PR. So the docstring is redundant and can be left out.

if callable(self._contains):
return self._contains(self, mouseevent)

Expand Down Expand Up @@ -466,26 +504,13 @@ def _do_cell_alignment(self):
cell.set_y(bottoms[row])

def auto_set_column_width(self, col):
""" Given column indexs in either List, Tuple or int. Will be able to
automatically set the columns into optimal sizes.

Here is the example of the input, which triger automatic adjustment on
columns to optimal size by given index numbers.
-1: the row labling
0: the 1st column
1: the 2nd column

Args:
col(List): list of indexs
>>>table.auto_set_column_width([-1,0,1])

col(Tuple): tuple of indexs
>>>table.auto_set_column_width((-1,0,1))

col(int): index integer
>>>table.auto_set_column_width(-1)
>>>table.auto_set_column_width(0)
>>>table.auto_set_column_width(1)
"""
Automatically set the widths of given columns to optimal sizes.

Parameters
----------
col : int or sequence of ints
The indices of the columns to auto-scale.
"""
# check for col possibility on iteration
try:
Expand Down Expand Up @@ -536,7 +561,7 @@ def _auto_set_font_size(self, renderer):
cell.set_fontsize(fontsize)

def scale(self, xscale, yscale):
""" Scale column widths by xscale and row heights by yscale. """
"""Scale column widths by *xscale* and row heights by *yscale*."""
for c in self._cells.values():
c.set_width(c.get_width() * xscale)
c.set_height(c.get_height() * yscale)
Expand All @@ -548,8 +573,20 @@ def set_fontsize(self, size):
Parameters
----------
size : float
"""

Notes
-----
As long as auto font size has not been disabled, the value will be
clipped such that the text fits horizontally into the cell.

You can disable this behavior using `.auto_set_font_size`.

>>> the_table.auto_set_font_size(False)
>>> the_table.set_fontsize(20)

However, there is no automatic scaling of the row height so that the
text may exceed the cell boundary.
"""
for cell in self._cells.values():
cell.set_fontsize(size)
self.stale = True
Expand Down Expand Up @@ -617,7 +654,18 @@ def _update_positions(self, renderer):
self._offset(ox, oy)

def get_celld(self):
"""Return a dict of cells in the table."""
r"""
Return a dict of cells in the table mapping *(row, column)* to
`.Cell`\s.

Notes
-----
You can also directly index into the Table object to access individual
cells::

cell = table[row, col]

"""
return self._cells


Expand All @@ -629,13 +677,75 @@ def table(ax,
loc='bottom', bbox=None, edges='closed',
**kwargs):
"""
TABLE(cellText=None, cellColours=None,
cellLoc='right', colWidths=None,
rowLabels=None, rowColours=None, rowLoc='left',
colLabels=None, colColours=None, colLoc='center',
loc='bottom', bbox=None, edges='closed')
Add a table to an `~.axes.Axes`.

At least one of *cellText* or *cellColours* must be specified. These
parameters must be 2D lists, in which the outer lists define the rows and
the inner list define the column values per row. Each row must have the
same number of elements.

The table can optionally have row and column headers, which are configured
using *rowLabels*, *rowColours*, *rowLoc* and *colLabels*, *colColours*,
*colLoc* respectively.

Parameters
----------
cellText : 2D list of str, optional
The texts to place into the table cells.

*Note*: Line breaks in the strings are currently not accounted for and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could use

.. note::
   Line breaks ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is rather a comment than something which should stand out. Therefore I intendedly chose not to use an admonition.

will result in the text exceeding the cell boundaries.

cellColours : 2D list of matplotlib color specs, optional
The background colors of the cells.

cellLoc : {'left', 'center', 'right'}, default: 'right'
The alignment of the text within the cells.

colWidths : list of float, optional
The column widths in units of the axes. If not given, all columns will
have a width of *1 / ncols*.

rowLabels : list of str, optional
The text of the row header cells.

rowColours : list of matplotlib color specs, optional
The colors of the row header cells.

rowLoc : {'left', 'center', 'right'}, optional, default: 'left'
The text alignment of the row header cells.

colLabels : list of str, optional
The text of the column header cells.

colColours : list of matplotlib color specs, optional
The colors of the column header cells.

rowLoc : {'left', 'center', 'right'}, optional, default: 'left'
The text alignment of the column header cells.

loc : str, optional
The position of the cell with respect to *ax*. This must be one of
the `~.Table.codes`.

bbox : `.Bbox`, optional
A bounding box to draw the table into. If this is not *None*, this
overrides *loc*.

edges : substring of 'BRTL' or {'open', 'closed', 'horizontal', 'vertical'}
The cell edges to be drawn with a line. See also
`~.CustomCell.visible_edges`.

Other Parameters
----------------
**kwargs
`.Artist` properties.

Returns
-------
table : `~matplotlib.table.Table`
The created table.

Factory function to generate a Table instance.
"""

if cellColours is None and cellText is None:
Expand Down