Hide keyboard shortcuts

Hot-keys on this page

r m x p   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 

8 

9""" 

10This module provides functionality to add a table to a plot. 

11 

12Use the factory function `~matplotlib.table.table` to create a ready-made 

13table from texts. If you need more control, use the `.Table` class and its 

14methods. 

15 

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

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

18 

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

20""" 

21 

22from . import artist, cbook, docstring 

23from .artist import Artist, allow_rasterization 

24from .patches import Rectangle 

25from .text import Text 

26from .transforms import Bbox 

27from .path import Path 

28 

29 

30class Cell(Rectangle): 

31 """ 

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

33 

34 .. note: 

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

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

37 `.Table.add_cell`. 

38 

39 Parameters 

40 ---------- 

41 xy : 2-tuple 

42 The position of the bottom left corner of the cell. 

43 width : float 

44 The cell width. 

45 height : float 

46 The cell height. 

47 edgecolor : color 

48 The color of the cell border. 

49 facecolor : color 

50 The cell facecolor. 

51 fill : bool 

52 Whether the cell background is filled. 

53 text : str 

54 The cell text. 

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

56 The alignment of the text within the cell. 

57 fontproperties : dict 

58 A dict defining the font properties of the text. Supported keys and 

59 values are the keyword arguments accepted by `.FontProperties`. 

60 """ 

61 

62 PAD = 0.1 

63 """Padding between text and rectangle.""" 

64 

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

66 edgecolor='k', facecolor='w', 

67 fill=True, 

68 text='', 

69 loc=None, 

70 fontproperties=None 

71 ): 

72 

73 # Call base 

74 Rectangle.__init__(self, xy, width=width, height=height, fill=fill, 

75 edgecolor=edgecolor, facecolor=facecolor) 

76 self.set_clip_on(False) 

77 

78 # Create text object 

79 if loc is None: 

80 loc = 'right' 

81 self._loc = loc 

82 self._text = Text(x=xy[0], y=xy[1], text=text, 

83 fontproperties=fontproperties) 

84 self._text.set_clip_on(False) 

85 

86 def set_transform(self, trans): 

87 Rectangle.set_transform(self, trans) 

88 # the text does not get the transform! 

89 self.stale = True 

90 

91 def set_figure(self, fig): 

92 Rectangle.set_figure(self, fig) 

93 self._text.set_figure(fig) 

94 

95 def get_text(self): 

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

97 return self._text 

98 

99 def set_fontsize(self, size): 

100 """Set the text fontsize.""" 

101 self._text.set_fontsize(size) 

102 self.stale = True 

103 

104 def get_fontsize(self): 

105 """Return the cell fontsize.""" 

106 return self._text.get_fontsize() 

107 

108 def auto_set_font_size(self, renderer): 

109 """Shrink font size until the text fits into the cell width.""" 

110 fontsize = self.get_fontsize() 

111 required = self.get_required_width(renderer) 

112 while fontsize > 1 and required > self.get_width(): 

113 fontsize -= 1 

114 self.set_fontsize(fontsize) 

115 required = self.get_required_width(renderer) 

116 

117 return fontsize 

118 

119 @allow_rasterization 

120 def draw(self, renderer): 

121 if not self.get_visible(): 

122 return 

123 # draw the rectangle 

124 Rectangle.draw(self, renderer) 

125 

126 # position the text 

127 self._set_text_position(renderer) 

128 self._text.draw(renderer) 

129 self.stale = False 

130 

131 def _set_text_position(self, renderer): 

132 """Set text up so it draws in the right place. 

133 

134 Currently support 'left', 'center' and 'right' 

135 """ 

136 bbox = self.get_window_extent(renderer) 

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

138 

139 # draw in center vertically 

140 self._text.set_verticalalignment('center') 

141 y = b + (h / 2.0) 

142 

143 # now position horizontally 

144 if self._loc == 'center': 

145 self._text.set_horizontalalignment('center') 

146 x = l + (w / 2.0) 

147 elif self._loc == 'left': 

148 self._text.set_horizontalalignment('left') 

149 x = l + (w * self.PAD) 

150 else: 

151 self._text.set_horizontalalignment('right') 

152 x = l + (w * (1.0 - self.PAD)) 

153 

154 self._text.set_position((x, y)) 

155 

156 def get_text_bounds(self, renderer): 

157 """ 

158 Return the text bounds as *(x, y, width, height)* in table coordinates. 

159 """ 

160 bbox = self._text.get_window_extent(renderer) 

