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

2This module defines default legend handlers. 

3 

4It is strongly encouraged to have read the :doc:`legend guide 

5</tutorials/intermediate/legend_guide>` before this documentation. 

6 

7Legend handlers are expected to be a callable object with a following 

8signature. :: 

9 

10 legend_handler(legend, orig_handle, fontsize, handlebox) 

11 

12Where *legend* is the legend itself, *orig_handle* is the original 

13plot, *fontsize* is the fontsize in pixels, and *handlebox* is a 

14OffsetBox instance. Within the call, you should create relevant 

15artists (using relevant properties from the *legend* and/or 

16*orig_handle*) and add them into the handlebox. The artists needs to 

17be scaled according to the fontsize (note that the size is in pixel, 

18i.e., this is dpi-scaled value). 

19 

20This module includes definition of several legend handler classes 

21derived from the base class (HandlerBase) with the following method:: 

22 

23 def legend_artist(self, legend, orig_handle, fontsize, handlebox) 

24 

25""" 

26 

27from itertools import cycle 

28 

29import numpy as np 

30 

31from matplotlib.lines import Line2D 

32from matplotlib.patches import Rectangle 

33import matplotlib.collections as mcoll 

34import matplotlib.colors as mcolors 

35 

36 

37def update_from_first_child(tgt, src): 

38 first_child = next(iter(src.get_children()), None) 

39 if first_child is not None: 

40 tgt.update_from(first_child) 

41 

42 

43class HandlerBase: 

44 """ 

45 A Base class for default legend handlers. 

46 

47 The derived classes are meant to override *create_artists* method, which 

48 has a following signature.:: 

49 

50 def create_artists(self, legend, orig_handle, 

51 xdescent, ydescent, width, height, fontsize, 

52 trans): 

53 

54 The overridden method needs to create artists of the given 

55 transform that fits in the given dimension (xdescent, ydescent, 

56 width, height) that are scaled by fontsize if necessary. 

57 

58 """ 

59 def __init__(self, xpad=0., ypad=0., update_func=None): 

60 self._xpad, self._ypad = xpad, ypad 

61 self._update_prop_func = update_func 

62 

63 def _update_prop(self, legend_handle, orig_handle): 

64 if self._update_prop_func is None: 

65 self._default_update_prop(legend_handle, orig_handle) 

66 else: 

67 self._update_prop_func(legend_handle, orig_handle) 

68 

69 def _default_update_prop(self, legend_handle, orig_handle): 

70 legend_handle.update_from(orig_handle) 

71 

72 def update_prop(self, legend_handle, orig_handle, legend): 

73 

74 self._update_prop(legend_handle, orig_handle) 

75 

76 legend._set_artist_props(legend_handle) 

77 legend_handle.set_clip_box(None) 

78 legend_handle.set_clip_path(None) 

79 

80 def adjust_drawing_area(self, legend, orig_handle, 

81 xdescent, ydescent, width, height, fontsize, 

82 ): 

83 xdescent = xdescent - self._xpad * fontsize 

84 ydescent = ydescent - self._ypad * fontsize 

85 width = width - self._xpad * fontsize 

86 height = height - self._ypad * fontsize 

87 return xdescent, ydescent, width, height 

88 

89 def legend_artist(self, legend, orig_handle, 

90 fontsize, handlebox): 

91 """ 

92 Return the artist that this HandlerBase generates for the given 

93 original artist/handle. 

94 

95 Parameters 

96 ---------- 

97 legend : :class:`matplotlib.legend.Legend` instance 

98 The legend for which these legend artists are being created. 

99 orig_handle : :class:`matplotlib.artist.Artist` or similar 

100 The object for which these legend artists are being created. 

101 fontsize : float or int 

102 The fontsize in pixels. The artists being created should 

103 be scaled according to the given fontsize. 

104 handlebox : :class:`matplotlib.offsetbox.OffsetBox` instance 

105 The box which has been created to hold this legend entry's 

