Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/matplotlib/table.py: 19%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# Original code by:
2# John Gill <jng@europe.renre.com>
3# Copyright 2004 John Gill and John Hunter
4#
5# Subsequent changes:
6# The Matplotlib development team
7# Copyright The Matplotlib development team
9"""
10Tables drawing.
12.. note::
13 The table implementation in Matplotlib is lightly maintained. For a more
14 featureful table implementation, you may wish to try `blume
15 <https://github.com/swfiua/blume>`_.
17Use the factory function `~matplotlib.table.table` to create a ready-made
18table from texts. If you need more control, use the `.Table` class and its
19methods.
21The table consists of a grid of cells, which are indexed by (row, column).
22The cell (0, 0) is positioned at the top left.
24Thanks to John Gill for providing the class and table.
25"""
27import numpy as np
29from . import _api, _docstring
30from .artist import Artist, allow_rasterization
31from .patches import Rectangle
32from .text import Text
33from .transforms import Bbox
34from .path import Path
37class Cell(Rectangle):
38 """
39 A cell is a `.Rectangle` with some associated `.Text`.
41 As a user, you'll most likely not creates cells yourself. Instead, you
42 should use either the `~matplotlib.table.table` factory function or
43 `.Table.add_cell`.
44 """
46 PAD = 0.1
47 """Padding between text and rectangle."""
49 _edges = 'BRTL'
50 _edge_aliases = {'open': '',
51 'closed': _edges, # default
52 'horizontal': 'BT',
53 'vertical': 'RL'
54 }
56 def __init__(self, xy, width, height, *,
57 edgecolor='k', facecolor='w',
58 fill=True,
59 text='',
60 loc='right',
61 fontproperties=None,
62 visible_edges='closed',
63 ):
64 """
65 Parameters
66 ----------
67 xy : 2-tuple
68 The position of the bottom left corner of the cell.
69 width : float
70 The cell width.
71 height : float
72 The cell height.
73 edgecolor : :mpltype:`color`, default: 'k'
74 The color of the cell border.
75 facecolor : :mpltype:`color`, default: 'w'
76 The cell facecolor.
77 fill : bool, default: True
78 Whether the cell background is filled.
79 text : str, optional
80 The cell text.
81 loc : {'right', 'center', 'left'}
82 The alignment of the text within the cell.
83 fontproperties : dict, optional
84 A dict defining the font properties of the text. Supported keys and
85 values are the keyword arguments accepted by `.FontProperties`.
86 visible_edges : {'closed', 'open', 'horizontal', 'vertical'} or \
87substring of 'BRTL'
88 The cell edges to be drawn with a line: a substring of 'BRTL'
89 (bottom, right, top, left), or one of 'open' (no edges drawn),
90 'closed' (all edges drawn), 'horizontal' (bottom and top),
91 'vertical' (right and left).
92 """
94 # Call base
95 super().__init__(xy, width=width, height=height, fill=fill,
96 edgecolor=edgecolor, facecolor=facecolor)
97 self.set_clip_on(False)
98 self.visible_edges = visible_edges
100 # Create text object
101 self._loc = loc
102 self._text = Text(x=xy[0], y=xy[1], clip_on=False,
103 text=text, fontproperties=fontproperties,
104 horizontalalignment=loc, verticalalignment='center')
106 @_api.rename_parameter("3.8", "trans", "t")
107 def set_transform(self, t):
108 super().set_transform(t)
109 # the text does not get the transform!
110 self.stale = True
112 def set_figure(self, fig):
113 super().set_figure(fig)
114 self._text.set_figure(fig)
116 def get_text(self):
117 """Return the cell `.Text` instance."""
118 return self._text
120 def set_fontsize(self, size):
121 """Set the text fontsize."""
122 self._text.set_fontsize(size)
123 self.stale = True
125 def get_fontsize(self):
126 """Return the cell fontsize."""
127 return self._text.get_fontsize()
129 def auto_set_font_size(self, renderer):
130 """Shrink font size until the text fits into the cell width."""
131 fontsize = self.get_fontsize()
132 required = self.get_required_width(renderer)
133 while fontsize > 1 and required > self.get_width():
134 fontsize -= 1
135 self.set_fontsize(fontsize)
136 required = self.get_required_width(renderer)
138 return fontsize
140 @allow_rasterization
141 def draw(self, renderer):
142 if not self.get_visible():
143 return
144 # draw the rectangle
145 super().draw(renderer)
146 # position the text
147 self._set_text_position(renderer)
148 self._text.draw(renderer)
149 self.stale = False
151 def _set_text_position(self, renderer):
152 """Set text up so it is drawn in the right place."""
153 bbox = self.get_window_extent(renderer)
154 # center vertically
155 y = bbox.y0 + bbox.height / 2
156 # position horizontally
157 loc = self._text.get_horizontalalignment()
158 if loc == 'center':
159 x = bbox.x0 + bbox.width / 2
160 elif loc == 'left':
161 x = bbox.x0 + bbox.width * self.PAD
162 else: # right.
163 x = bbox.x0 + bbox.width * (1 - self.PAD)
164 self._text.set_position((x, y))
166 def get_text_bounds(self, renderer):
167 """
168 Return the text bounds as *(x, y, width, height)* in table coordinates.
169 """
170 return (self._text.get_window_extent(renderer)
171 .transformed(self.get_data_transform().inverted())
172 .bounds)
174 def get_required_width(self, renderer):
175 """Return the minimal required width for the cell."""
176 l, b, w, h = self.get_text_bounds(renderer)
177 return w * (1.0 + (2.0 * self.PAD))
179 @_docstring.dedent_interpd
180 def set_text_props(self, **kwargs):
181 """
182 Update the text properties.
184 Valid keyword arguments are:
186 %(Text:kwdoc)s
187 """
188 self._text._internal_update(kwargs)
189 self.stale = True
191 @property
192 def visible_edges(self):
193 """
194 The cell edges to be drawn with a line.
196 Reading this property returns a substring of 'BRTL' (bottom, right,
197 top, left').
199 When setting this property, you can use a substring of 'BRTL' or one
200 of {'open', 'closed', 'horizontal', 'vertical'}.
201 """
202 return self._visible_edges
204 @visible_edges.setter
205 def visible_edges(self, value):
206 if value is None:
207 self._visible_edges = self._edges
208 elif value in self._edge_aliases:
209 self._visible_edges = self._edge_aliases[value]
210 else:
211 if any(edge not in self._edges for edge in value):
212 raise ValueError('Invalid edge param {}, must only be one of '
213 '{} or string of {}'.format(
214 value,
215 ", ".join(self._edge_aliases),
216 ", ".join(self._edges)))
217 self._visible_edges = value
218 self.stale = True
220 def get_path(self):
221 """Return a `.Path` for the `.visible_edges`."""
222 codes = [Path.MOVETO]
223 codes.extend(
224 Path.LINETO if edge in self._visible_edges else Path.MOVETO
225 for edge in self._edges)
226 if Path.MOVETO not in codes[1:]: # All sides are visible
227 codes[-1] = Path.CLOSEPOLY
228 return Path(
229 [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]],
230 codes,
231 readonly=True
232 )
235CustomCell = Cell # Backcompat. alias.
238class Table(Artist):
239 """
240 A table of cells.
242 The table consists of a grid of cells, which are indexed by (row, column).
244 For a simple table, you'll have a full grid of cells with indices from
245 (0, 0) to (num_rows-1, num_cols-1), in which the cell (0, 0) is positioned
246 at the top left. However, you can also add cells with negative indices.
247 You don't have to add a cell to every grid position, so you can create
248 tables that have holes.
250 *Note*: You'll usually not create an empty table from scratch. Instead use
251 `~matplotlib.table.table` to create a table from data.
252 """
253 codes = {'best': 0,
254 'upper right': 1, # default
255 'upper left': 2,
256 'lower left': 3,
257 'lower right': 4,
258 'center left': 5,
259 'center right': 6,
260 'lower center': 7,
261 'upper center': 8,
262 'center': 9,
263 'top right': 10,
264 'top left': 11,
265 'bottom left': 12,
266 'bottom right': 13,
267 'right': 14,
268 'left': 15,
269 'top': 16,
270 'bottom': 17,
271 }
272 """Possible values where to place the table relative to the Axes."""
274 FONTSIZE = 10
276 AXESPAD = 0.02
277 """The border between the Axes and the table edge in Axes units."""
279 def __init__(self, ax, loc=None, bbox=None, **kwargs):
280 """
281 Parameters
282 ----------
283 ax : `~matplotlib.axes.Axes`
284 The `~.axes.Axes` to plot the table into.
285 loc : str, optional
286 The position of the cell with respect to *ax*. This must be one of
287 the `~.Table.codes`.
288 bbox : `.Bbox` or [xmin, ymin, width, height], optional
289 A bounding box to draw the table into. If this is not *None*, this
290 overrides *loc*.
292 Other Parameters
293 ----------------
294 **kwargs
295 `.Artist` properties.
296 """
298 super().__init__()
300 if isinstance(loc, str):
301 if loc not in self.codes:
302 raise ValueError(
303 "Unrecognized location {!r}. Valid locations are\n\t{}"
304 .format(loc, '\n\t'.join(self.codes)))
305 loc = self.codes[loc]
306 self.set_figure(ax.figure)
307 self._axes = ax
308 self._loc = loc
309 self._bbox = bbox
311 # use axes coords
312 ax._unstale_viewLim()
313 self.set_transform(ax.transAxes)
315 self._cells = {}
316 self._edges = None
317 self._autoColumns = []
318 self._autoFontsize = True
319 self._internal_update(kwargs)
321 self.set_clip_on(False)
323 def add_cell(self, row, col, *args, **kwargs):
324 """
325 Create a cell and add it to the table.
327 Parameters
328 ----------
329 row : int
330 Row index.
331 col : int
332 Column index.
333 *args, **kwargs
334 All other parameters are passed on to `Cell`.
336 Returns
337 -------
338 `.Cell`
339 The created cell.
341 """
342 xy = (0, 0)
343 cell = Cell(xy, visible_edges=self.edges, *args, **kwargs)
344 self[row, col] = cell
345 return cell
347 def __setitem__(self, position, cell):
348 """
349 Set a custom cell in a given position.
350 """
351 _api.check_isinstance(Cell, cell=cell)
352 try:
353 row, col = position[0], position[1]
354 except Exception as err:
355 raise KeyError('Only tuples length 2 are accepted as '
356 'coordinates') from err
357 cell.set_figure(self.figure)
358 cell.set_transform(self.get_transform())
359 cell.set_clip_on(False)
360 self._cells[row, col] = cell
361 self.stale = True
363 def __getitem__(self, position):
364 """Retrieve a custom cell from a given position."""
365 return self._cells[position]
367 @property
368 def edges(self):
369 """
370 The default value of `~.Cell.visible_edges` for newly added
371 cells using `.add_cell`.
373 Notes
374 -----
375 This setting does currently only affect newly created cells using
376 `.add_cell`.
378 To change existing cells, you have to set their edges explicitly::
380 for c in tab.get_celld().values():
381 c.visible_edges = 'horizontal'
383 """
384 return self._edges
386 @edges.setter
387 def edges(self, value):
388 self._edges = value
389 self.stale = True
391 def _approx_text_height(self):
392 return (self.FONTSIZE / 72.0 * self.figure.dpi /
393 self._axes.bbox.height * 1.2)
395 @allow_rasterization
396 def draw(self, renderer):
397 # docstring inherited
399 # Need a renderer to do hit tests on mouseevent; assume the last one
400 # will do
401 if renderer is None:
402 renderer = self.figure._get_renderer()
403 if renderer is None:
404 raise RuntimeError('No renderer defined')
406 if not self.get_visible():
407 return
408 renderer.open_group('table', gid=self.get_gid())
409 self._update_positions(renderer)
411 for key in sorted(self._cells):
412 self._cells[key].draw(renderer)
414 renderer.close_group('table')
415 self.stale = False
417 def _get_grid_bbox(self, renderer):
418 """
419 Get a bbox, in axes coordinates for the cells.
421 Only include those in the range (0, 0) to (maxRow, maxCol).
422 """
423 boxes = [cell.get_window_extent(renderer)
424 for (row, col), cell in self._cells.items()
425 if row >= 0 and col >= 0]
426 bbox = Bbox.union(boxes)
427 return bbox.transformed(self.get_transform().inverted())
429 def contains(self, mouseevent):
430 # docstring inherited
431 if self._different_canvas(mouseevent):
432 return False, {}
433 # TODO: Return index of the cell containing the cursor so that the user
434 # doesn't have to bind to each one individually.
435 renderer = self.figure._get_renderer()
436 if renderer is not None:
437 boxes = [cell.get_window_extent(renderer)
438 for (row, col), cell in self._cells.items()
439 if row >= 0 and col >= 0]
440 bbox = Bbox.union(boxes)
441 return bbox.contains(mouseevent.x, mouseevent.y), {}
442 else:
443 return False, {}
445 def get_children(self):
446 """Return the Artists contained by the table."""
447 return list(self._cells.values())
449 def get_window_extent(self, renderer=None):
450 # docstring inherited
451 if renderer is None:
452 renderer = self.figure._get_renderer()
453 self._update_positions(renderer)
454 boxes = [cell.get_window_extent(renderer)
455 for cell in self._cells.values()]
456 return Bbox.union(boxes)
458 def _do_cell_alignment(self):
459 """
460 Calculate row heights and column widths; position cells accordingly.
461 """
462 # Calculate row/column widths
463 widths = {}
464 heights = {}
465 for (row, col), cell in self._cells.items():
466 height = heights.setdefault(row, 0.0)
467 heights[row] = max(height, cell.get_height())
468 width = widths.setdefault(col, 0.0)
469 widths[col] = max(width, cell.get_width())
471 # work out left position for each column
472 xpos = 0
473 lefts = {}
474 for col in sorted(widths):
475 lefts[col] = xpos
476 xpos += widths[col]
478 ypos = 0
479 bottoms = {}
480 for row in sorted(heights, reverse=True):
481 bottoms[row] = ypos
482 ypos += heights[row]
484 # set cell positions
485 for (row, col), cell in self._cells.items():
486 cell.set_x(lefts[col])
487 cell.set_y(bottoms[row])
489 def auto_set_column_width(self, col):
490 """
491 Automatically set the widths of given columns to optimal sizes.
493 Parameters
494 ----------
495 col : int or sequence of ints
496 The indices of the columns to auto-scale.
497 """
498 col1d = np.atleast_1d(col)
499 if not np.issubdtype(col1d.dtype, np.integer):
500 _api.warn_deprecated("3.8", name="col",
501 message="%(name)r must be an int or sequence of ints. "
502 "Passing other types is deprecated since %(since)s "
503 "and will be removed %(removal)s.")
504 return
505 for cell in col1d:
506 self._autoColumns.append(cell)
508 self.stale = True
510 def _auto_set_column_width(self, col, renderer):
511 """Automatically set width for column."""
512 cells = [cell for key, cell in self._cells.items() if key[1] == col]
513 max_width = max((cell.get_required_width(renderer) for cell in cells),
514 default=0)
515 for cell in cells:
516 cell.set_width(max_width)
518 def auto_set_font_size(self, value=True):
519 """Automatically set font size."""
520 self._autoFontsize = value
521 self.stale = True
523 def _auto_set_font_size(self, renderer):
525 if len(self._cells) == 0:
526 return
527 fontsize = next(iter(self._cells.values())).get_fontsize()
528 cells = []
529 for key, cell in self._cells.items():
530 # ignore auto-sized columns
531 if key[1] in self._autoColumns:
532 continue
533 size = cell.auto_set_font_size(renderer)
534 fontsize = min(fontsize, size)
535 cells.append(cell)
537 # now set all fontsizes equal
538 for cell in self._cells.values():
539 cell.set_fontsize(fontsize)
541 def scale(self, xscale, yscale):
542 """Scale column widths by *xscale* and row heights by *yscale*."""
543 for c in self._cells.values():
544 c.set_width(c.get_width() * xscale)
545 c.set_height(c.get_height() * yscale)
547 def set_fontsize(self, size):
548 """
549 Set the font size, in points, of the cell text.
551 Parameters
552 ----------
553 size : float
555 Notes
556 -----
557 As long as auto font size has not been disabled, the value will be
558 clipped such that the text fits horizontally into the cell.
560 You can disable this behavior using `.auto_set_font_size`.
562 >>> the_table.auto_set_font_size(False)
563 >>> the_table.set_fontsize(20)
565 However, there is no automatic scaling of the row height so that the
566 text may exceed the cell boundary.
567 """
568 for cell in self._cells.values():
569 cell.set_fontsize(size)
570 self.stale = True
572 def _offset(self, ox, oy):
573 """Move all the artists by ox, oy (axes coords)."""
574 for c in self._cells.values():
575 x, y = c.get_x(), c.get_y()
576 c.set_x(x + ox)
577 c.set_y(y + oy)
579 def _update_positions(self, renderer):
580 # called from renderer to allow more precise estimates of
581 # widths and heights with get_window_extent
583 # Do any auto width setting
584 for col in self._autoColumns:
585 self._auto_set_column_width(col, renderer)
587 if self._autoFontsize:
588 self._auto_set_font_size(renderer)
590 # Align all the cells
591 self._do_cell_alignment()
593 bbox = self._get_grid_bbox(renderer)
594 l, b, w, h = bbox.bounds
596 if self._bbox is not None:
597 # Position according to bbox
598 if isinstance(self._bbox, Bbox):
599 rl, rb, rw, rh = self._bbox.bounds
600 else:
601 rl, rb, rw, rh = self._bbox
602 self.scale(rw / w, rh / h)
603 ox = rl - l
604 oy = rb - b
605 self._do_cell_alignment()
606 else:
607 # Position using loc
608 (BEST, UR, UL, LL, LR, CL, CR, LC, UC, C,
609 TR, TL, BL, BR, R, L, T, B) = range(len(self.codes))
610 # defaults for center
611 ox = (0.5 - w / 2) - l
612 oy = (0.5 - h / 2) - b
613 if self._loc in (UL, LL, CL): # left
614 ox = self.AXESPAD - l
615 if self._loc in (BEST, UR, LR, R, CR): # right
616 ox = 1 - (l + w + self.AXESPAD)
617 if self._loc in (BEST, UR, UL, UC): # upper
618 oy = 1 - (b + h + self.AXESPAD)
619 if self._loc in (LL, LR, LC): # lower
620 oy = self.AXESPAD - b
621 if self._loc in (LC, UC, C): # center x
622 ox = (0.5 - w / 2) - l
623 if self._loc in (CL, CR, C): # center y
624 oy = (0.5 - h / 2) - b
626 if self._loc in (TL, BL, L): # out left
627 ox = - (l + w)
628 if self._loc in (TR, BR, R): # out right
629 ox = 1.0 - l
630 if self._loc in (TR, TL, T): # out top
631 oy = 1.0 - b
632 if self._loc in (BL, BR, B): # out bottom
633 oy = - (b + h)
635 self._offset(ox, oy)
637 def get_celld(self):
638 r"""
639 Return a dict of cells in the table mapping *(row, column)* to
640 `.Cell`\s.
642 Notes
643 -----
644 You can also directly index into the Table object to access individual
645 cells::
647 cell = table[row, col]
649 """
650 return self._cells
653@_docstring.dedent_interpd
654def table(ax,
655 cellText=None, cellColours=None,
656 cellLoc='right', colWidths=None,
657 rowLabels=None, rowColours=None, rowLoc='left',
658 colLabels=None, colColours=None, colLoc='center',
659 loc='bottom', bbox=None, edges='closed',
660 **kwargs):
661 """
662 Add a table to an `~.axes.Axes`.
664 At least one of *cellText* or *cellColours* must be specified. These
665 parameters must be 2D lists, in which the outer lists define the rows and
666 the inner list define the column values per row. Each row must have the
667 same number of elements.
669 The table can optionally have row and column headers, which are configured
670 using *rowLabels*, *rowColours*, *rowLoc* and *colLabels*, *colColours*,
671 *colLoc* respectively.
673 For finer grained control over tables, use the `.Table` class and add it to
674 the Axes with `.Axes.add_table`.
676 Parameters
677 ----------
678 cellText : 2D list of str, optional
679 The texts to place into the table cells.
681 *Note*: Line breaks in the strings are currently not accounted for and
682 will result in the text exceeding the cell boundaries.
684 cellColours : 2D list of :mpltype:`color`, optional
685 The background colors of the cells.
687 cellLoc : {'right', 'center', 'left'}
688 The alignment of the text within the cells.
690 colWidths : list of float, optional
691 The column widths in units of the axes. If not given, all columns will
692 have a width of *1 / ncols*.
694 rowLabels : list of str, optional
695 The text of the row header cells.
697 rowColours : list of :mpltype:`color`, optional
698 The colors of the row header cells.
700 rowLoc : {'left', 'center', 'right'}
701 The text alignment of the row header cells.
703 colLabels : list of str, optional
704 The text of the column header cells.
706 colColours : list of :mpltype:`color`, optional
707 The colors of the column header cells.
709 colLoc : {'center', 'left', 'right'}
710 The text alignment of the column header cells.
712 loc : str, default: 'bottom'
713 The position of the cell with respect to *ax*. This must be one of
714 the `~.Table.codes`.
716 bbox : `.Bbox` or [xmin, ymin, width, height], optional
717 A bounding box to draw the table into. If this is not *None*, this
718 overrides *loc*.
720 edges : {'closed', 'open', 'horizontal', 'vertical'} or substring of 'BRTL'
721 The cell edges to be drawn with a line. See also
722 `~.Cell.visible_edges`.
724 Returns
725 -------
726 `~matplotlib.table.Table`
727 The created table.
729 Other Parameters
730 ----------------
731 **kwargs
732 `.Table` properties.
734 %(Table:kwdoc)s
735 """
737 if cellColours is None and cellText is None:
738 raise ValueError('At least one argument from "cellColours" or '
739 '"cellText" must be provided to create a table.')
741 # Check we have some cellText
742 if cellText is None:
743 # assume just colours are needed
744 rows = len(cellColours)
745 cols = len(cellColours[0])
746 cellText = [[''] * cols] * rows
748 rows = len(cellText)
749 cols = len(cellText[0])
750 for row in cellText:
751 if len(row) != cols:
752 raise ValueError(f"Each row in 'cellText' must have {cols} "
753 "columns")
755 if cellColours is not None:
756 if len(cellColours) != rows:
757 raise ValueError(f"'cellColours' must have {rows} rows")
758 for row in cellColours:
759 if len(row) != cols:
760 raise ValueError("Each row in 'cellColours' must have "
761 f"{cols} columns")
762 else:
763 cellColours = ['w' * cols] * rows
765 # Set colwidths if not given
766 if colWidths is None:
767 colWidths = [1.0 / cols] * cols
769 # Fill in missing information for column
770 # and row labels
771 rowLabelWidth = 0
772 if rowLabels is None:
773 if rowColours is not None:
774 rowLabels = [''] * rows
775 rowLabelWidth = colWidths[0]
776 elif rowColours is None:
777 rowColours = 'w' * rows
779 if rowLabels is not None:
780 if len(rowLabels) != rows:
781 raise ValueError(f"'rowLabels' must be of length {rows}")
783 # If we have column labels, need to shift
784 # the text and colour arrays down 1 row
785 offset = 1
786 if colLabels is None:
787 if colColours is not None:
788 colLabels = [''] * cols
789 else:
790 offset = 0
791 elif colColours is None:
792 colColours = 'w' * cols
794 # Set up cell colours if not given
795 if cellColours is None:
796 cellColours = ['w' * cols] * rows
798 # Now create the table
799 table = Table(ax, loc, bbox, **kwargs)
800 table.edges = edges
801 height = table._approx_text_height()
803 # Add the cells
804 for row in range(rows):
805 for col in range(cols):
806 table.add_cell(row + offset, col,
807 width=colWidths[col], height=height,
808 text=cellText[row][col],
809 facecolor=cellColours[row][col],
810 loc=cellLoc)
811 # Do column labels
812 if colLabels is not None:
813 for col in range(cols):
814 table.add_cell(0, col,
815 width=colWidths[col], height=height,
816 text=colLabels[col], facecolor=colColours[col],
817 loc=colLoc)
819 # Do row labels
820 if rowLabels is not None:
821 for row in range(rows):
822 table.add_cell(row + offset, -1,
823 width=rowLabelWidth or 1e-15, height=height,
824 text=rowLabels[row], facecolor=rowColours[row],
825 loc=rowLoc)
826 if rowLabelWidth == 0:
827 table.auto_set_column_width(-1)
829 ax.add_table(table)
830 return table