Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Implementation of Issue #4044. Added ScientificTable and ScientificCell subclasses. #4259

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 14 commits into from
Apr 19, 2015
Merged
Show file tree
Hide file tree
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
11 changes: 11 additions & 0 deletions doc/users/whats_new/updated_table.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Updated Table and to control edge visibility
--------------------------------------------
Added the ability to toggle the visibility of lines in Tables.
Functionality added to the table() factory function under the keyword argument "edges".
Values can be the strings "open", "closed", "horizontal", "vertical" or combinations of the letters "L", "R", "T", "B" which represent left, right, top, and bottom respectively.

Example:
table(..., edges="open") # No line visible
table(..., edges="closed") # All lines visible
table(..., edges="horizontal") # Only top and bottom lines visible
table(..., edges="LT") # Only left and top lines visible.
97 changes: 85 additions & 12 deletions lib/matplotlib/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from matplotlib import docstring
from .text import Text
from .transforms import Bbox
from matplotlib.path import Path


class Cell(Rectangle):
Expand Down Expand Up @@ -146,6 +147,67 @@ def set_text_props(self, **kwargs):
self._text.update(kwargs)


class CustomCell(Cell):
"""
A subclass of Cell where the sides may be visibly toggled.

"""

_edges = 'BRTL'
_edge_aliases = {'open': '',
Copy link
Member

Choose a reason for hiding this comment

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

trim the extra white space please.

We much not have pep8 compliance on the rest of this file or the test would be failing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@tacaswell do you mean the extra whitespace inside the _edge_aliases dictionary? I can't see any other whitespace and yeah pep8 isn't failing.

Copy link
Member

Choose a reason for hiding this comment

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

I would expect pep8 to require

_edge_aliases = {'open': '',

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@tacaswell afaik spaces are allowed after colons inside of dictionaries.

Nothing against it is mentioned in the PEP 8 style guide: https://www.python.org/dev/peps/pep-0008/

And running pep8 on a minimal example and people on SO seem to confirm: http://stackoverflow.com/questions/13497793/python-alignment-of-assignments-style

I'm also at PyCon right now, I could ask people here too

Copy link
Member

Choose a reason for hiding this comment

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

Well, learn something every day.

'closed': _edges, # default
'horizontal': 'BT',
'vertical': 'RL'
}

def __init__(self, *args, **kwargs):
visible_edges = kwargs.pop('visible_edges')
Cell.__init__(self, *args, **kwargs)
self.visible_edges = visible_edges

@property
def visible_edges(self):
return self._visible_edges

@visible_edges.setter
def visible_edges(self, value):
if value is None:
self._visible_edges = self._edges
elif value in self._edge_aliases:
self._visible_edges = self._edge_aliases[value]
else:
for edge in value:
if edge not in self._edges:
msg = ('Invalid edge param {0}, must only be one of'
' {1} or string of {2}.').format(
value,
", ".join(self._edge_aliases.keys()),
", ".join(self._edges),
)
raise ValueError(msg)
self._visible_edges = value

def get_path(self):
'Return a path where the edges specificed by _visible_edges are drawn'

codes = [Path.MOVETO]

for edge in self._edges:
if edge in self._visible_edges:
codes.append(Path.LINETO)
else:
codes.append(Path.MOVETO)

if Path.MOVETO not in codes[1:]: # All sides are visible
codes[-1] = Path.CLOSEPOLY

return Path(
[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]],
codes,
readonly=True
)