161 bboxa = bbox.inverse_transformed(self.get_data_transform()) 

162 return bboxa.bounds 

163 

164 def get_required_width(self, renderer): 

165 """Return the minimal required width for the cell.""" 

166 l, b, w, h = self.get_text_bounds(renderer) 

167 return w * (1.0 + (2.0 * self.PAD)) 

168 

169 @docstring.dedent_interpd 

170 def set_text_props(self, **kwargs): 

171 """ 

172 Update the text properties. 

173 

174 Valid keyword arguments are: 

175 

176 %(Text)s 

177 """ 

178 self._text.update(kwargs) 

179 self.stale = True 

180 

181 

182class CustomCell(Cell): 

183 """ 

184 A `.Cell` subclass with configurable edge visibility. 

185 """ 

186 

187 _edges = 'BRTL' 

188 _edge_aliases = {'open': '', 

189 'closed': _edges, # default 

190 'horizontal': 'BT', 

191 'vertical': 'RL' 

192 } 

193 

194 def __init__(self, *args, visible_edges, **kwargs): 

195 super().__init__(*args, **kwargs) 

196 self.visible_edges = visible_edges 

197 

198 @property 

199 def visible_edges(self): 

200 """ 

201 The cell edges to be drawn with a line. 

202 

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

204 top, left'). 

205 

206 When setting this property, you can use a substring of 'BRTL' or one 

207 of {'open', 'closed', 'horizontal', 'vertical'}. 

208 """ 

209 return self._visible_edges 

210 

211 @visible_edges.setter 

212 def visible_edges(self, value): 

213 if value is None: 

214 self._visible_edges = self._edges 

215 elif value in self._edge_aliases: 

216 self._visible_edges = self._edge_aliases[value] 

217 else: 

218 if any(edge not in self._edges for edge in value): 

219 raise ValueError('Invalid edge param {}, must only be one of ' 

220 '{} or string of {}'.format( 

221 value, 

222 ", ".join(self._edge_aliases), 

223 ", ".join(self._edges))) 

224 self._visible_edges = value 

225 self.stale = True 

226 

227 def get_path(self): 

228 """Return a `.Path` for the `.visible_edges`.""" 

229 codes = [Path.MOVETO] 

230 codes.extend( 

231 Path.LINETO if edge in self._visible_edges else Path.MOVETO 

232 for edge in self._edges) 

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

234 codes[-1] = Path.CLOSEPOLY 

235 return Path( 

236 [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]], 

237 codes, 

238 readonly=True 

239 ) 

240 

241 

242class Table(Artist): 

243 """ 

244 A table of cells. 

245 

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

247 

248 For a simple table, you'll have a full grid of cells with indices from 

249 (0, 0) to (num_rows-1, num_cols-1), in which the cell (0, 0) is positioned 

250 at the top left. However, you can also add cells with negative indices. 

251 You don't have to add a cell to every grid position, so you can create 

252 tables that have holes. 

253 

254 *Note*: You'll usually not create an empty table from scratch. Instead use 

255 `~matplotlib.table.table` to create a table from data. 

256 """ 

257 codes = {'best': 0, 

258 'upper right': 1, # default 

259 'upper left': 2, 

260 'lower left': 3, 

261 'lower right': 4, 

262 'center left': 5, 

263 'center right': 6, 

264 'lower center': 7, 

265 'upper center': 8, 

266 'center': 9, 

267 'top right': 10, 

268 'top left': 11, 

269 'bottom left': 12, 

270 'bottom right': 13, 

271 'right': 14, 

272 'left': 15, 

273 'top': 16, 

274 'bottom': 17, 

275 } 

276 """Possible values where to place the table relative to the Axes.""" 

277 

278 FONTSIZE = 10 

279 

280 AXESPAD = 0.02 

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

282 

283 def __init__(self, ax, loc=None, bbox=None, **kwargs): 

284 """ 

285 Parameters 

286 ---------- 

287 ax : `matplotlib.axes.Axes` 

288 The `~.axes.Axes` to plot the table into. 

289 loc : str 

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

291 the `~.Table.codes`. 

292 bbox : `.Bbox` or None 

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

294 overrides *loc*. 

295 

296 Other Parameters 

297 ---------------- 

298 **kwargs 

299 `.Artist` properties. 

300 """ 

301 

302 Artist.__init__(self) 

303 

304 if isinstance(loc, str): 

305 if loc not in self.codes: 