106 artists. Artists created in the `legend_artist` method must 

107 be added to this handlebox inside this method. 

108 

109 """ 

110 xdescent, ydescent, width, height = self.adjust_drawing_area( 

111 legend, orig_handle, 

112 handlebox.xdescent, handlebox.ydescent, 

113 handlebox.width, handlebox.height, 

114 fontsize) 

115 artists = self.create_artists(legend, orig_handle, 

116 xdescent, ydescent, width, height, 

117 fontsize, handlebox.get_transform()) 

118 

119 # create_artists will return a list of artists. 

120 for a in artists: 

121 handlebox.add_artist(a) 

122 

123 # we only return the first artist 

124 return artists[0] 

125 

126 def create_artists(self, legend, orig_handle, 

127 xdescent, ydescent, width, height, fontsize, 

128 trans): 

129 raise NotImplementedError('Derived must override') 

130 

131 

132class HandlerNpoints(HandlerBase): 

133 """ 

134 A legend handler that shows *numpoints* points in the legend entry. 

135 """ 

136 def __init__(self, marker_pad=0.3, numpoints=None, **kw): 

137 """ 

138 Parameters 

139 ---------- 

140 marker_pad : float 

141 Padding between points in legend entry. 

142 

143 numpoints : int 

144 Number of points to show in legend entry. 

145 

146 Notes 

147 ----- 

148 Any other keyword arguments are given to `HandlerBase`. 

149 """ 

150 HandlerBase.__init__(self, **kw) 

151 

152 self._numpoints = numpoints 

153 self._marker_pad = marker_pad 

154 

155 def get_numpoints(self, legend): 

156 if self._numpoints is None: 

157 return legend.numpoints 

158 else: 

159 return self._numpoints 

160 

161 def get_xdata(self, legend, xdescent, ydescent, width, height, fontsize): 

162 numpoints = self.get_numpoints(legend) 

163 if numpoints > 1: 

164 # we put some pad here to compensate the size of the marker 

165 pad = self._marker_pad * fontsize 

166 xdata = np.linspace(-xdescent + pad, 

167 -xdescent + width - pad, 

168 numpoints) 

169 xdata_marker = xdata 

170 else: 

171 xdata = [-xdescent, -xdescent + width] 

172 xdata_marker = [-xdescent + 0.5 * width] 

173 return xdata, xdata_marker 

174 

175 

176class HandlerNpointsYoffsets(HandlerNpoints): 

177 """ 

178 A legend handler that shows *numpoints* in the legend, and allows them to 

179 be individually offest in the y-direction. 

180 """ 

181 def __init__(self, numpoints=None, yoffsets=None, **kw): 

182 """ 

183 Parameters 

184 ---------- 

185 numpoints : int 

186 Number of points to show in legend entry. 

187 

188 yoffsets : array of floats 

189 Length *numpoints* list of y offsets for each point in 

190 legend entry. 

191 

192 Notes 

193 ----- 

194 Any other keyword arguments are given to `HandlerNpoints`. 

195 """ 

196 HandlerNpoints.__init__(self, numpoints=numpoints, **kw) 

197 self._yoffsets = yoffsets 

198 

199 def get_ydata(self, legend, xdescent, ydescent, width, height, fontsize): 

200 if self._yoffsets is None: 

201 ydata = height * legend._scatteryoffsets 

202 else: 

203 ydata = height * np.asarray(self._yoffsets) 

204 

205 return ydata 

206 

207 

208class HandlerLine2D(HandlerNpoints): 

209 """ 

210 Handler for `.Line2D` instances. 

211 """ 

212 def __init__(self, marker_pad=0.3, numpoints=None, **kw): 

213 """ 

214 Parameters 

215 ---------- 

216 marker_pad : float 

217 Padding between points in legend entry. 

218 

219 numpoints : int 

220 Number of points to show in legend entry. 

221 

222 Notes 

223 ----- 

224 Any other keyword arguments are given to `HandlerNpoints`. 

