You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			847 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			847 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Python
		
	
# Original code by:
 | 
						|
#    John Gill <jng@europe.renre.com>
 | 
						|
#    Copyright 2004 John Gill and John Hunter
 | 
						|
#
 | 
						|
# Subsequent changes:
 | 
						|
#    The Matplotlib development team
 | 
						|
#    Copyright The Matplotlib development team
 | 
						|
 | 
						|
"""
 | 
						|
Tables drawing.
 | 
						|
 | 
						|
.. note::
 | 
						|
    The table implementation in Matplotlib is lightly maintained. For a more
 | 
						|
    featureful table implementation, you may wish to try `blume
 | 
						|
    <https://github.com/swfiua/blume>`_.
 | 
						|
 | 
						|
Use the factory function `~matplotlib.table.table` to create a ready-made
 | 
						|
table from texts. If you need more control, use the `.Table` class and its
 | 
						|
methods.
 | 
						|
 | 
						|
The table consists of a grid of cells, which are indexed by (row, column).
 | 
						|
The cell (0, 0) is positioned at the top left.
 | 
						|
 | 
						|
Thanks to John Gill for providing the class and table.
 | 
						|
"""
 | 
						|
 | 
						|
import numpy as np
 | 
						|
 | 
						|
from . import _api, _docstring
 | 
						|
from .artist import Artist, allow_rasterization
 | 
						|
from .patches import Rectangle
 | 
						|
from .text import Text
 | 
						|
from .transforms import Bbox
 | 
						|
from .path import Path
 | 
						|
 | 
						|
from .cbook import _is_pandas_dataframe
 | 
						|
 | 
						|
 | 
						|