306 cbook.warn_deprecated( 

307 "3.1", message="Unrecognized location {!r}. Falling back " 

308 "on 'bottom'; valid locations are\n\t{}\n" 

309 "This will raise an exception %(removal)s." 

310 .format(loc, '\n\t'.join(self.codes))) 

311 loc = 'bottom' 

312 loc = self.codes[loc] 

313 self.set_figure(ax.figure) 

314 self._axes = ax 

315 self._loc = loc 

316 self._bbox = bbox 

317 

318 # use axes coords 

319 ax._unstale_viewLim() 

320 self.set_transform(ax.transAxes) 

321 

322 self._cells = {} 

323 self._edges = None 

324 self._autoColumns = [] 

325 self._autoFontsize = True 

326 self.update(kwargs) 

327 

328 self.set_clip_on(False) 

329 

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

331 """ 

332 Create a cell and add it to the table. 

333 

334 Parameters 

335 ---------- 

336 row : int 

337 Row index. 

338 col : int 

339 Column index. 

340 *args, **kwargs 

341 All other parameters are passed on to `Cell`. 

342 

343 Returns 

344 ------- 

345 cell : `.CustomCell` 

346 The created cell. 

347 

348 """ 

349 xy = (0, 0) 

350 cell = CustomCell(xy, visible_edges=self.edges, *args, **kwargs) 

351 self[row, col] = cell 

352 return cell 

353 

354 def __setitem__(self, position, cell): 

355 """ 

356 Set a custom cell in a given position. 

357 """ 

358 cbook._check_isinstance(CustomCell, cell=cell) 

359 try: 

360 row, col = position[0], position[1] 

361 except Exception: 

362 raise KeyError('Only tuples length 2 are accepted as coordinates') 

363 cell.set_figure(self.figure) 

364 cell.set_transform(self.get_transform()) 

365 cell.set_clip_on(False) 

366 self._cells[row, col] = cell 

367 self.stale = True 

368 

369 def __getitem__(self, position): 

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

371 return self._cells[position] 

372 

373 @property 

374 def edges(self): 

375 """ 

376 The default value of `~.CustomCell.visible_edges` for newly added 

377 cells using `.add_cell`. 

378 

379 Notes 

380 ----- 

381 This setting does currently only affect newly created cells using 

382 `.add_cell`. 

383 

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

385 

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

387 c.visible_edges = 'horizontal' 

388 

389 """ 

390 return self._edges 

391 

392 @edges.setter 

393 def edges(self, value): 

394 self._edges = value 

395 self.stale = True 

396 

397 def _approx_text_height(self): 

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

399 self._axes.bbox.height * 1.2) 

400 

401 @allow_rasterization 

402 def draw(self, renderer): 

403 # docstring inherited 

404 

405 # Need a renderer to do hit tests on mouseevent; assume the last one 

406 # will do 

407 if renderer is None: 

408 renderer = self.figure._cachedRenderer 

409 if renderer is None: 

410 raise RuntimeError('No renderer defined') 

411 

412 if not self.get_visible(): 

413 return 

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

415 self._update_positions(renderer) 

416 

417 for key in sorted(self._cells): 

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

419 

420 renderer.close_group('table') 

421 self.stale = False 

422 

423 def _get_grid_bbox(self, renderer): 

424 """ 

425 Get a bbox, in axes co-ordinates for the cells. 

426 

427 Only include those in the range (0, 0) to (maxRow, maxCol). 

428 """ 