225 """ 

226 HandlerNpoints.__init__(self, marker_pad=marker_pad, 

227 numpoints=numpoints, **kw) 

228 

229 def create_artists(self, legend, orig_handle, 

230 xdescent, ydescent, width, height, fontsize, 

231 trans): 

232 

233 xdata, xdata_marker = self.get_xdata(legend, xdescent, ydescent, 

234 width, height, fontsize) 

235 

236 ydata = np.full_like(xdata, ((height - ydescent) / 2)) 

237 legline = Line2D(xdata, ydata) 

238 

239 self.update_prop(legline, orig_handle, legend) 

240 legline.set_drawstyle('default') 

241 legline.set_marker("") 

242 

243 legline_marker = Line2D(xdata_marker, ydata[:len(xdata_marker)]) 

244 self.update_prop(legline_marker, orig_handle, legend) 

245 legline_marker.set_linestyle('None') 

246 if legend.markerscale != 1: 

247 newsz = legline_marker.get_markersize() * legend.markerscale 

248 legline_marker.set_markersize(newsz) 

249 # we don't want to add this to the return list because 

250 # the texts and handles are assumed to be in one-to-one 

251 # correspondence. 

252 legline._legmarker = legline_marker 

253 

254 legline.set_transform(trans) 

255 legline_marker.set_transform(trans) 

256 

257 return [legline, legline_marker] 

258 

259 

260class HandlerPatch(HandlerBase): 

261 """ 

262 Handler for `.Patch` instances. 

263 """ 

264 def __init__(self, patch_func=None, **kw): 

265 """ 

266 Parameters 

267 ---------- 

268 patch_func : callable, optional 

269 The function that creates the legend key artist. 

270 *patch_func* should have the signature:: 

271 

272 def patch_func(legend=legend, orig_handle=orig_handle, 

273 xdescent=xdescent, ydescent=ydescent, 

274 width=width, height=height, fontsize=fontsize) 

275 

276 Subsequently the created artist will have its ``update_prop`` 

277 method called and the appropriate transform will be applied. 

278 

279 Notes 

280 ----- 

281 Any other keyword arguments are given to `HandlerBase`. 

282 """ 

283 HandlerBase.__init__(self, **kw) 

284 self._patch_func = patch_func 

285 

286 def _create_patch(self, legend, orig_handle, 

287 xdescent, ydescent, width, height, fontsize): 

288 if self._patch_func is None: 

289 p = Rectangle(xy=(-xdescent, -ydescent), 

290 width=width, height=height) 

291 else: 

292 p = self._patch_func(legend=legend, orig_handle=orig_handle, 

293 xdescent=xdescent, ydescent=ydescent, 

294 width=width, height=height, fontsize=fontsize) 

295 return p 

296 

297 def create_artists(self, legend, orig_handle, 

298 xdescent, ydescent, width, height, fontsize, trans): 

299 p = self._create_patch(legend, orig_handle, 

300 xdescent, ydescent, width, height, fontsize) 

301 self.update_prop(p, orig_handle, legend) 

302 p.set_transform(trans) 

303 return [p] 

304 

305 

306class HandlerLineCollection(HandlerLine2D): 

307 """ 

308 Handler for `.LineCollection` instances. 

309 """ 

310 def get_numpoints(self, legend): 

311 if self._numpoints is None: 

312 return legend.scatterpoints 

313 else: 

314 return self._numpoints 

315 

316 def _default_update_prop(self, legend_handle, orig_handle): 

317 lw = orig_handle.get_linewidths()[0] 

318 dashes = orig_handle._us_linestyles[0] 

319 color = orig_handle.get_colors()[0] 

320 legend_handle.set_color(color) 

321 legend_handle.set_linestyle(dashes) 

322 legend_handle.set_linewidth(lw) 

323 

324 def create_artists(self, legend, orig_handle, 

325 xdescent, ydescent, width, height, fontsize, trans): 

326 

327 xdata, xdata_marker = self.get_xdata(legend, xdescent, ydescent, 

328 width, height, fontsize) 

329 ydata = np.full_like(xdata, (height - ydescent) / 2) 

330 legline = Line2D(xdata, ydata) 

331 

332 self.update_prop(legline, orig_handle, legend) 

333 legline.set_transform(trans) 

334 

335 return [legline] 

336 

337 

338class HandlerRegularPolyCollection(HandlerNpointsYoffsets): 

339 """ 