class Cell(Rectangle):
 | 
						|
    """
 | 
						|
    A cell is a `.Rectangle` with some associated `.Text`.
 | 
						|
 | 
						|
    As a user, you'll most likely not creates cells yourself. Instead, you
 | 
						|
    should use either the `~matplotlib.table.table` factory function or
 | 
						|
    `.Table.add_cell`.
 | 
						|
    """
 | 
						|
 | 
						|
    PAD = 0.1
 | 
						|
    """Padding between text and rectangle."""
 | 
						|
 | 
						|
    _edges = 'BRTL'
 | 
						|
    _edge_aliases = {'open':         '',
 | 
						|
                     'closed':       _edges,  # default
 | 
						|
                     'horizontal':   'BT',
 | 
						|
                     'vertical':     'RL'
 | 
						|
                     }
 | 
						|
 | 
						|
    def __init__(self, xy, width, height, *,
 | 
						|
                 edgecolor='k', facecolor='w',
 | 
						|
                 fill=True,
 | 
						|
                 text='',
 | 
						|
                 loc='right',
 | 
						|
                 fontproperties=None,
 | 
						|
                 visible_edges='closed',
 | 
						|
                 ):
 | 
						|
        """
 | 
						|
        Parameters
 | 
						|
        ----------
 | 
						|
        xy : 2-tuple
 | 
						|
            The position of the bottom left corner of the cell.
 | 
						|
        width : float
 | 
						|
            The cell width.
 | 
						|
        height : float
 | 
						|
            The cell height.
 | 
						|
        edgecolor : :mpltype:`color`, default: 'k'
 | 
						|
            The color of the cell border.
 | 
						|
        facecolor : :mpltype:`color`, default: 'w'
 | 
						|
            The cell facecolor.
 | 
						|
        fill : bool, default: True
 | 
						|
            Whether the cell background is filled.
 | 
						|
        text : str, optional
 | 
						|
            The cell text.
 | 
						|
        loc : {'right', 'center', 'left'}
 | 
						|
            The alignment of the text within the cell.
 | 
						|
        fontproperties : dict, optional
 | 
						|
            A dict defining the font properties of the text. Supported keys and
 | 
						|
            values are the keyword arguments accepted by `.FontProperties`.
 | 
						|
        visible_edges : {'closed', 'open', 'horizontal', 'vertical'} or \
 | 
						|
substring of 'BRTL'
 | 
						|
            The cell edges to be drawn with a line: a substring of 'BRTL'
 | 
						|
            (bottom, right, top, left), or one of 'open' (no edges drawn),
 | 
						|
            'closed' (all edges drawn), 'horizontal' (bottom and top),
 | 
						|
            'vertical' (right and left).
 | 
						|
        """
 | 
						|
 | 
						|
        # Call base
 | 
						|
        super().__init__(xy, width=width, height=height, fill=fill,
 | 
						|
                         edgecolor=edgecolor, facecolor=facecolor)
 | 
						|
        self.set_clip_on(False)
 | 
						|
        self.visible_edges = visible_edges
 | 
						|
 | 
						|
        # Create text object
 | 
						|
        self._loc = loc
 | 
						|
        self._text = Text(x=xy[0], y=xy[1], clip_on=False,
 | 
						|
                          text=text, fontproperties=fontproperties,
 | 
						|
                          horizontalalignment=loc, verticalalignment='center')
 | 
						|
 | 
						|
    def set_transform(self, t):
 | 
						|
        super().set_transform(t)
 | 
						|
        # the text does not get the transform!
 | 
						|
        self.stale = True
 | 
						|
 | 
						|
    def set_figure(self, fig):
 | 
						|
        super().set_figure(fig)
 | 
						|
        self._text.set_figure(fig)
 | 
						|
 | 
						|
    def get_text(self):
 | 
						|
        """Return the cell `.Text` instance."""
 | 
						|
        return self._text
 | 
						|
 | 
						|
    def set_fontsize(self, size):
 | 
						|
        """Set the text fontsize."""
 | 
						|
        self._text.set_fontsize(size)
 | 
						|
        self.stale = True
 | 
						|
 | 
						|
    def get_fontsize(self):
 | 
						|
        """Return the cell fontsize."""
 | 
						|
        return self._text.get_fontsize()
 | 
						|
 | 
						|
    def auto_set_font_size(self, renderer):
 | 
						|
        """Shrink font size until the text fits into the cell width."""
 | 
						|
        fontsize = self.get_fontsize()
 | 
						|
        required = self.get_required_width(renderer)
 | 
						|
        while fontsize > 1 and required > self.get_width():
 | 
						|
            fontsize -= 1
 | 
						|
            self.set_fontsize(fontsize)
 | 
						|
            required = self.get_required_width(renderer)
 | 
						|
 | 
						|
        return fontsize
 | 
						|
 | 
						|
    @allow_rasterization
 | 
						|
    def draw(self, renderer):
 | 
						|
        if not self.get_visible():
 | 
						|
            return
 | 
						|
        # draw the rectangle
 | 
						|
        super().draw(renderer)
 | 
						|
        # position the text
 | 
						|
        self._set_text_position(renderer)
 | 
						|
        self._text.draw(renderer)
 | 
						|
        self.stale = False
 | 
						|
 | 
						|
    def _set_text_position(self, renderer):
 | 
						|
        """Set text up so it is drawn in the right place."""
 | 
						|
        bbox = self.get_window_extent(renderer)
 | 
						|
        # center vertically
 | 
						|
        y = bbox.y0 + bbox.height / 2
 | 
						|
        # position horizontally
 | 
						|
        loc = self._text.get_horizontalalignment()
 | 
						|
        if loc == 'center':
 | 
						|
            x = bbox.x0 + bbox.width / 2
 | 
						|
        elif loc == 'left':
 | 
						|
            x = bbox.x0 + bbox.width * self.PAD
 | 
						|
        else:  # right.
 | 
						|
            x = bbox.x0 + bbox.width * (1 - self.PAD)
 | 
						|
        self._text.set_position((x, y))
 | 
						|
 | 
						|
    def get_text_bounds(self, renderer):
 | 
						|
        """
 | 
						|
        Return the text bounds as *(x, y, width, height)* in table coordinates.
 | 
						|
        """
 | 
						|
        return (self._text.get_window_extent(renderer)
 | 
						|
                .transformed(self.get_data_transform().inverted())
 | 
						|
                .bounds)
 | 
						|
 | 
						|
    def get_required_width(self, renderer):
 | 
						|
        """Return the minimal required width for the cell."""
 | 
						|
        l, b, w, h = self.get_text_bounds(renderer)
 | 
						|
        return w * (1.0 + (2.0 * self.PAD))
 | 
						|
 | 
						|
    @_docstring.interpd
 | 
						|
    def set_text_props(self, **kwargs):
 | 
						|
        """
 | 
						|
        Update the text properties.
 | 
						|
 | 
						|
        Valid keyword arguments are:
 | 
						|
 | 
						|
        %(Text:kwdoc)s
 | 
						|
        """
 | 
						|
        self._text._internal_update(kwargs)
 | 
						|
        self.stale = True
 | 
						|
 | 
						|
    @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
 | 
						|
    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:
 | 
						|
            if any(edge not in self._edges for edge in value):
 | 
						|
                raise ValueError('Invalid edge param {}, must only be one of '
 | 
						|
                                 '{} or string of {}'.format(
 | 
						|
                                     value,
 | 
						|
                                     ", ".join(self._edge_aliases),
 | 
						|
                                     ", ".join(self._edges)))
 | 
						|
            self._visible_edges = value
 | 
						|
        self.stale = True
 | 
						|
 | 
						|
    def get_path(self):
 | 
						|
        """Return a `.Path` for the `.visible_edges`."""
 | 
						|
        codes = [Path.MOVETO]
 | 
						|
        codes.extend(
 | 
						|
            Path.LINETO if edge in self._visible_edges else Path.MOVETO
 | 
						|
            for edge in self._edges)
 | 
						|
        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
 | 
						|
            )
 | 
						|
 | 
						|
 | 
						|