429 boxes = [cell.get_window_extent(renderer) 

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

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

432 bbox = Bbox.union(boxes) 

433 return bbox.inverse_transformed(self.get_transform()) 

434 

435 def contains(self, mouseevent): 

436 # docstring inherited 

437 inside, info = self._default_contains(mouseevent) 

438 if inside is not None: 

439 return inside, info 

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

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

442 renderer = self.figure._cachedRenderer 

443 if renderer is not None: 

444 boxes = [cell.get_window_extent(renderer) 

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

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

447 bbox = Bbox.union(boxes) 

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

449 else: 

450 return False, {} 

451 

452 def get_children(self): 

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

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

455 

456 def get_window_extent(self, renderer): 

457 """Return the bounding box of the table in window coords.""" 

458 self._update_positions(renderer) 

459 boxes = [cell.get_window_extent(renderer) 

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

461 return Bbox.union(boxes) 

462 

463 def _do_cell_alignment(self): 

464 """ 

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

466 """ 

467 # Calculate row/column widths 

468 widths = {} 

469 heights = {} 

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

471 height = heights.setdefault(row, 0.0) 

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

473 width = widths.setdefault(col, 0.0) 

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

475 

476 # work out left position for each column 

477 xpos = 0 

478 lefts = {} 

479 for col in sorted(widths): 

480 lefts[col] = xpos 

481 xpos += widths[col] 

482 

483 ypos = 0 

484 bottoms = {} 

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

486 bottoms[row] = ypos 

487 ypos += heights[row] 

488 

489 # set cell positions 

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

491 cell.set_x(lefts[col]) 

492 cell.set_y(bottoms[row]) 

493 

494 def auto_set_column_width(self, col): 

495 """ 

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

497 

498 Parameters 

499 ---------- 

500 col : int or sequence of ints 

501 The indices of the columns to auto-scale. 

502 """ 

503 # check for col possibility on iteration 

504 try: 

505 iter(col) 

506 except (TypeError, AttributeError): 

507 self._autoColumns.append(col) 

508 else: 

509 for cell in col: 

510 self._autoColumns.append(cell) 

511 

512 self.stale = True 

513 

514 def _auto_set_column_width(self, col, renderer): 

515 """Automatically set width for column.""" 

516 cells = [cell for key, cell in self._cells.items() if key[1] == col] 

517 max_width = max((cell.get_required_width(renderer) for cell in cells), 

518 default=0) 

519 for cell in cells: 

520 cell.set_width(max_width) 

521 

522 def auto_set_font_size(self, value=True): 

523 """Automatically set font size.""" 

524 self._autoFontsize = value 

525 self.stale = True 

526 

527 def _auto_set_font_size(self, renderer): 

528 

529 if len(self._cells) == 0: 

530 return 

531 fontsize = next(iter(self._cells.values())).get_fontsize() 

532 cells = [] 

533 for key, cell in self._cells.items(): 

534 # ignore auto-sized columns 

535 if key[1] in self._autoColumns: 

536 continue 

537 size = cell.auto_set_font_size(renderer) 

538 fontsize = min(fontsize, size) 

539 cells.append(cell) 

540 

541 # now set all fontsizes equal 

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

543 cell.set_fontsize(fontsize) 

544 

545 def scale(self, xscale, yscale): 

546 """Scale column widths by *xscale* and row heights by *yscale*.""" 

547 for c in self._cells.values(): 

548 c.set_width(c.get_width() * xscale) 

549 c.set_height(c.get_height() * yscale) 

550 

551 def set_fontsize(self, size): 

552 """ 

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

554 

555 Parameters 

556 ---------- 

557 size : float 

558 

559 Notes 

560 ----- 

561 As long as auto font size has not been disabled, the value will be 

562 clipped such that the text fits horizontally into the cell. 

563 

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

565 

566 >>> the_table.auto_set_font_size(False) 

567 >>> the_table.set_fontsize(20) 

568 

569 However, there is no automatic scaling of the row height so that the 

570 text may exceed the cell boundary. 

571 """ 

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

573 cell.set_fontsize(size) 

574 self.stale = True 

575 

576 def _offset(self, ox, oy): 

577 """Move all the artists by ox, oy (axes coords).""" 

578 for c in self._cells.values(): 

579 x, y = c.get_x(), c.get_y() 

580 c.set_x(x + ox) 

581 c.set_y(y + oy) 

582 

583 def _update_positions(self, renderer): 

584 # called from renderer to allow more precise estimates of 

585 # widths and heights with get_window_extent 

586 

587 # Do any auto width setting 

588 for col in self._autoColumns: 

589 self._auto_set_column_width(col, renderer) 

590 

591 if self._autoFontsize: 

592 self._auto_set_font_size(renderer) 

593 

594 # Align all the cells 

595 self._do_cell_alignment() 

596 

597 bbox = self._get_grid_bbox(renderer) 

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

599 

600 if self._bbox is not None: 

601 # Position according to bbox 

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

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

604 ox = rl - l 

605 oy = rb - b 

606 self._do_cell_alignment() 

607 else: 

608 # Position using loc 

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

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

611 # defaults for center 

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

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

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

615 ox = self.AXESPAD - l 

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

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

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

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

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

621 oy = self.AXESPAD - b 

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

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

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

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

626 

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

628 ox = - (l + w) 

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

630 ox = 1.0 - l 

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

632 oy = 1.0 - b 

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

634 oy = - (b + h) 

635 

636 self._offset(ox, oy) 

637 

638 def get_celld(self): 

639 r""" 

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

641 `.Cell`\s. 

642 

643 Notes 

644 ----- 

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

646 cells:: 

647 

648 cell = table[row, col] 

649 

650 """ 

651 return self._cells 

652 

653 

654docstring.interpd.update(Table=artist.kwdoc(Table)) 

655 

656 

657@docstring.dedent_interpd 

658def table(ax, 

659 cellText=None, cellColours=None, 

660 cellLoc='right', colWidths=None, 

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

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

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

664 **kwargs): 

665 """ 

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

667 

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

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

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

671 same number of elements. 

672 

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

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

675 *colLoc* respectively. 

676 

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

678 the axes with `.Axes.add_table`. 

679 

680 Parameters 

681 ---------- 

682 cellText : 2D list of str, optional 

683 The texts to place into the table cells. 

684 

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

686 will result in the text exceeding the cell boundaries. 

687 

688 cellColours : 2D list of colors, optional 

689 The background colors of the cells. 

690 

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

692 The alignment of the text within the cells. 

693 

694 colWidths : list of float, optional 

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

696 have a width of *1 / ncols*. 

697 

698 rowLabels : list of str, optional 

699 The text of the row header cells. 

700 

701 rowColours : list of colors, optional 

702 The colors of the row header cells. 

703 

704 rowLoc : {'left', 'center', 'right'}, optional, default: 'left' 

705 The text alignment of the row header cells. 

706 

707 colLabels : list of str, optional 

708 The text of the column header cells. 

709 

710 colColours : list of colors, optional 

711 The colors of the column header cells. 

712 

713 colLoc : {'left', 'center', 'right'}, optional, default: 'left' 

714 The text alignment of the column header cells. 

715 

716 loc : str, optional 

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

718 the `~.Table.codes`. 

719 

720 bbox : `.Bbox`, optional 

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

722 overrides *loc*. 

723 

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

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

726 `~.CustomCell.visible_edges`. 

727 

728 Other Parameters 

729 ---------------- 

730 **kwargs 

731 `.Table` properties. 

732 

733 %(Table)s 

734 

735 Returns 

736 ------- 

737 table : `~matplotlib.table.Table` 

738 The created table. 

739 """ 

740 

741 if cellColours is None and cellText is None: 

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

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

744 

745 # Check we have some cellText 

746 if cellText is None: 

747 # assume just colours are needed 

748 rows = len(cellColours) 

749 cols = len(cellColours[0]) 

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

751 

752 rows = len(cellText) 

753 cols = len(cellText[0]) 

754 for row in cellText: 

755 if len(row) != cols: 

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

757 .format(cols)) 

758 

759 if cellColours is not None: 

760 if len(cellColours) != rows: 

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

762 for row in cellColours: 

763 if len(row) != cols: 

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

765 "columns".format(cols)) 

766 else: 

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

768 

769 # Set colwidths if not given 

770 if colWidths is None: 

771 colWidths = [1.0 / cols] * cols 

772 

773 # Fill in missing information for column 

774 # and row labels 

775 rowLabelWidth = 0 

776 if rowLabels is None: 

777 if rowColours is not None: 

778 rowLabels = [''] * rows 

779 rowLabelWidth = colWidths[0] 

780 elif rowColours is None: 

781 rowColours = 'w' * rows 

782 

783 if rowLabels is not None: 

784 if len(rowLabels) != rows: 

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

786 

787 # If we have column labels, need to shift 

788 # the text and colour arrays down 1 row 

789 offset = 1 

790 if colLabels is None: 

791 if colColours is not None: 

792 colLabels = [''] * cols 

793 else: 

794 offset = 0 

795 elif colColours is None: 

796 colColours = 'w' * cols 

797 

798 # Set up cell colours if not given 

799 if cellColours is None: 

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

801 

802 # Now create the table 

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

804 table.edges = edges 

805 height = table._approx_text_height() 

806 

807 # Add the cells 

808 for row in range(rows): 

809 for col in range(cols): 

810 table.add_cell(row + offset, col, 

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

812 text=cellText[row][col], 

813 facecolor=cellColours[row][col], 

814 loc=cellLoc) 

815 # Do column labels 

816 if colLabels is not None: 

817 for col in range(cols): 

818 table.add_cell(0, col, 

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

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

821 loc=colLoc) 

822 

823 # Do row labels 

824 if rowLabels is not None: 

825 for row in range(rows): 

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

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

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

829 loc=rowLoc) 

830 if rowLabelWidth == 0: 

831 table.auto_set_column_width(-1) 

832 

833 ax.add_table(table) 

834 return table