340 Handler for `.RegularPolyCollections`. 

341 """ 

342 def __init__(self, yoffsets=None, sizes=None, **kw): 

343 HandlerNpointsYoffsets.__init__(self, yoffsets=yoffsets, **kw) 

344 

345 self._sizes = sizes 

346 

347 def get_numpoints(self, legend): 

348 if self._numpoints is None: 

349 return legend.scatterpoints 

350 else: 

351 return self._numpoints 

352 

353 def get_sizes(self, legend, orig_handle, 

354 xdescent, ydescent, width, height, fontsize): 

355 if self._sizes is None: 

356 handle_sizes = orig_handle.get_sizes() 

357 if not len(handle_sizes): 

358 handle_sizes = [1] 

359 size_max = max(handle_sizes) * legend.markerscale ** 2 

360 size_min = min(handle_sizes) * legend.markerscale ** 2 

361 

362 numpoints = self.get_numpoints(legend) 

363 if numpoints < 4: 

364 sizes = [.5 * (size_max + size_min), size_max, 

365 size_min][:numpoints] 

366 else: 

367 rng = (size_max - size_min) 

368 sizes = rng * np.linspace(0, 1, numpoints) + size_min 

369 else: 

370 sizes = self._sizes 

371 

372 return sizes 

373 

374 def update_prop(self, legend_handle, orig_handle, legend): 

375 

376 self._update_prop(legend_handle, orig_handle) 

377 

378 legend_handle.set_figure(legend.figure) 

379 # legend._set_artist_props(legend_handle) 

380 legend_handle.set_clip_box(None) 

381 legend_handle.set_clip_path(None) 

382 

383 def create_collection(self, orig_handle, sizes, offsets, transOffset): 

384 p = type(orig_handle)(orig_handle.get_numsides(), 

385 rotation=orig_handle.get_rotation(), 

386 sizes=sizes, 

387 offsets=offsets, 

388 transOffset=transOffset, 

389 ) 

390 return p 

391 

392 def create_artists(self, legend, orig_handle, 

393 xdescent, ydescent, width, height, fontsize, 

394 trans): 

395 xdata, xdata_marker = self.get_xdata(legend, xdescent, ydescent, 

396 width, height, fontsize) 

397 

398 ydata = self.get_ydata(legend, xdescent, ydescent, 

399 width, height, fontsize) 

400 

401 sizes = self.get_sizes(legend, orig_handle, xdescent, ydescent, 

402 width, height, fontsize) 

403 

404 p = self.create_collection(orig_handle, sizes, 

405 offsets=list(zip(xdata_marker, ydata)), 

406 transOffset=trans) 

407 

408 self.update_prop(p, orig_handle, legend) 

409 p._transOffset = trans 

410 return [p] 

411 

412 

413class HandlerPathCollection(HandlerRegularPolyCollection): 

414 """ 

415 Handler for `.PathCollections`, which are used by `~.Axes.scatter`. 

416 """ 

417 def create_collection(self, orig_handle, sizes, offsets, transOffset): 

418 p = type(orig_handle)([orig_handle.get_paths()[0]], 

419 sizes=sizes, 

420 offsets=offsets, 

421 transOffset=transOffset, 

422 ) 

423 return p 

424 

425 

426class HandlerCircleCollection(HandlerRegularPolyCollection): 

427 """ 

428 Handler for `.CircleCollections`. 