class Table(Artist):
"""
Create a table of cells.
Expand Down Expand Up @@ -203,6 +265,7 @@ def __init__(self, ax, loc=None, bbox=None, **kwargs):

self._texts = []
self._cells = {}
self._edges = None
self._autoRows = []
self._autoColumns = []
self._autoFontsize = True
Expand All @@ -216,13 +279,21 @@ def add_cell(self, row, col, *args, **kwargs):
""" Add a cell to the table. """
xy = (0, 0)

cell = Cell(xy, *args, **kwargs)
cell = CustomCell(xy, visible_edges=self.edges, *args, **kwargs)
cell.set_figure(self.figure)
cell.set_transform(self.get_transform())

cell.set_clip_on(False)
self._cells[(row, col)] = cell

@property
def edges(self):
return self._edges

@edges.setter
def edges(self, value):
self._edges = value

def _approx_text_height(self):
return (self.FONTSIZE / 72.0 * self.figure.dpi /
self._axes.bbox.height * 1.2)
Expand All @@ -246,8 +317,8 @@ def draw(self, renderer):
keys.sort()
for key in keys:
self._cells[key].draw(renderer)
#for c in self._cells.itervalues():
# c.draw(renderer)
# for c in self._cells.itervalues():
# c.draw(renderer)
renderer.close_group('table')

def _get_grid_bbox(self, renderer):
Expand All @@ -273,8 +344,8 @@ def contains(self, mouseevent):
# doesn't have to bind to each one individually.
if self._cachedRenderer is not None:
boxes = [self._cells[pos].get_window_extent(self._cachedRenderer)
for pos in six.iterkeys(self._cells)
if pos[0] >= 0 and pos[1] >= 0]
for pos in six.iterkeys(self._cells)
if pos[0] >= 0 and pos[1] >= 0]
bbox = Bbox.union(boxes)
return bbox.contains(mouseevent.x, mouseevent.y), {}
else:
Expand Down Expand Up @@ -455,23 +526,24 @@ def get_celld(self):


def table(ax,
cellText=None, cellColours=None,
cellLoc='right', colWidths=None,
rowLabels=None, rowColours=None, rowLoc='left',
colLabels=None, colColours=None, colLoc='center',
loc='bottom', bbox=None,
**kwargs):
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',
**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)
loc='bottom', bbox=None, edges='closed')

Factory function to generate a Table instance.

Thanks to John Gill for providing the class and table.
"""

# Check we have some cellText
if cellText is None:
# assume just colours are needed
Expand Down Expand Up @@ -528,6 +600,7 @@ def table(ax,

# Now create the table
table = Table(ax, loc, bbox, **kwargs)
table.edges = edges
height = table._approx_text_height()

# Add the cells
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 42 additions & 0 deletions lib/matplotlib/tests/test_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
import numpy as np
from matplotlib.testing.decorators import image_comparison

from matplotlib.table import CustomCell
from matplotlib.path import Path
from nose.tools import assert_equal


@image_comparison(baseline_images=['table_zorder'],
extensions=['png'],
Expand Down Expand Up @@ -79,3 +83,41 @@ def test_label_colours():
colColours=colours,
colLabels=['Header'] * dim,
loc='best')


@image_comparison(baseline_images=['table_cell_manipulation'],
Copy link
Member

Choose a reason for hiding this comment

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

Add the remove_text=True kwarg here to simplify the figures, and reduce the likelihood of spurious differences related to font handling.

Copy link
Member

Choose a reason for hiding this comment

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

This has been addressed.

extensions=['png'], remove_text=True)
def test_diff_cell_table():
cells = ('horizontal', 'vertical', 'open', 'closed', 'T', 'R', 'B', 'L')
cellText = [['1'] * len(cells)] * 2
colWidths = [0.1] * len(cells)

_, axes = plt.subplots(nrows=len(cells), figsize=(4, len(cells)+1))
for ax, cell in zip(axes, cells):
ax.table(
colWidths=colWidths,
cellText=cellText,
loc='center',
edges=cell,
)
ax.axis('off')
plt.tight_layout()
Copy link
Member

Choose a reason for hiding this comment

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

This isn't essential to the test, is it?



def test_customcell():
types = ('horizontal', 'vertical', 'open', 'closed', 'T', 'R', 'B', 'L')
codes = (
(Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO, Path.MOVETO),
(Path.MOVETO, Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO),
(Path.MOVETO, Path.MOVETO, Path.MOVETO, Path.MOVETO, Path.MOVETO),
(Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY),
(Path.MOVETO, Path.MOVETO, Path.MOVETO, Path.LINETO, Path.MOVETO),
(Path.MOVETO, Path.MOVETO, Path.LINETO, Path.MOVETO, Path.MOVETO),
(Path.MOVETO, Path.LINETO, Path.MOVETO, Path.MOVETO, Path.MOVETO),
(Path.MOVETO, Path.MOVETO, Path.MOVETO, Path.MOVETO, Path.LINETO),
)

for t, c in zip(types, codes):
cell = CustomCell((0, 0), visible_edges=t, width=1, height=1)
code = tuple(s for _, s in cell.get_path().iter_segments())
assert_equal(c, code)