CustomCell = Cell  # Backcompat. alias.
 | 
						|
 | 
						|
 | 
						|
class Table(Artist):
 | 
						|
    """
 | 
						|
    A table of cells.
 | 
						|
 | 
						|
    The table consists of a grid of cells, which are indexed by (row, column).
 | 
						|
 | 
						|
    For a simple table, you'll have a full grid of cells with indices from
 | 
						|
    (0, 0) to (num_rows-1, num_cols-1), in which the cell (0, 0) is positioned
 | 
						|
    at the top left. However, you can also add cells with negative indices.
 | 
						|
    You don't have to add a cell to every grid position, so you can create
 | 
						|
    tables that have holes.
 | 
						|
 | 
						|
    *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
 | 
						|
             'upper left':   2,
 | 
						|
             'lower left':   3,
 | 
						|
             'lower right':  4,
 | 
						|
             'center left':  5,
 | 
						|
             'center right': 6,
 | 
						|
             'lower center': 7,
 | 
						|
             'upper center': 8,
 | 
						|
             'center':       9,
 | 
						|
             'top right':    10,
 | 
						|
             'top left':     11,
 | 
						|
             'bottom left':  12,
 | 
						|
             'bottom right': 13,
 | 
						|
             'right':        14,
 | 
						|
             'left':         15,
 | 
						|
             '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 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, optional
 | 
						|
            The position of the cell with respect to *ax*. This must be one of
 | 
						|
            the `~.Table.codes`.
 | 
						|
        bbox : `.Bbox` or [xmin, ymin, width, height], optional
 | 
						|
            A bounding box to draw the table into. If this is not *None*, this
 | 
						|
            overrides *loc*.
 | 
						|
 | 
						|
        Other Parameters
 | 
						|
        ----------------
 | 
						|
        **kwargs
 | 
						|
            `.Artist` properties.
 | 
						|
        """
 | 
						|
 | 
						|
        super().__init__()
 | 
						|
 | 
						|
        if isinstance(loc, str):
 | 
						|
            if loc not in self.codes:
 | 
						|
                raise ValueError(
 | 
						|
                    "Unrecognized location {!r}. Valid locations are\n\t{}"
 | 
						|
                    .format(loc, '\n\t'.join(self.codes)))
 | 
						|
            loc = self.codes[loc]
 | 
						|
        self.set_figure(ax.get_figure(root=False))
 | 
						|
        self._axes = ax
 | 
						|
        self._loc = loc
 | 
						|
        self._bbox = bbox
 | 
						|
 | 
						|
        # use axes coords
 | 
						|
        ax._unstale_viewLim()
 | 
						|
        self.set_transform(ax.transAxes)
 | 
						|
 | 
						|
        self._cells = {}
 | 
						|
        self._edges = None
 | 
						|
        self._autoColumns = []
 | 
						|
        self._autoFontsize = True
 | 
						|
        self._internal_update(kwargs)
 | 
						|
 | 
						|
        self.set_clip_on(False)
 | 
						|
 | 
						|
    def add_cell(self, row, col, *args, **kwargs):
 | 
						|
        """
 | 
						|
        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
 | 
						|
        -------
 | 
						|
        `.Cell`
 | 
						|
            The created cell.
 | 
						|
 | 
						|
        """
 | 
						|
        xy = (0, 0)
 | 
						|
        cell = Cell(xy, visible_edges=self.edges, *args, **kwargs)
 | 
						|
        self[row, col] = cell
 | 
						|
        return cell
 | 
						|
 | 
						|
    def __setitem__(self, position, cell):
 | 
						|
        """
 | 
						|
        Set a custom cell in a given position.
 | 
						|
        """
 | 
						|
        _api.check_isinstance(Cell, cell=cell)
 | 
						|
        try:
 | 
						|
            row, col = position[0], position[1]
 | 
						|
        except Exception as err:
 | 
						|
            raise KeyError('Only tuples length 2 are accepted as '
 | 
						|
                           'coordinates') from err
 | 
						|
        cell.set_figure(self.get_figure(root=False))
 | 
						|
        cell.set_transform(self.get_transform())
 | 
						|
        cell.set_clip_on(False)
 | 
						|
        self._cells[row, col] = cell
 | 
						|
        self.stale = True
 | 
						|
 | 
						|
    def __getitem__(self, position):
 | 
						|
        """Retrieve a custom cell from a given position."""
 | 
						|
        return self._cells[position]
 | 
						|
 | 
						|
    @property
 | 
						|
    def edges(self):
 | 
						|
        """
 | 
						|
        The default value of `~.Cell.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
 | 
						|
    def edges(self, value):
 | 
						|
        self._edges = value
 | 
						|
        self.stale = True
 | 
						|
 | 
						|
    def _approx_text_height(self):
 | 
						|
        return (self.FONTSIZE / 72.0 * self.get_figure(root=True).dpi /
 | 
						|
                self._axes.bbox.height * 1.2)
 | 
						|
 | 
						|
    @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:
 | 
						|
            renderer = self.get_figure(root=True)._get_renderer()
 | 
						|
        if renderer is None:
 | 
						|
            raise RuntimeError('No renderer defined')
 | 
						|
 | 
						|
        if not self.get_visible():
 | 
						|
            return
 | 
						|
        renderer.open_group('table', gid=self.get_gid())
 | 
						|
        self._update_positions(renderer)
 | 
						|
 | 
						|
        for key in sorted(self._cells):
 | 
						|
            self._cells[key].draw(renderer)
 | 
						|
 | 
						|
        renderer.close_group('table')
 | 
						|
        self.stale = False
 | 
						|
 | 
						|
    def _get_grid_bbox(self, renderer):
 | 
						|
        """
 | 
						|
        Get a bbox, in axes coordinates for the cells.
 | 
						|
 | 
						|
        Only include those in the range (0, 0) to (maxRow, maxCol).
 | 
						|
        """
 | 
						|
        boxes = [cell.get_window_extent(renderer)
 | 
						|
                 for (row, col), cell in self._cells.items()
 | 
						|
                 if row >= 0 and col >= 0]
 | 
						|
        bbox = Bbox.union(boxes)
 | 
						|
        return bbox.transformed(self.get_transform().inverted())
 | 
						|
 | 
						|
    def contains(self, mouseevent):
 | 
						|
        # docstring inherited
 | 
						|
        if self._different_canvas(mouseevent):
 | 
						|
            return False, {}
 | 
						|
        # TODO: Return index of the cell containing the cursor so that the user
 | 
						|
        # doesn't have to bind to each one individually.
 | 
						|
        renderer = self.get_figure(root=True)._get_renderer()
 | 
						|
        if renderer is not None:
 | 
						|
            boxes = [cell.get_window_extent(renderer)
 | 
						|
                     for (row, col), cell in self._cells.items()
 | 
						|
                     if row >= 0 and col >= 0]
 | 
						|
            bbox = Bbox.union(boxes)
 | 
						|
            return bbox.contains(mouseevent.x, mouseevent.y), {}
 | 
						|
        else:
 | 
						|
            return False, {}
 | 
						|
 | 
						|
    def get_children(self):
 | 
						|
        """Return the Artists contained by the table."""
 | 
						|
        return list(self._cells.values())
 | 
						|
 | 
						|
    def get_window_extent(self, renderer=None):
 | 
						|
        # docstring inherited
 | 
						|
        if renderer is None:
 | 
						|
            renderer = self.get_figure(root=True)._get_renderer()
 | 
						|
        self._update_positions(renderer)
 | 
						|
        boxes = [cell.get_window_extent(renderer)
 | 
						|
                 for cell in self._cells.values()]
 | 
						|
        return Bbox.union(boxes)
 | 
						|
 | 
						|
    def _do_cell_alignment(self):
 | 
						|
        """
 | 
						|
        Calculate row heights and column widths; position cells accordingly.
 | 
						|
        """
 | 
						|
        # Calculate row/column widths
 | 
						|
        widths = {}
 | 
						|
        heights = {}
 | 
						|
        for (row, col), cell in self._cells.items():
 | 
						|
            height = heights.setdefault(row, 0.0)
 | 
						|
            heights[row] = max(height, cell.get_height())
 | 
						|
            width = widths.setdefault(col, 0.0)
 | 
						|
            widths[col] = max(width, cell.get_width())
 | 
						|
 | 
						|
        # work out left position for each column
 | 
						|
        xpos = 0
 | 
						|
        lefts = {}
 | 
						|
        for col in sorted(widths):
 | 
						|
            lefts[col] = xpos
 | 
						|
            xpos += widths[col]
 | 
						|
 | 
						|
        ypos = 0
 | 
						|
        bottoms = {}
 | 
						|
        for row in sorted(heights, reverse=True):
 | 
						|
            bottoms[row] = ypos
 | 
						|
            ypos += heights[row]
 | 
						|
 | 
						|
        # set cell positions
 | 
						|
        for (row, col), cell in self._cells.items():
 | 
						|
            cell.set_x(lefts[col])
 | 
						|
            cell.set_y(bottoms[row])
 | 
						|
 | 
						|
    def auto_set_column_width(self, col):
 | 
						|
        """
 | 
						|
        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.
 | 
						|
        """
 | 
						|
        col1d = np.atleast_1d(col)
 | 
						|
        if not np.issubdtype(col1d.dtype, np.integer):
 | 
						|
            raise TypeError("col must be an int or sequence of ints.")
 | 
						|
        for cell in col1d:
 | 
						|
            self._autoColumns.append(cell)
 | 
						|
 | 
						|
        self.stale = True
 | 
						|
 | 
						|
    def _auto_set_column_width(self, col, renderer):
 | 
						|
        """Automatically set width for column."""
 | 
						|
        cells = [cell for key, cell in self._cells.items() if key[1] == col]
 | 
						|
        max_width = max((cell.get_required_width(renderer) for cell in cells),
 | 
						|
                        default=0)
 | 
						|
        for cell in cells:
 | 
						|
            cell.set_width(max_width)
 | 
						|
 | 
						|
    def auto_set_font_size(self, value=True):
 | 
						|
        """Automatically set font size."""
 | 
						|
        self._autoFontsize = value
 | 
						|
        self.stale = True
 | 
						|
 | 
						|
    def _auto_set_font_size(self, renderer):
 | 
						|
 | 
						|
        if len(self._cells) == 0:
 | 
						|
            return
 | 
						|
        fontsize = next(iter(self._cells.values())).get_fontsize()
 | 
						|
        cells = []
 | 
						|
        for key, cell in self._cells.items():
 | 
						|
            # ignore auto-sized columns
 | 
						|
            if key[1] in self._autoColumns:
 | 
						|
                continue
 | 
						|
            size = cell.auto_set_font_size(renderer)
 | 
						|
            fontsize = min(fontsize, size)
 | 
						|
            cells.append(cell)
 | 
						|
 | 
						|
        # now set all fontsizes equal
 | 
						|
        for cell in self._cells.values():
 | 
						|
            cell.set_fontsize(fontsize)
 | 
						|
 | 
						|
    def scale(self, xscale, 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)
 | 
						|
 | 
						|
    def set_fontsize(self, size):
 | 
						|
        """
 | 
						|
        Set the font size, in points, of the cell text.
 | 
						|
 | 
						|
        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
 | 
						|
 | 
						|
    def _offset(self, ox, oy):
 | 
						|
        """Move all the artists by ox, oy (axes coords)."""
 | 
						|
        for c in self._cells.values():
 | 
						|
            x, y = c.get_x(), c.get_y()
 | 
						|
            c.set_x(x + ox)
 | 
						|
            c.set_y(y + oy)
 | 
						|
 | 
						|
    def _update_positions(self, renderer):
 | 
						|
        # called from renderer to allow more precise estimates of
 | 
						|
        # widths and heights with get_window_extent
 | 
						|
 | 
						|
        # Do any auto width setting
 | 
						|
        for col in self._autoColumns:
 | 
						|
            self._auto_set_column_width(col, renderer)
 | 
						|
 | 
						|
        if self._autoFontsize:
 | 
						|
            self._auto_set_font_size(renderer)
 | 
						|
 | 
						|
        # Align all the cells
 | 
						|
        self._do_cell_alignment()
 | 
						|
 | 
						|
        bbox = self._get_grid_bbox(renderer)
 | 
						|
        l, b, w, h = bbox.bounds
 | 
						|
 | 
						|
        if self._bbox is not None:
 | 
						|
            # Position according to bbox
 | 
						|
            if isinstance(self._bbox, Bbox):
 | 
						|
                rl, rb, rw, rh = self._bbox.bounds
 | 
						|
            else:
 | 
						|
                rl, rb, rw, rh = self._bbox
 | 
						|
            self.scale(rw / w, rh / h)
 | 
						|
            ox = rl - l
 | 
						|
            oy = rb - b
 | 
						|
            self._do_cell_alignment()
 | 
						|
        else:
 | 
						|
            # Position using loc
 | 
						|
            (BEST, UR, UL, LL, LR, CL, CR, LC, UC, C,
 | 
						|
             TR, TL, BL, BR, R, L, T, B) = range(len(self.codes))
 | 
						|
            # defaults for center
 | 
						|
            ox = (0.5 - w / 2) - l
 | 
						|
            oy = (0.5 - h / 2) - b
 | 
						|
            if self._loc in (UL, LL, CL):   # left
 | 
						|
                ox = self.AXESPAD - l
 | 
						|
            if self._loc in (BEST, UR, LR, R, CR):  # right
 | 
						|
                ox = 1 - (l + w + self.AXESPAD)
 | 
						|
            if self._loc in (BEST, UR, UL, UC):     # upper
 | 
						|
                oy = 1 - (b + h + self.AXESPAD)
 | 
						|
            if self._loc in (LL, LR, LC):           # lower
 | 
						|
                oy = self.AXESPAD - b
 | 
						|
            if self._loc in (LC, UC, C):            # center x
 | 
						|
                ox = (0.5 - w / 2) - l
 | 
						|
            if self._loc in (CL, CR, C):            # center y
 | 
						|
                oy = (0.5 - h / 2) - b
 | 
						|
 | 
						|
            if self._loc in (TL, BL, L):            # out left
 | 
						|
                ox = - (l + w)
 | 
						|
            if self._loc in (TR, BR, R):            # out right
 | 
						|
                ox = 1.0 - l
 | 
						|
            if self._loc in (TR, TL, T):            # out top
 | 
						|
                oy = 1.0 - b
 | 
						|
            if self._loc in (BL, BR, B):           # out bottom
 | 
						|
                oy = - (b + h)
 | 
						|
 | 
						|
        self._offset(ox, oy)
 | 
						|
 | 
						|
    def get_celld(self):
 | 
						|
        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
 | 
						|
 | 
						|
 | 
						|