429 """ 

430 def create_collection(self, orig_handle, sizes, offsets, transOffset): 

431 p = type(orig_handle)(sizes, 

432 offsets=offsets, 

433 transOffset=transOffset, 

434 ) 

435 return p 

436 

437 

438class HandlerErrorbar(HandlerLine2D): 

439 """ 

440 Handler for Errorbars. 

441 """ 

442 def __init__(self, xerr_size=0.5, yerr_size=None, 

443 marker_pad=0.3, numpoints=None, **kw): 

444 

445 self._xerr_size = xerr_size 

446 self._yerr_size = yerr_size 

447 

448 HandlerLine2D.__init__(self, marker_pad=marker_pad, 

449 numpoints=numpoints, **kw) 

450 

451 def get_err_size(self, legend, xdescent, ydescent, 

452 width, height, fontsize): 

453 xerr_size = self._xerr_size * fontsize 

454 

455 if self._yerr_size is None: 

456 yerr_size = xerr_size 

457 else: 

458 yerr_size = self._yerr_size * fontsize 

459 

460 return xerr_size, yerr_size 

461 

462 def create_artists(self, legend, orig_handle, 

463 xdescent, ydescent, width, height, fontsize, 

464 trans): 

465 

466 plotlines, caplines, barlinecols = orig_handle 

467 

468 xdata, xdata_marker = self.get_xdata(legend, xdescent, ydescent, 

469 width, height, fontsize) 

470 

471 ydata = np.full_like(xdata, (height - ydescent) / 2) 

472 legline = Line2D(xdata, ydata) 

473 

474 xdata_marker = np.asarray(xdata_marker) 

475 ydata_marker = np.asarray(ydata[:len(xdata_marker)]) 

476 

477 xerr_size, yerr_size = self.get_err_size(legend, xdescent, ydescent, 

478 width, height, fontsize) 

479 

480 legline_marker = Line2D(xdata_marker, ydata_marker) 

481 

482 # when plotlines are None (only errorbars are drawn), we just 

483 # make legline invisible. 

484 if plotlines is None: 

485 legline.set_visible(False) 

486 legline_marker.set_visible(False) 

487 else: 

488 self.update_prop(legline, plotlines, legend) 

489 

490 legline.set_drawstyle('default') 

491 legline.set_marker('None') 

492 

493 self.update_prop(legline_marker, plotlines, legend) 

494 legline_marker.set_linestyle('None') 

495 

496 if legend.markerscale != 1: 

497 newsz = legline_marker.get_markersize() * legend.markerscale 

498 legline_marker.set_markersize(newsz) 

499 

500 handle_barlinecols = [] 

501 handle_caplines = [] 

502 

503 if orig_handle.has_xerr: 

504 verts = [((x - xerr_size, y), (x + xerr_size, y)) 

505 for x, y in zip(xdata_marker, ydata_marker)] 

506 coll = mcoll.LineCollection(verts) 

507 self.update_prop(coll, barlinecols[0], legend) 

508 handle_barlinecols.append(coll) 

509 

510 if caplines: 

511 capline_left = Line2D(xdata_marker - xerr_size, ydata_marker) 

512 capline_right = Line2D(xdata_marker + xerr_size, ydata_marker) 

513 self.update_prop(capline_left, caplines[0], legend) 

514 self.update_prop(capline_right, caplines[0], legend) 

515 capline_left.set_marker("|") 

516 capline_right.set_marker("|") 

517 

518 handle_caplines.append(capline_left) 

519 handle_caplines.append(capline_right) 

520 

521 if orig_handle.has_yerr: 

522 verts = [((x, y - yerr_size), (x, y + yerr_size)) 

523 for x, y in zip(xdata_marker, ydata_marker)] 

524 coll = mcoll.LineCollection(verts) 

525 self.update_prop(coll, barlinecols[0], legend) 

526 handle_barlinecols.append(coll) 

527 

528 if caplines: 

529 capline_left = Line2D(xdata_marker, ydata_marker - yerr_size) 

530 capline_right = Line2D(xdata_marker, ydata_marker + yerr_size) 

531 self.update_prop(capline_left, caplines[0], legend) 

532 self.update_prop(capline_right, caplines[0], legend) 

533 capline_left.set_marker("_") 

534 capline_right.set_marker("_") 

535 

536 handle_caplines.append(capline_left) 

537 handle_caplines.append(capline_right) 

538 

539 artists = [ 

540 *handle_barlinecols, *handle_caplines, legline, legline_marker, 

541 ] 

542 for artist in artists: 

543 artist.set_transform(trans) 

544 return artists 

545 

546 

547class HandlerStem(HandlerNpointsYoffsets): 

548 """ 

