Coverage for /usr/lib/python3/dist-packages/matplotlib/table.py: 19%

335 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

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 

8 

9""" 

10Tables drawing. 

11 

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>`_. 

16 

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. 

20 

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

22The cell (0, 0) is positioned at the top left. 

23 

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

25""" 

26 

27from . import _api, _docstring 

28from .artist import Artist, allow_rasterization 

29from .patches import Rectangle 

30from .text import Text 

31from .transforms import Bbox 

32from .path import Path 

33 

34 

35class Cell(Rectangle): 

36 """ 

37 A cell is a `.Rectangle` with some associated `.Text`. 

38 

39 As a user, you'll most likely not creates cells yourself. Instead, you 

40 should use either the `~matplotlib.table.table` factory function or 

41 `.Table.add_cell`. 

42 """ 

43 

44 PAD = 0.1 

45 """Padding between text and rectangle.""" 

46 

47 _edges = 'BRTL' 

48 _edge_aliases = {'open': '', 

49 'closed': _edges, # default 

50 'horizontal': 'BT', 

51 'vertical': 'RL' 

52 } 

53 

54 @_api.make_keyword_only("3.6", name="edgecolor") 

55 def __init__(self, xy, width, height, 

56 edgecolor='k', facecolor='w', 

57 fill=True, 

58 text='', 

59 loc=None, 

60 fontproperties=None, 

61 *, 

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 : color 

74 The color of the cell border. 

75 facecolor : color 

76 The cell facecolor. 

77 fill : bool 

78 Whether the cell background is filled. 

79 text : str 

80 The cell text. 

81 loc : {'left', 'center', 'right'}, default: 'right' 

82 The alignment of the text within the cell. 

83 fontproperties : dict 

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 : str, default: 'closed' 

87 The cell edges to be drawn with a line: a substring of 'BRTL' 

88 (bottom, right, top, left), or one of 'open' (no edges drawn), 

89 'closed' (all edges drawn), 'horizontal' (bottom and top), 

90 'vertical' (right and left). 

91 """ 

92 

93 # Call base 

94 super().__init__(xy, width=width, height=height, fill=fill, 

95 edgecolor=edgecolor, facecolor=facecolor) 

96 self.set_clip_on(False) 

97 self.visible_edges = visible_edges 

98 

99 # Create text object 

100 if loc is None: 

101 loc = 'right' 

102 self._loc = loc 

103 self._text = Text(x=xy[0], y=xy[1], clip_on=False, 

104 text=text, fontproperties=fontproperties, 

105 horizontalalignment=loc, verticalalignment='center') 

106 

107 def set_transform(self, trans): 

108 super().set_transform(trans) 

109 # the text does not get the transform! 

110 self.stale = True 

111 

112 def set_figure(self, fig): 

113 super().set_figure(fig) 

114 self._text.set_figure(fig) 

115 

116 def get_text(self): 

117 """Return the cell `.Text` instance.""" 

118 return self._text 

119 

120 def set_fontsize(self, size): 

121 """Set the text fontsize.""" 

122 self._text.set_fontsize(size) 

123 self.stale = True 

124 

125 def get_fontsize(self): 

126 """Return the cell fontsize.""" 

127 return self._text.get_fontsize() 

128 

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) 

137 

138 return fontsize 

139 

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 

150 

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)) 

165 

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) 

173 

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)) 

178 

179 @_docstring.dedent_interpd 

180 def set_text_props(self, **kwargs): 

181 """ 

182 Update the text properties. 

183 

184 Valid keyword arguments are: 

185 

186 %(Text:kwdoc)s 

187 """ 

188 self._text._internal_update(kwargs) 

189 self.stale = True 

190 

191 @property 

192 def visible_edges(self): 

193 """ 

194 The cell edges to be drawn with a line. 

195 

196 Reading this property returns a substring of 'BRTL' (bottom, right, 

197 top, left'). 

198 

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 

203 

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 

219 

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 ) 

233 

234 

235CustomCell = Cell # Backcompat. alias. 

236 

237 

238class Table(Artist): 

239 """ 

240 A table of cells. 

241 

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

243 

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. 

249 

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.""" 

273 

274 FONTSIZE = 10 

275 

276 AXESPAD = 0.02 

277 """The border between the Axes and the table edge in Axes units.""" 

278 

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 

286 The position of the cell with respect to *ax*. This must be one of 

287 the `~.Table.codes`. 

288 bbox : `.Bbox` or None 

289 A bounding box to draw the table into. If this is not *None*, this 

290 overrides *loc*. 

291 

292 Other Parameters 

293 ---------------- 

294 **kwargs 

295 `.Artist` properties. 

296 """ 

297 

298 super().__init__() 

299 

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 

310 

311 # use axes coords 

312 ax._unstale_viewLim() 

313 self.set_transform(ax.transAxes) 

314 

315 self._cells = {} 

316 self._edges = None 

317 self._autoColumns = [] 

318 self._autoFontsize = True 

319 self._internal_update(kwargs) 

320 

321 self.set_clip_on(False) 

322 

323 def add_cell(self, row, col, *args, **kwargs): 

324 """ 

325 Create a cell and add it to the table. 

326 

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`. 

335 

336 Returns 

337 ------- 

338 `.Cell` 

339 The created cell. 

340 

341 """ 

342 xy = (0, 0) 

343 cell = Cell(xy, visible_edges=self.edges, *args, **kwargs) 

344 self[row, col] = cell 

345 return cell 

346 

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 

362 

363 def __getitem__(self, position): 

364 """Retrieve a custom cell from a given position.""" 

365 return self._cells[position] 

366 

367 @property 

368 def edges(self): 

369 """ 

370 The default value of `~.Cell.visible_edges` for newly added 

371 cells using `.add_cell`. 

372 

373 Notes 

374 ----- 

375 This setting does currently only affect newly created cells using 

376 `.add_cell`. 

377 

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

379 

380 for c in tab.get_celld().values(): 

381 c.visible_edges = 'horizontal' 

382 

383 """ 

384 return self._edges 

385 

386 @edges.setter 

387 def edges(self, value): 

388 self._edges = value 

389 self.stale = True 

390 

391 def _approx_text_height(self): 

392 return (self.FONTSIZE / 72.0 * self.figure.dpi / 

393 self._axes.bbox.height * 1.2) 

394 

395 @allow_rasterization 

396 def draw(self, renderer): 

397 # docstring inherited 

398 

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') 

405 

406 if not self.get_visible(): 

407 return 

408 renderer.open_group('table', gid=self.get_gid()) 

409 self._update_positions(renderer) 

410 

411 for key in sorted(self._cells): 

412 self._cells[key].draw(renderer) 

413 

414 renderer.close_group('table') 

415 self.stale = False 

416 

417 def _get_grid_bbox(self, renderer): 

418 """ 

419 Get a bbox, in axes coordinates for the cells. 

420 

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()) 

428 

429 def contains(self, mouseevent): 

430 # docstring inherited 

431 inside, info = self._default_contains(mouseevent) 

432 if inside is not None: 

433 return inside, info 

434 # TODO: Return index of the cell containing the cursor so that the user 

435 # doesn't have to bind to each one individually. 

436 renderer = self.figure._get_renderer() 

437 if renderer is not None: 

438 boxes = [cell.get_window_extent(renderer) 

439 for (row, col), cell in self._cells.items() 

440 if row >= 0 and col >= 0] 

441 bbox = Bbox.union(boxes) 

442 return bbox.contains(mouseevent.x, mouseevent.y), {} 

443 else: 

444 return False, {} 

445 

446 def get_children(self): 

447 """Return the Artists contained by the table.""" 

448 return list(self._cells.values()) 

449 

450 def get_window_extent(self, renderer=None): 

451 # docstring inherited 

452 if renderer is None: 

453 renderer = self.figure._get_renderer() 

454 self._update_positions(renderer) 

455 boxes = [cell.get_window_extent(renderer) 

456 for cell in self._cells.values()] 

457 return Bbox.union(boxes) 

458 

459 def _do_cell_alignment(self): 

460 """ 

461 Calculate row heights and column widths; position cells accordingly. 

462 """ 

463 # Calculate row/column widths 

464 widths = {} 

465 heights = {} 

466 for (row, col), cell in self._cells.items(): 

467 height = heights.setdefault(row, 0.0) 

468 heights[row] = max(height, cell.get_height()) 

469 width = widths.setdefault(col, 0.0) 

470 widths[col] = max(width, cell.get_width()) 

471 

472 # work out left position for each column 

473 xpos = 0 

474 lefts = {} 

475 for col in sorted(widths): 

476 lefts[col] = xpos 

477 xpos += widths[col] 

478 

479 ypos = 0 

480 bottoms = {} 

481 for row in sorted(heights, reverse=True): 

482 bottoms[row] = ypos 

483 ypos += heights[row] 

484 

485 # set cell positions 

486 for (row, col), cell in self._cells.items(): 

487 cell.set_x(lefts[col]) 

488 cell.set_y(bottoms[row]) 

489 

490 def auto_set_column_width(self, col): 

491 """ 

492 Automatically set the widths of given columns to optimal sizes. 

493 

494 Parameters 

495 ---------- 

496 col : int or sequence of ints 

497 The indices of the columns to auto-scale. 

498 """ 

499 # check for col possibility on iteration 

500 try: 

501 iter(col) 

502 except (TypeError, AttributeError): 

503 self._autoColumns.append(col) 

504 else: 

505 for cell in col: 

506 self._autoColumns.append(cell) 

507 

508 self.stale = True 

509 

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) 

517 

518 def auto_set_font_size(self, value=True): 

519 """Automatically set font size.""" 

520 self._autoFontsize = value 

521 self.stale = True 

522 

523 def _auto_set_font_size(self, renderer): 

524 

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) 

536 

537 # now set all fontsizes equal 

538 for cell in self._cells.values(): 

539 cell.set_fontsize(fontsize) 

540 

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) 

546 

547 def set_fontsize(self, size): 

548 """ 

549 Set the font size, in points, of the cell text. 

550 

551 Parameters 

552 ---------- 

553 size : float 

554 

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. 

559 

560 You can disable this behavior using `.auto_set_font_size`. 

561 

562 >>> the_table.auto_set_font_size(False) 

563 >>> the_table.set_fontsize(20) 

564 

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 

571 

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) 

578 

579 def _update_positions(self, renderer): 

580 # called from renderer to allow more precise estimates of 

581 # widths and heights with get_window_extent 

582 

583 # Do any auto width setting 

584 for col in self._autoColumns: 

585 self._auto_set_column_width(col, renderer) 

586 

587 if self._autoFontsize: 

588 self._auto_set_font_size(renderer) 

589 

590 # Align all the cells 

591 self._do_cell_alignment() 

592 

593 bbox = self._get_grid_bbox(renderer) 

594 l, b, w, h = bbox.bounds 

595 

596 if self._bbox is not None: 

597 # Position according to bbox 

598 rl, rb, rw, rh = self._bbox 

599 self.scale(rw / w, rh / h) 

600 ox = rl - l 

601 oy = rb - b 

602 self._do_cell_alignment() 

603 else: 

604 # Position using loc 

605 (BEST, UR, UL, LL, LR, CL, CR, LC, UC, C, 

606 TR, TL, BL, BR, R, L, T, B) = range(len(self.codes)) 

607 # defaults for center 

608 ox = (0.5 - w / 2) - l 

609 oy = (0.5 - h / 2) - b 

610 if self._loc in (UL, LL, CL): # left 

611 ox = self.AXESPAD - l 

612 if self._loc in (BEST, UR, LR, R, CR): # right 

613 ox = 1 - (l + w + self.AXESPAD) 

614 if self._loc in (BEST, UR, UL, UC): # upper 

615 oy = 1 - (b + h + self.AXESPAD) 

616 if self._loc in (LL, LR, LC): # lower 

617 oy = self.AXESPAD - b 

618 if self._loc in (LC, UC, C): # center x 

619 ox = (0.5 - w / 2) - l 

620 if self._loc in (CL, CR, C): # center y 

621 oy = (0.5 - h / 2) - b 

622 

623 if self._loc in (TL, BL, L): # out left 

624 ox = - (l + w) 

625 if self._loc in (TR, BR, R): # out right 

626 ox = 1.0 - l 

627 if self._loc in (TR, TL, T): # out top 

628 oy = 1.0 - b 

629 if self._loc in (BL, BR, B): # out bottom 

630 oy = - (b + h) 

631 

632 self._offset(ox, oy) 

633 

634 def get_celld(self): 

635 r""" 

636 Return a dict of cells in the table mapping *(row, column)* to 

637 `.Cell`\s. 

638 

639 Notes 

640 ----- 

641 You can also directly index into the Table object to access individual 

642 cells:: 

643 

644 cell = table[row, col] 

645 

646 """ 

647 return self._cells 

648 

649 

650@_docstring.dedent_interpd 

651def table(ax, 

652 cellText=None, cellColours=None, 

653 cellLoc='right', colWidths=None, 

654 rowLabels=None, rowColours=None, rowLoc='left', 

655 colLabels=None, colColours=None, colLoc='center', 

656 loc='bottom', bbox=None, edges='closed', 

657 **kwargs): 

658 """ 

659 Add a table to an `~.axes.Axes`. 

660 

661 At least one of *cellText* or *cellColours* must be specified. These 

662 parameters must be 2D lists, in which the outer lists define the rows and 

663 the inner list define the column values per row. Each row must have the 

664 same number of elements. 

665 

666 The table can optionally have row and column headers, which are configured 

667 using *rowLabels*, *rowColours*, *rowLoc* and *colLabels*, *colColours*, 

668 *colLoc* respectively. 

669 

670 For finer grained control over tables, use the `.Table` class and add it to 

671 the axes with `.Axes.add_table`. 

672 

673 Parameters 

674 ---------- 

675 cellText : 2D list of str, optional 

676 The texts to place into the table cells. 

677 

678 *Note*: Line breaks in the strings are currently not accounted for and 

679 will result in the text exceeding the cell boundaries. 

680 

681 cellColours : 2D list of colors, optional 

682 The background colors of the cells. 

683 

684 cellLoc : {'left', 'center', 'right'}, default: 'right' 

685 The alignment of the text within the cells. 

686 

687 colWidths : list of float, optional 

688 The column widths in units of the axes. If not given, all columns will 

689 have a width of *1 / ncols*. 

690 

691 rowLabels : list of str, optional 

692 The text of the row header cells. 

693 

694 rowColours : list of colors, optional 

695 The colors of the row header cells. 

696 

697 rowLoc : {'left', 'center', 'right'}, default: 'left' 

698 The text alignment of the row header cells. 

699 

700 colLabels : list of str, optional 

701 The text of the column header cells. 

702 

703 colColours : list of colors, optional 

704 The colors of the column header cells. 

705 

706 colLoc : {'left', 'center', 'right'}, default: 'left' 

707 The text alignment of the column header cells. 

708 

709 loc : str, optional 

710 The position of the cell with respect to *ax*. This must be one of 

711 the `~.Table.codes`. 

712 

713 bbox : `.Bbox`, optional 

714 A bounding box to draw the table into. If this is not *None*, this 

715 overrides *loc*. 

716 

717 edges : substring of 'BRTL' or {'open', 'closed', 'horizontal', 'vertical'} 

718 The cell edges to be drawn with a line. See also 

719 `~.Cell.visible_edges`. 

720 

721 Returns 

722 ------- 

723 `~matplotlib.table.Table` 

724 The created table. 

725 

726 Other Parameters 

727 ---------------- 

728 **kwargs 

729 `.Table` properties. 

730 

731 %(Table:kwdoc)s 

732 """ 

733 

734 if cellColours is None and cellText is None: 

735 raise ValueError('At least one argument from "cellColours" or ' 

736 '"cellText" must be provided to create a table.') 

737 

738 # Check we have some cellText 

739 if cellText is None: 

740 # assume just colours are needed 

741 rows = len(cellColours) 

742 cols = len(cellColours[0]) 

743 cellText = [[''] * cols] * rows 

744 

745 rows = len(cellText) 

746 cols = len(cellText[0]) 

747 for row in cellText: 

748 if len(row) != cols: 

749 raise ValueError("Each row in 'cellText' must have {} columns" 

750 .format(cols)) 

751 

752 if cellColours is not None: 

753 if len(cellColours) != rows: 

754 raise ValueError("'cellColours' must have {} rows".format(rows)) 

755 for row in cellColours: 

756 if len(row) != cols: 

757 raise ValueError("Each row in 'cellColours' must have {} " 

758 "columns".format(cols)) 

759 else: 

760 cellColours = ['w' * cols] * rows 

761 

762 # Set colwidths if not given 

763 if colWidths is None: 

764 colWidths = [1.0 / cols] * cols 

765 

766 # Fill in missing information for column 

767 # and row labels 

768 rowLabelWidth = 0 

769 if rowLabels is None: 

770 if rowColours is not None: 

771 rowLabels = [''] * rows 

772 rowLabelWidth = colWidths[0] 

773 elif rowColours is None: 

774 rowColours = 'w' * rows 

775 

776 if rowLabels is not None: 

777 if len(rowLabels) != rows: 

778 raise ValueError("'rowLabels' must be of length {0}".format(rows)) 

779 

780 # If we have column labels, need to shift 

781 # the text and colour arrays down 1 row 

782 offset = 1 

783 if colLabels is None: 

784 if colColours is not None: 

785 colLabels = [''] * cols 

786 else: 

787 offset = 0 

788 elif colColours is None: 

789 colColours = 'w' * cols 

790 

791 # Set up cell colours if not given 

792 if cellColours is None: 

793 cellColours = ['w' * cols] * rows 

794 

795 # Now create the table 

796 table = Table(ax, loc, bbox, **kwargs) 

797 table.edges = edges 

798 height = table._approx_text_height() 

799 

800 # Add the cells 

801 for row in range(rows): 

802 for col in range(cols): 

803 table.add_cell(row + offset, col, 

804 width=colWidths[col], height=height, 

805 text=cellText[row][col], 

806 facecolor=cellColours[row][col], 

807 loc=cellLoc) 

808 # Do column labels 

809 if colLabels is not None: 

810 for col in range(cols): 

811 table.add_cell(0, col, 

812 width=colWidths[col], height=height, 

813 text=colLabels[col], facecolor=colColours[col], 

814 loc=colLoc) 

815 

816 # Do row labels 

817 if rowLabels is not None: 

818 for row in range(rows): 

819 table.add_cell(row + offset, -1, 

820 width=rowLabelWidth or 1e-15, height=height, 

821 text=rowLabels[row], facecolor=rowColours[row], 

822 loc=rowLoc) 

823 if rowLabelWidth == 0: 

824 table.auto_set_column_width(-1) 

825 

826 ax.add_table(table) 

827 return table