@_docstring.interpd
 | 
						|
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, edges='closed',
 | 
						|
          **kwargs):
 | 
						|
    """
 | 
						|
    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.
 | 
						|
 | 
						|
    For finer grained control over tables, use the `.Table` class and add it to
 | 
						|
    the Axes with `.Axes.add_table`.
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    cellText : 2D list of str or pandas.DataFrame, optional
 | 
						|
        The texts to place into the table cells.
 | 
						|
 | 
						|
        *Note*: Line breaks in the strings are currently not accounted for and
 | 
						|
        will result in the text exceeding the cell boundaries.
 | 
						|
 | 
						|
    cellColours : 2D list of :mpltype:`color`, optional
 | 
						|
        The background colors of the cells.
 | 
						|
 | 
						|
    cellLoc : {'right', 'center', 'left'}
 | 
						|
        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 :mpltype:`color`, optional
 | 
						|
        The colors of the row header cells.
 | 
						|
 | 
						|
    rowLoc : {'left', 'center', 'right'}
 | 
						|
        The text alignment of the row header cells.
 | 
						|
 | 
						|
    colLabels : list of str, optional
 | 
						|
        The text of the column header cells.
 | 
						|
 | 
						|
    colColours : list of :mpltype:`color`, optional
 | 
						|
        The colors of the column header cells.
 | 
						|
 | 
						|
    colLoc : {'center', 'left', 'right'}
 | 
						|
        The text alignment of the column header cells.
 | 
						|
 | 
						|
    loc : str, default: 'bottom'
 | 
						|
        The position of the cell with respect to *ax*. This must be one of
 | 
						|
        the `~.Table.codes`.
 | 
						|
 | 
						|
    bbox : `.Bbox` or [xmin, ymin, width, height], optional
 | 
						|
        A bounding box to draw the table into. If this is not *None*, this
 | 
						|
        overrides *loc*.
 | 
						|
 | 
						|
    edges : {'closed', 'open', 'horizontal', 'vertical'} or substring of 'BRTL'
 | 
						|
        The cell edges to be drawn with a line. See also
 | 
						|
        `~.Cell.visible_edges`.
 | 
						|
 | 
						|
    Returns
 | 
						|
    -------
 | 
						|
    `~matplotlib.table.Table`
 | 
						|
        The created table.
 | 
						|
 | 
						|
    Other Parameters
 | 
						|
    ----------------
 | 
						|
    **kwargs
 | 
						|
        `.Table` properties.
 | 
						|
 | 
						|
    %(Table:kwdoc)s
 | 
						|
    """
 | 
						|
 | 
						|
    if cellColours is None and cellText is None:
 | 
						|
        raise ValueError('At least one argument from "cellColours" or '
 | 
						|
                         '"cellText" must be provided to create a table.')
 | 
						|
 | 
						|
    # Check we have some cellText
 | 
						|
    if cellText is None:
 | 
						|
        # assume just colours are needed
 | 
						|
        rows = len(cellColours)
 | 
						|
        cols = len(cellColours[0])
 | 
						|
        cellText = [[''] * cols] * rows
 | 
						|
 | 
						|
    # Check if we have a Pandas DataFrame
 | 
						|
    if _is_pandas_dataframe(cellText):
 | 
						|
        # if rowLabels/colLabels are empty, use DataFrame entries.
 | 
						|
        # Otherwise, throw an error.
 | 
						|
        if rowLabels is None:
 | 
						|
            rowLabels = cellText.index
 | 
						|
        else:
 | 
						|
            raise ValueError("rowLabels cannot be used alongside Pandas DataFrame")
 | 
						|
        if colLabels is None:
 | 
						|
            colLabels = cellText.columns
 | 
						|
        else:
 | 
						|
            raise ValueError("colLabels cannot be used alongside Pandas DataFrame")
 | 
						|
        # Update cellText with only values
 | 
						|
        cellText = cellText.values
 | 
						|
 | 
						|
    rows = len(cellText)
 | 
						|
    cols = len(cellText[0])
 | 
						|
    for row in cellText:
 | 
						|
        if len(row) != cols:
 | 
						|
            raise ValueError(f"Each row in 'cellText' must have {cols} "
 | 
						|
                             "columns")
 | 
						|
 | 
						|
    if cellColours is not None:
 | 
						|
        if len(cellColours) != rows:
 | 
						|
            raise ValueError(f"'cellColours' must have {rows} rows")
 | 
						|
        for row in cellColours:
 | 
						|
            if len(row) != cols:
 | 
						|
                raise ValueError("Each row in 'cellColours' must have "
 | 
						|
                                 f"{cols} columns")
 | 
						|
    else:
 | 
						|
        cellColours = ['w' * cols] * rows
 | 
						|
 | 
						|
    # Set colwidths if not given
 | 
						|
    if colWidths is None:
 | 
						|
        colWidths = [1.0 / cols] * cols
 | 
						|
 | 
						|
    # Fill in missing information for column
 | 
						|
    # and row labels
 | 
						|
    rowLabelWidth = 0
 | 
						|
    if rowLabels is None:
 | 
						|
        if rowColours is not None:
 | 
						|
            rowLabels = [''] * rows
 | 
						|
            rowLabelWidth = colWidths[0]
 | 
						|
    elif rowColours is None:
 | 
						|
        rowColours = 'w' * rows
 | 
						|
 | 
						|
    if rowLabels is not None:
 | 
						|
        if len(rowLabels) != rows:
 | 
						|
            raise ValueError(f"'rowLabels' must be of length {rows}")
 | 
						|
 | 
						|
    # If we have column labels, need to shift
 | 
						|
    # the text and colour arrays down 1 row
 | 
						|
    offset = 1
 | 
						|
    if colLabels is None:
 | 
						|
        if colColours is not None:
 | 
						|
            colLabels = [''] * cols
 | 
						|
        else:
 | 
						|
            offset = 0
 | 
						|
    elif colColours is None:
 | 
						|
        colColours = 'w' * cols
 | 
						|
 | 
						|
    # Set up cell colours if not given
 | 
						|
    if cellColours is None:
 | 
						|
        cellColours = ['w' * cols] * rows
 | 
						|
 | 
						|
    # Now create the table
 | 
						|
    table = Table(ax, loc, bbox, **kwargs)
 | 
						|
    table.edges = edges
 | 
						|
    height = table._approx_text_height()
 | 
						|
 | 
						|
    # Add the cells
 | 
						|
    for row in range(rows):
 | 
						|
        for col in range(cols):
 | 
						|
            table.add_cell(row + offset, col,
 | 
						|
                           width=colWidths[col], height=height,
 | 
						|
                           text=cellText[row][col],
 | 
						|
                           facecolor=cellColours[row][col],
 | 
						|
                           loc=cellLoc)
 | 
						|
    # Do column labels
 | 
						|
    if colLabels is not None:
 | 
						|
        for col in range(cols):
 | 
						|
            table.add_cell(0, col,
 | 
						|
                           width=colWidths[col], height=height,
 | 
						|
                           text=colLabels[col], facecolor=colColours[col],
 | 
						|
                           loc=colLoc)
 | 
						|
 | 
						|
    # Do row labels
 | 
						|
    if rowLabels is not None:
 | 
						|
        for row in range(rows):
 | 
						|
            table.add_cell(row + offset, -1,
 | 
						|
                           width=rowLabelWidth or 1e-15, height=height,
 | 
						|
                           text=rowLabels[row], facecolor=rowColours[row],
 | 
						|
                           loc=rowLoc)
 | 
						|
        if rowLabelWidth == 0:
 | 
						|
            table.auto_set_column_width(-1)
 | 
						|
 | 
						|
    # set_fontsize is only effective after cells are added
 | 
						|
    if "fontsize" in kwargs:
 | 
						|
        table.set_fontsize(kwargs["fontsize"])
 | 
						|
 | 
						|
    ax.add_table(table)
 | 
						|
    return table
 |