549 Handler for plots produced by `~.Axes.stem`. 

550 """ 

551 def __init__(self, marker_pad=0.3, numpoints=None, 

552 bottom=None, yoffsets=None, **kw): 

553 """ 

554 Parameters 

555 ---------- 

556 marker_pad : float 

557 Padding between points in legend entry. Default is 0.3. 

558 

559 numpoints : int, optional 

560 Number of points to show in legend entry. 

561 

562 bottom : float, optional 

563 

564 yoffsets : array of floats, optional 

565 Length *numpoints* list of y offsets for each point in 

566 legend entry. 

567 

568 Notes 

569 ----- 

570 Any other keyword arguments are given to `HandlerNpointsYoffsets`. 

571 """ 

572 

573 HandlerNpointsYoffsets.__init__(self, marker_pad=marker_pad, 

574 numpoints=numpoints, 

575 yoffsets=yoffsets, 

576 **kw) 

577 self._bottom = bottom 

578 

579 def get_ydata(self, legend, xdescent, ydescent, width, height, fontsize): 

580 if self._yoffsets is None: 

581 ydata = height * (0.5 * legend._scatteryoffsets + 0.5) 

582 else: 

583 ydata = height * np.asarray(self._yoffsets) 

584 

585 return ydata 

586 

587 def create_artists(self, legend, orig_handle, 

588 xdescent, ydescent, width, height, fontsize, 

589 trans): 

590 markerline, stemlines, baseline = orig_handle 

591 # Check to see if the stemcontainer is storing lines as a list or a 

592 # LineCollection. Eventually using a list will be removed, and this 

593 # logic can also be removed. 

594 using_linecoll = isinstance(stemlines, mcoll.LineCollection) 

595 

596 xdata, xdata_marker = self.get_xdata(legend, xdescent, ydescent, 

597 width, height, fontsize) 

598 

599 ydata = self.get_ydata(legend, xdescent, ydescent, 

600 width, height, fontsize) 

601 

602 if self._bottom is None: 

603 bottom = 0. 

604 else: 

605 bottom = self._bottom 

606 

607 leg_markerline = Line2D(xdata_marker, ydata[:len(xdata_marker)]) 

608 self.update_prop(leg_markerline, markerline, legend) 

609 

610 leg_stemlines = [Line2D([x, x], [bottom, y]) 

611 for x, y in zip(xdata_marker, ydata)] 

612 

613 if using_linecoll: 

614 # change the function used by update_prop() from the default 

615 # to one that handles LineCollection 

616 orig_update_func = self._update_prop_func 

617 self._update_prop_func = self._copy_collection_props 

618 

619 for line in leg_stemlines: 

620 self.update_prop(line, stemlines, legend) 

621 

622 else: 

623 for lm, m in zip(leg_stemlines, stemlines): 

624 self.update_prop(lm, m, legend) 

625 

626 if using_linecoll: 

627 self._update_prop_func = orig_update_func 

628 

629 leg_baseline = Line2D([np.min(xdata), np.max(xdata)], 

630 [bottom, bottom]) 

631 self.update_prop(leg_baseline, baseline, legend) 

632 

633 artists = [*leg_stemlines, leg_baseline, leg_markerline] 

634 for artist in artists: 

635 artist.set_transform(trans) 

636 return artists 

637 

638 def _copy_collection_props(self, legend_handle, orig_handle): 

639 """ 

640 Method to copy properties from a LineCollection (orig_handle) to a 

641 Line2D (legend_handle). 

642 """ 

643 legend_handle.set_color(orig_handle.get_color()[0]) 

644 legend_handle.set_linestyle(orig_handle.get_linestyle()[0]) 

645 

646 

647class HandlerTuple(HandlerBase): 

648 """ 

649 Handler for Tuple. 

650 

651 Additional kwargs are passed through to `HandlerBase`. 

652 

653 Parameters 

654 ---------- 

655 ndivide : int, optional 

656 The number of sections to divide the legend area into. If None, 

657 use the length of the input tuple. Default is 1. 

658 

659 

660 pad : float, optional 

661 If None, fall back to ``legend.borderpad`` as the default. 

662 In units of fraction of font size. Default is None. 

663 """ 

664 def __init__(self, ndivide=1, pad=None, **kwargs): 

665 

666 self._ndivide = ndivide 

667 self._pad = pad 

668 HandlerBase.__init__(self, **kwargs) 

669 

670 def create_artists(self, legend, orig_handle, 

671 xdescent, ydescent, width, height, fontsize, 

672 trans): 

673 

674 handler_map = legend.get_legend_handler_map() 

675 

676 if self._ndivide is None: 

677 ndivide = len(orig_handle) 

678 else: 

679 ndivide = self._ndivide 

680 

681 if self._pad is None: 

682 pad = legend.borderpad * fontsize 

683 else: 

684 pad = self._pad * fontsize 

685 

686 if ndivide > 1: 

687 width = (width - pad * (ndivide - 1)) / ndivide 

688 

689 xds_cycle = cycle(xdescent - (width + pad) * np.arange(ndivide)) 

690 

691 a_list = [] 

692 for handle1 in orig_handle: 

693 handler = legend.get_legend_handler(handler_map, handle1) 

694 _a_list = handler.create_artists( 

695 legend, handle1, 

696 next(xds_cycle), ydescent, width, height, fontsize, trans) 

697 a_list.extend(_a_list) 

698 

699 return a_list 

700 

701 

702class HandlerPolyCollection(HandlerBase): 

703 """ 

704 Handler for `.PolyCollection` used in `~.Axes.fill_between` and 

705 `~.Axes.stackplot`. 

706 """ 

707 def _update_prop(self, legend_handle, orig_handle): 

708 def first_color(colors): 

709 if colors is None: 

710 return None 

711 colors = mcolors.to_rgba_array(colors) 

712 if len(colors): 

713 return colors[0] 

714 else: 

715 return "none" 

716 

717 def get_first(prop_array): 

718 if len(prop_array): 

719 return prop_array[0] 

720 else: 

721 return None 

722 edgecolor = getattr(orig_handle, '_original_edgecolor', 

723 orig_handle.get_edgecolor()) 

724 legend_handle.set_edgecolor(first_color(edgecolor)) 

725 facecolor = getattr(orig_handle, '_original_facecolor', 

726 orig_handle.get_facecolor()) 

727 legend_handle.set_facecolor(first_color(facecolor)) 

728 legend_handle.set_fill(orig_handle.get_fill()) 

729 legend_handle.set_hatch(orig_handle.get_hatch()) 

730 legend_handle.set_linewidth(get_first(orig_handle.get_linewidths())) 

731 legend_handle.set_linestyle(get_first(orig_handle.get_linestyles())) 

732 legend_handle.set_transform(get_first(orig_handle.get_transforms())) 

733 legend_handle.set_figure(orig_handle.get_figure()) 

734 legend_handle.set_alpha(orig_handle.get_alpha()) 

735 

736 def create_artists(self, legend, orig_handle, 

737 xdescent, ydescent, width, height, fontsize, trans): 

738 p = Rectangle(xy=(-xdescent, -ydescent), 

739 width=width, height=height) 

740 self.update_prop(p, orig_handle, legend) 

741 p.set_transform(trans) 

742 return [p]