Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/matplotlib/markers.py: 23%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

414 statements  

1r""" 

2Functions to handle markers; used by the marker functionality of 

3`~matplotlib.axes.Axes.plot`, `~matplotlib.axes.Axes.scatter`, and 

4`~matplotlib.axes.Axes.errorbar`. 

5 

6All possible markers are defined here: 

7 

8============================== ====== ========================================= 

9marker symbol description 

10============================== ====== ========================================= 

11``"."`` |m00| point 

12``","`` |m01| pixel 

13``"o"`` |m02| circle 

14``"v"`` |m03| triangle_down 

15``"^"`` |m04| triangle_up 

16``"<"`` |m05| triangle_left 

17``">"`` |m06| triangle_right 

18``"1"`` |m07| tri_down 

19``"2"`` |m08| tri_up 

20``"3"`` |m09| tri_left 

21``"4"`` |m10| tri_right 

22``"8"`` |m11| octagon 

23``"s"`` |m12| square 

24``"p"`` |m13| pentagon 

25``"P"`` |m23| plus (filled) 

26``"*"`` |m14| star 

27``"h"`` |m15| hexagon1 

28``"H"`` |m16| hexagon2 

29``"+"`` |m17| plus 

30``"x"`` |m18| x 

31``"X"`` |m24| x (filled) 

32``"D"`` |m19| diamond 

33``"d"`` |m20| thin_diamond 

34``"|"`` |m21| vline 

35``"_"`` |m22| hline 

36``0`` (``TICKLEFT``) |m25| tickleft 

37``1`` (``TICKRIGHT``) |m26| tickright 

38``2`` (``TICKUP``) |m27| tickup 

39``3`` (``TICKDOWN``) |m28| tickdown 

40``4`` (``CARETLEFT``) |m29| caretleft 

41``5`` (``CARETRIGHT``) |m30| caretright 

42``6`` (``CARETUP``) |m31| caretup 

43``7`` (``CARETDOWN``) |m32| caretdown 

44``8`` (``CARETLEFTBASE``) |m33| caretleft (centered at base) 

45``9`` (``CARETRIGHTBASE``) |m34| caretright (centered at base) 

46``10`` (``CARETUPBASE``) |m35| caretup (centered at base) 

47``11`` (``CARETDOWNBASE``) |m36| caretdown (centered at base) 

48``"none"`` or ``"None"`` nothing 

49``" "`` or ``""`` nothing 

50``"$...$"`` |m37| Render the string using mathtext. 

51 E.g ``"$f$"`` for marker showing the 

52 letter ``f``. 

53``verts`` A list of (x, y) pairs used for Path 

54 vertices. The center of the marker is 

55 located at (0, 0) and the size is 

56 normalized, such that the created path 

57 is encapsulated inside the unit cell. 

58``path`` A `~matplotlib.path.Path` instance. 

59``(numsides, 0, angle)`` A regular polygon with ``numsides`` 

60 sides, rotated by ``angle``. 

61``(numsides, 1, angle)`` A star-like symbol with ``numsides`` 

62 sides, rotated by ``angle``. 

63``(numsides, 2, angle)`` An asterisk with ``numsides`` sides, 

64 rotated by ``angle``. 

65============================== ====== ========================================= 

66 

67Note that special symbols can be defined via the 

68:ref:`STIX math font <mathtext>`, 

69e.g. ``"$\u266B$"``. For an overview over the STIX font symbols refer to the 

70`STIX font table <http://www.stixfonts.org/allGlyphs.html>`_. 

71Also see the :doc:`/gallery/text_labels_and_annotations/stix_fonts_demo`. 

72 

73Integer numbers from ``0`` to ``11`` create lines and triangles. Those are 

74equally accessible via capitalized variables, like ``CARETDOWNBASE``. 

75Hence the following are equivalent:: 

76 

77 plt.plot([1, 2, 3], marker=11) 

78 plt.plot([1, 2, 3], marker=matplotlib.markers.CARETDOWNBASE) 

79 

80Markers join and cap styles can be customized by creating a new instance of 

81MarkerStyle. 

82A MarkerStyle can also have a custom `~matplotlib.transforms.Transform` 

83allowing it to be arbitrarily rotated or offset. 

84 

85Examples showing the use of markers: 

86 

87* :doc:`/gallery/lines_bars_and_markers/marker_reference` 

88* :doc:`/gallery/lines_bars_and_markers/scatter_star_poly` 

89* :doc:`/gallery/lines_bars_and_markers/multivariate_marker_plot` 

90 

91.. |m00| image:: /_static/markers/m00.png 

92.. |m01| image:: /_static/markers/m01.png 

93.. |m02| image:: /_static/markers/m02.png 

94.. |m03| image:: /_static/markers/m03.png 

95.. |m04| image:: /_static/markers/m04.png 

96.. |m05| image:: /_static/markers/m05.png 

97.. |m06| image:: /_static/markers/m06.png 

98.. |m07| image:: /_static/markers/m07.png 

99.. |m08| image:: /_static/markers/m08.png 

100.. |m09| image:: /_static/markers/m09.png 

101.. |m10| image:: /_static/markers/m10.png 

102.. |m11| image:: /_static/markers/m11.png 

103.. |m12| image:: /_static/markers/m12.png 

104.. |m13| image:: /_static/markers/m13.png 

105.. |m14| image:: /_static/markers/m14.png 

106.. |m15| image:: /_static/markers/m15.png 

107.. |m16| image:: /_static/markers/m16.png 

108.. |m17| image:: /_static/markers/m17.png 

109.. |m18| image:: /_static/markers/m18.png 

110.. |m19| image:: /_static/markers/m19.png 

111.. |m20| image:: /_static/markers/m20.png 

112.. |m21| image:: /_static/markers/m21.png 

113.. |m22| image:: /_static/markers/m22.png 

114.. |m23| image:: /_static/markers/m23.png 

115.. |m24| image:: /_static/markers/m24.png 

116.. |m25| image:: /_static/markers/m25.png 

117.. |m26| image:: /_static/markers/m26.png 

118.. |m27| image:: /_static/markers/m27.png 

119.. |m28| image:: /_static/markers/m28.png 

120.. |m29| image:: /_static/markers/m29.png 

121.. |m30| image:: /_static/markers/m30.png 

122.. |m31| image:: /_static/markers/m31.png 

123.. |m32| image:: /_static/markers/m32.png 

124.. |m33| image:: /_static/markers/m33.png 

125.. |m34| image:: /_static/markers/m34.png 

126.. |m35| image:: /_static/markers/m35.png 

127.. |m36| image:: /_static/markers/m36.png 

128.. |m37| image:: /_static/markers/m37.png 

129""" 

130import copy 

131 

132from collections.abc import Sized 

133 

134import numpy as np 

135 

136import matplotlib as mpl 

137from . import _api, cbook 

138from .path import Path 

139from .transforms import IdentityTransform, Affine2D 

140from ._enums import JoinStyle, CapStyle 

141 

142# special-purpose marker identifiers: 

143(TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN, 

144 CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN, 

145 CARETLEFTBASE, CARETRIGHTBASE, CARETUPBASE, CARETDOWNBASE) = range(12) 

146 

147_empty_path = Path(np.empty((0, 2))) 

148 

149 

150class MarkerStyle: 

151 """ 

152 A class representing marker types. 

153 

154 Instances are immutable. If you need to change anything, create a new 

155 instance. 

156 

157 Attributes 

158 ---------- 

159 markers : dict 

160 All known markers. 

161 filled_markers : tuple 

162 All known filled markers. This is a subset of *markers*. 

163 fillstyles : tuple 

164 The supported fillstyles. 

165 """ 

166 

167 markers = { 

168 '.': 'point', 

169 ',': 'pixel', 

170 'o': 'circle', 

171 'v': 'triangle_down', 

172 '^': 'triangle_up', 

173 '<': 'triangle_left', 

174 '>': 'triangle_right', 

175 '1': 'tri_down', 

176 '2': 'tri_up', 

177 '3': 'tri_left', 

178 '4': 'tri_right', 

179 '8': 'octagon', 

180 's': 'square', 

181 'p': 'pentagon', 

182 '*': 'star', 

183 'h': 'hexagon1', 

184 'H': 'hexagon2', 

185 '+': 'plus', 

186 'x': 'x', 

187 'D': 'diamond', 

188 'd': 'thin_diamond', 

189 '|': 'vline', 

190 '_': 'hline', 

191 'P': 'plus_filled', 

192 'X': 'x_filled', 

193 TICKLEFT: 'tickleft', 

194 TICKRIGHT: 'tickright', 

195 TICKUP: 'tickup', 

196 TICKDOWN: 'tickdown', 

197 CARETLEFT: 'caretleft', 

198 CARETRIGHT: 'caretright', 

199 CARETUP: 'caretup', 

200 CARETDOWN: 'caretdown', 

201 CARETLEFTBASE: 'caretleftbase', 

202 CARETRIGHTBASE: 'caretrightbase', 

203 CARETUPBASE: 'caretupbase', 

204 CARETDOWNBASE: 'caretdownbase', 

205 "None": 'nothing', 

206 "none": 'nothing', 

207 ' ': 'nothing', 

208 '': 'nothing' 

209 } 

210 

211 # Just used for informational purposes. is_filled() 

212 # is calculated in the _set_* functions. 

213 filled_markers = ( 

214 '.', 'o', 'v', '^', '<', '>', '8', 's', 'p', '*', 'h', 'H', 'D', 'd', 

215 'P', 'X') 

216 

217 fillstyles = ('full', 'left', 'right', 'bottom', 'top', 'none') 

218 _half_fillstyles = ('left', 'right', 'bottom', 'top') 

219 

220 def __init__(self, marker, 

221 fillstyle=None, transform=None, capstyle=None, joinstyle=None): 

222 """ 

223 Parameters 

224 ---------- 

225 marker : str, array-like, Path, MarkerStyle 

226 - Another instance of `MarkerStyle` copies the details of that *marker*. 

227 - For other possible marker values, see the module docstring 

228 `matplotlib.markers`. 

229 

230 fillstyle : str, default: :rc:`markers.fillstyle` 

231 One of 'full', 'left', 'right', 'bottom', 'top', 'none'. 

232 

233 transform : `~matplotlib.transforms.Transform`, optional 

234 Transform that will be combined with the native transform of the 

235 marker. 

236 

237 capstyle : `.CapStyle` or %(CapStyle)s, optional 

238 Cap style that will override the default cap style of the marker. 

239 

240 joinstyle : `.JoinStyle` or %(JoinStyle)s, optional 

241 Join style that will override the default join style of the marker. 

242 """ 

243 self._marker_function = None 

244 self._user_transform = transform 

245 self._user_capstyle = CapStyle(capstyle) if capstyle is not None else None 

246 self._user_joinstyle = JoinStyle(joinstyle) if joinstyle is not None else None 

247 self._set_fillstyle(fillstyle) 

248 self._set_marker(marker) 

249 

250 def _recache(self): 

251 if self._marker_function is None: 

252 return 

253 self._path = _empty_path 

254 self._transform = IdentityTransform() 

255 self._alt_path = None 

256 self._alt_transform = None 

257 self._snap_threshold = None 

258 self._joinstyle = JoinStyle.round 

259 self._capstyle = self._user_capstyle or CapStyle.butt 

260 # Initial guess: Assume the marker is filled unless the fillstyle is 

261 # set to 'none'. The marker function will override this for unfilled 

262 # markers. 

263 self._filled = self._fillstyle != 'none' 

264 self._marker_function() 

265 

266 def __bool__(self): 

267 return bool(len(self._path.vertices)) 

268 

269 def is_filled(self): 

270 return self._filled 

271 

272 def get_fillstyle(self): 

273 return self._fillstyle 

274 

275 def _set_fillstyle(self, fillstyle): 

276 """ 

277 Set the fillstyle. 

278 

279 Parameters 

280 ---------- 

281 fillstyle : {'full', 'left', 'right', 'bottom', 'top', 'none'} 

282 The part of the marker surface that is colored with 

283 markerfacecolor. 

284 """ 

285 if fillstyle is None: 

286 fillstyle = mpl.rcParams['markers.fillstyle'] 

287 _api.check_in_list(self.fillstyles, fillstyle=fillstyle) 

288 self._fillstyle = fillstyle 

289 

290 def get_joinstyle(self): 

291 return self._joinstyle.name 

292 

293 def get_capstyle(self): 

294 return self._capstyle.name 

295 

296 def get_marker(self): 

297 return self._marker 

298 

299 def _set_marker(self, marker): 

300 """ 

301 Set the marker. 

302 

303 Parameters 

304 ---------- 

305 marker : str, array-like, Path, MarkerStyle 

306 - Another instance of `MarkerStyle` copies the details of that *marker*. 

307 - For other possible marker values see the module docstring 

308 `matplotlib.markers`. 

309 """ 

310 if isinstance(marker, str) and cbook.is_math_text(marker): 

311 self._marker_function = self._set_mathtext_path 

312 elif isinstance(marker, (int, str)) and marker in self.markers: 

313 self._marker_function = getattr(self, '_set_' + self.markers[marker]) 

314 elif (isinstance(marker, np.ndarray) and marker.ndim == 2 and 

315 marker.shape[1] == 2): 

316 self._marker_function = self._set_vertices 

317 elif isinstance(marker, Path): 

318 self._marker_function = self._set_path_marker 

319 elif (isinstance(marker, Sized) and len(marker) in (2, 3) and 

320 marker[1] in (0, 1, 2)): 

321 self._marker_function = self._set_tuple_marker 

322 elif isinstance(marker, MarkerStyle): 

323 self.__dict__ = copy.deepcopy(marker.__dict__) 

324 else: 

325 try: 

326 Path(marker) 

327 self._marker_function = self._set_vertices 

328 except ValueError as err: 

329 raise ValueError( 

330 f'Unrecognized marker style {marker!r}') from err 

331 

332 if not isinstance(marker, MarkerStyle): 

333 self._marker = marker 

334 self._recache() 

335 

336 def get_path(self): 

337 """ 

338 Return a `.Path` for the primary part of the marker. 

339 

340 For unfilled markers this is the whole marker, for filled markers, 

341 this is the area to be drawn with *markerfacecolor*. 

342 """ 

343 return self._path 

344 

345 def get_transform(self): 

346 """ 

347 Return the transform to be applied to the `.Path` from 

348 `MarkerStyle.get_path()`. 

349 """ 

350 if self._user_transform is None: 

351 return self._transform.frozen() 

352 else: 

353 return (self._transform + self._user_transform).frozen() 

354 

355 def get_alt_path(self): 

356 """ 

357 Return a `.Path` for the alternate part of the marker. 

358 

359 For unfilled markers, this is *None*; for filled markers, this is the 

360 area to be drawn with *markerfacecoloralt*. 

361 """ 

362 return self._alt_path 

363 

364 def get_alt_transform(self): 

365 """ 

366 Return the transform to be applied to the `.Path` from 

367 `MarkerStyle.get_alt_path()`. 

368 """ 

369 if self._user_transform is None: 

370 return self._alt_transform.frozen() 

371 else: 

372 return (self._alt_transform + self._user_transform).frozen() 

373 

374 def get_snap_threshold(self): 

375 return self._snap_threshold 

376 

377 def get_user_transform(self): 

378 """Return user supplied part of marker transform.""" 

379 if self._user_transform is not None: 

380 return self._user_transform.frozen() 

381 

382 def transformed(self, transform): 

383 """ 

384 Return a new version of this marker with the transform applied. 

385 

386 Parameters 

387 ---------- 

388 transform : `~matplotlib.transforms.Affine2D` 

389 Transform will be combined with current user supplied transform. 

390 """ 

391 new_marker = MarkerStyle(self) 

392 if new_marker._user_transform is not None: 

393 new_marker._user_transform += transform 

394 else: 

395 new_marker._user_transform = transform 

396 return new_marker 

397 

398 def rotated(self, *, deg=None, rad=None): 

399 """ 

400 Return a new version of this marker rotated by specified angle. 

401 

402 Parameters 

403 ---------- 

404 deg : float, optional 

405 Rotation angle in degrees. 

406 

407 rad : float, optional 

408 Rotation angle in radians. 

409 

410 .. note:: You must specify exactly one of deg or rad. 

411 """ 

412 if deg is None and rad is None: 

413 raise ValueError('One of deg or rad is required') 

414 if deg is not None and rad is not None: 

415 raise ValueError('Only one of deg and rad can be supplied') 

416 new_marker = MarkerStyle(self) 

417 if new_marker._user_transform is None: 

418 new_marker._user_transform = Affine2D() 

419 

420 if deg is not None: 

421 new_marker._user_transform.rotate_deg(deg) 

422 if rad is not None: 

423 new_marker._user_transform.rotate(rad) 

424 

425 return new_marker 

426 

427 def scaled(self, sx, sy=None): 

428 """ 

429 Return new marker scaled by specified scale factors. 

430 

431 If *sy* is not given, the same scale is applied in both the *x*- and 

432 *y*-directions. 

433 

434 Parameters 

435 ---------- 

436 sx : float 

437 *X*-direction scaling factor. 

438 sy : float, optional 

439 *Y*-direction scaling factor. 

440 """ 

441 if sy is None: 

442 sy = sx 

443 

444 new_marker = MarkerStyle(self) 

445 _transform = new_marker._user_transform or Affine2D() 

446 new_marker._user_transform = _transform.scale(sx, sy) 

447 return new_marker 

448 

449 def _set_nothing(self): 

450 self._filled = False 

451 

452 def _set_custom_marker(self, path): 

453 rescale = np.max(np.abs(path.vertices)) # max of x's and y's. 

454 self._transform = Affine2D().scale(0.5 / rescale) 

455 self._path = path 

456 

457 def _set_path_marker(self): 

458 self._set_custom_marker(self._marker) 

459 

460 def _set_vertices(self): 

461 self._set_custom_marker(Path(self._marker)) 

462 

463 def _set_tuple_marker(self): 

464 marker = self._marker 

465 if len(marker) == 2: 

466 numsides, rotation = marker[0], 0.0 

467 elif len(marker) == 3: 

468 numsides, rotation = marker[0], marker[2] 

469 symstyle = marker[1] 

470 if symstyle == 0: 

471 self._path = Path.unit_regular_polygon(numsides) 

472 self._joinstyle = self._user_joinstyle or JoinStyle.miter 

473 elif symstyle == 1: 

474 self._path = Path.unit_regular_star(numsides) 

475 self._joinstyle = self._user_joinstyle or JoinStyle.bevel 

476 elif symstyle == 2: 

477 self._path = Path.unit_regular_asterisk(numsides) 

478 self._filled = False 

479 self._joinstyle = self._user_joinstyle or JoinStyle.bevel 

480 else: 

481 raise ValueError(f"Unexpected tuple marker: {marker}") 

482 self._transform = Affine2D().scale(0.5).rotate_deg(rotation) 

483 

484 def _set_mathtext_path(self): 

485 """ 

486 Draw mathtext markers '$...$' using `.TextPath` object. 

487 

488 Submitted by tcb 

489 """ 

490 from matplotlib.text import TextPath 

491 

492 # again, the properties could be initialised just once outside 

493 # this function 

494 text = TextPath(xy=(0, 0), s=self.get_marker(), 

495 usetex=mpl.rcParams['text.usetex']) 

496 if len(text.vertices) == 0: 

497 return 

498 

499 bbox = text.get_extents() 

500 max_dim = max(bbox.width, bbox.height) 

501 self._transform = ( 

502 Affine2D() 

503 .translate(-bbox.xmin + 0.5 * -bbox.width, -bbox.ymin + 0.5 * -bbox.height) 

504 .scale(1.0 / max_dim)) 

505 self._path = text 

506 self._snap = False 

507 

508 def _half_fill(self): 

509 return self.get_fillstyle() in self._half_fillstyles 

510 

511 def _set_circle(self, size=1.0): 

512 self._transform = Affine2D().scale(0.5 * size) 

513 self._snap_threshold = np.inf 

514 if not self._half_fill(): 

515 self._path = Path.unit_circle() 

516 else: 

517 self._path = self._alt_path = Path.unit_circle_righthalf() 

518 fs = self.get_fillstyle() 

519 self._transform.rotate_deg( 

520 {'right': 0, 'top': 90, 'left': 180, 'bottom': 270}[fs]) 

521 self._alt_transform = self._transform.frozen().rotate_deg(180.) 

522 

523 def _set_point(self): 

524 self._set_circle(size=0.5) 

525 

526 def _set_pixel(self): 

527 self._path = Path.unit_rectangle() 

528 # Ideally, you'd want -0.5, -0.5 here, but then the snapping 

529 # algorithm in the Agg backend will round this to a 2x2 

530 # rectangle from (-1, -1) to (1, 1). By offsetting it 

531 # slightly, we can force it to be (0, 0) to (1, 1), which both 

532 # makes it only be a single pixel and places it correctly 

533 # aligned to 1-width stroking (i.e. the ticks). This hack is 

534 # the best of a number of bad alternatives, mainly because the 

535 # backends are not aware of what marker is actually being used 

536 # beyond just its path data. 

537 self._transform = Affine2D().translate(-0.49999, -0.49999) 

538 self._snap_threshold = None 

539 

540 _triangle_path = Path._create_closed([[0, 1], [-1, -1], [1, -1]]) 

541 # Going down halfway looks to small. Golden ratio is too far. 

542 _triangle_path_u = Path._create_closed([[0, 1], [-3/5, -1/5], [3/5, -1/5]]) 

543 _triangle_path_d = Path._create_closed( 

544 [[-3/5, -1/5], [3/5, -1/5], [1, -1], [-1, -1]]) 

545 _triangle_path_l = Path._create_closed([[0, 1], [0, -1], [-1, -1]]) 

546 _triangle_path_r = Path._create_closed([[0, 1], [0, -1], [1, -1]]) 

547 

548 def _set_triangle(self, rot, skip): 

549 self._transform = Affine2D().scale(0.5).rotate_deg(rot) 

550 self._snap_threshold = 5.0 

551 

552 if not self._half_fill(): 

553 self._path = self._triangle_path 

554 else: 

555 mpaths = [self._triangle_path_u, 

556 self._triangle_path_l, 

557 self._triangle_path_d, 

558 self._triangle_path_r] 

559 

560 fs = self.get_fillstyle() 

561 if fs == 'top': 

562 self._path = mpaths[(0 + skip) % 4] 

563 self._alt_path = mpaths[(2 + skip) % 4] 

564 elif fs == 'bottom': 

565 self._path = mpaths[(2 + skip) % 4] 

566 self._alt_path = mpaths[(0 + skip) % 4] 

567 elif fs == 'left': 

568 self._path = mpaths[(1 + skip) % 4] 

569 self._alt_path = mpaths[(3 + skip) % 4] 

570 else: 

571 self._path = mpaths[(3 + skip) % 4] 

572 self._alt_path = mpaths[(1 + skip) % 4] 

573 

574 self._alt_transform = self._transform 

575 

576 self._joinstyle = self._user_joinstyle or JoinStyle.miter 

577 

578 def _set_triangle_up(self): 

579 return self._set_triangle(0.0, 0) 

580 

581 def _set_triangle_down(self): 

582 return self._set_triangle(180.0, 2) 

583 

584 def _set_triangle_left(self): 

585 return self._set_triangle(90.0, 3) 

586 

587 def _set_triangle_right(self): 

588 return self._set_triangle(270.0, 1) 

589 

590 def _set_square(self): 

591 self._transform = Affine2D().translate(-0.5, -0.5) 

592 self._snap_threshold = 2.0 

593 if not self._half_fill(): 

594 self._path = Path.unit_rectangle() 

595 else: 

596 # Build a bottom filled square out of two rectangles, one filled. 

597 self._path = Path([[0.0, 0.0], [1.0, 0.0], [1.0, 0.5], 

598 [0.0, 0.5], [0.0, 0.0]]) 

599 self._alt_path = Path([[0.0, 0.5], [1.0, 0.5], [1.0, 1.0], 

600 [0.0, 1.0], [0.0, 0.5]]) 

601 fs = self.get_fillstyle() 

602 rotate = {'bottom': 0, 'right': 90, 'top': 180, 'left': 270}[fs] 

603 self._transform.rotate_deg(rotate) 

604 self._alt_transform = self._transform 

605 

606 self._joinstyle = self._user_joinstyle or JoinStyle.miter 

607 

608 def _set_diamond(self): 

609 self._transform = Affine2D().translate(-0.5, -0.5).rotate_deg(45) 

610 self._snap_threshold = 5.0 

611 if not self._half_fill(): 

612 self._path = Path.unit_rectangle() 

613 else: 

614 self._path = Path([[0, 0], [1, 0], [1, 1], [0, 0]]) 

615 self._alt_path = Path([[0, 0], [0, 1], [1, 1], [0, 0]]) 

616 fs = self.get_fillstyle() 

617 rotate = {'right': 0, 'top': 90, 'left': 180, 'bottom': 270}[fs] 

618 self._transform.rotate_deg(rotate) 

619 self._alt_transform = self._transform 

620 self._joinstyle = self._user_joinstyle or JoinStyle.miter 

621 

622 def _set_thin_diamond(self): 

623 self._set_diamond() 

624 self._transform.scale(0.6, 1.0) 

625 

626 def _set_pentagon(self): 

627 self._transform = Affine2D().scale(0.5) 

628 self._snap_threshold = 5.0 

629 

630 polypath = Path.unit_regular_polygon(5) 

631 

632 if not self._half_fill(): 

633 self._path = polypath 

634 else: 

635 verts = polypath.vertices 

636 y = (1 + np.sqrt(5)) / 4. 

637 top = Path(verts[[0, 1, 4, 0]]) 

638 bottom = Path(verts[[1, 2, 3, 4, 1]]) 

639 left = Path([verts[0], verts[1], verts[2], [0, -y], verts[0]]) 

640 right = Path([verts[0], verts[4], verts[3], [0, -y], verts[0]]) 

641 self._path, self._alt_path = { 

642 'top': (top, bottom), 'bottom': (bottom, top), 

643 'left': (left, right), 'right': (right, left), 

644 }[self.get_fillstyle()] 

645 self._alt_transform = self._transform 

646 

647 self._joinstyle = self._user_joinstyle or JoinStyle.miter 

648 

649 def _set_star(self): 

650 self._transform = Affine2D().scale(0.5) 

651 self._snap_threshold = 5.0 

652 

653 polypath = Path.unit_regular_star(5, innerCircle=0.381966) 

654 

655 if not self._half_fill(): 

656 self._path = polypath 

657 else: 

658 verts = polypath.vertices 

659 top = Path(np.concatenate([verts[0:4], verts[7:10], verts[0:1]])) 

660 bottom = Path(np.concatenate([verts[3:8], verts[3:4]])) 

661 left = Path(np.concatenate([verts[0:6], verts[0:1]])) 

662 right = Path(np.concatenate([verts[0:1], verts[5:10], verts[0:1]])) 

663 self._path, self._alt_path = { 

664 'top': (top, bottom), 'bottom': (bottom, top), 

665 'left': (left, right), 'right': (right, left), 

666 }[self.get_fillstyle()] 

667 self._alt_transform = self._transform 

668 

669 self._joinstyle = self._user_joinstyle or JoinStyle.bevel 

670 

671 def _set_hexagon1(self): 

672 self._transform = Affine2D().scale(0.5) 

673 self._snap_threshold = None 

674 

675 polypath = Path.unit_regular_polygon(6) 

676 

677 if not self._half_fill(): 

678 self._path = polypath 

679 else: 

680 verts = polypath.vertices 

681 # not drawing inside lines 

682 x = np.abs(np.cos(5 * np.pi / 6.)) 

683 top = Path(np.concatenate([[(-x, 0)], verts[[1, 0, 5]], [(x, 0)]])) 

684 bottom = Path(np.concatenate([[(-x, 0)], verts[2:5], [(x, 0)]])) 

685 left = Path(verts[0:4]) 

686 right = Path(verts[[0, 5, 4, 3]]) 

687 self._path, self._alt_path = { 

688 'top': (top, bottom), 'bottom': (bottom, top), 

689 'left': (left, right), 'right': (right, left), 

690 }[self.get_fillstyle()] 

691 self._alt_transform = self._transform 

692 

693 self._joinstyle = self._user_joinstyle or JoinStyle.miter 

694 

695 def _set_hexagon2(self): 

696 self._transform = Affine2D().scale(0.5).rotate_deg(30) 

697 self._snap_threshold = None 

698 

699 polypath = Path.unit_regular_polygon(6) 

700 

701 if not self._half_fill(): 

702 self._path = polypath 

703 else: 

704 verts = polypath.vertices 

705 # not drawing inside lines 

706 x, y = np.sqrt(3) / 4, 3 / 4. 

707 top = Path(verts[[1, 0, 5, 4, 1]]) 

708 bottom = Path(verts[1:5]) 

709 left = Path(np.concatenate([ 

710 [(x, y)], verts[:3], [(-x, -y), (x, y)]])) 

711 right = Path(np.concatenate([ 

712 [(x, y)], verts[5:2:-1], [(-x, -y)]])) 

713 self._path, self._alt_path = { 

714 'top': (top, bottom), 'bottom': (bottom, top), 

715 'left': (left, right), 'right': (right, left), 

716 }[self.get_fillstyle()] 

717 self._alt_transform = self._transform 

718 

719 self._joinstyle = self._user_joinstyle or JoinStyle.miter 

720 

721 def _set_octagon(self): 

722 self._transform = Affine2D().scale(0.5) 

723 self._snap_threshold = 5.0 

724 

725 polypath = Path.unit_regular_polygon(8) 

726 

727 if not self._half_fill(): 

728 self._transform.rotate_deg(22.5) 

729 self._path = polypath 

730 else: 

731 x = np.sqrt(2.) / 4. 

732 self._path = self._alt_path = Path( 

733 [[0, -1], [0, 1], [-x, 1], [-1, x], 

734 [-1, -x], [-x, -1], [0, -1]]) 

735 fs = self.get_fillstyle() 

736 self._transform.rotate_deg( 

737 {'left': 0, 'bottom': 90, 'right': 180, 'top': 270}[fs]) 

738 self._alt_transform = self._transform.frozen().rotate_deg(180.0) 

739 

740 self._joinstyle = self._user_joinstyle or JoinStyle.miter 

741 

742 _line_marker_path = Path([[0.0, -1.0], [0.0, 1.0]]) 

743 

744 def _set_vline(self): 

745 self._transform = Affine2D().scale(0.5) 

746 self._snap_threshold = 1.0 

747 self._filled = False 

748 self._path = self._line_marker_path 

749 

750 def _set_hline(self): 

751 self._set_vline() 

752 self._transform = self._transform.rotate_deg(90) 

753 

754 _tickhoriz_path = Path([[0.0, 0.0], [1.0, 0.0]]) 

755 

756 def _set_tickleft(self): 

757 self._transform = Affine2D().scale(-1.0, 1.0) 

758 self._snap_threshold = 1.0 

759 self._filled = False 

760 self._path = self._tickhoriz_path 

761 

762 def _set_tickright(self): 

763 self._transform = Affine2D().scale(1.0, 1.0) 

764 self._snap_threshold = 1.0 

765 self._filled = False 

766 self._path = self._tickhoriz_path 

767 

768 _tickvert_path = Path([[-0.0, 0.0], [-0.0, 1.0]]) 

769 

770 def _set_tickup(self): 

771 self._transform = Affine2D().scale(1.0, 1.0) 

772 self._snap_threshold = 1.0 

773 self._filled = False 

774 self._path = self._tickvert_path 

775 

776 def _set_tickdown(self): 

777 self._transform = Affine2D().scale(1.0, -1.0) 

778 self._snap_threshold = 1.0 

779 self._filled = False 

780 self._path = self._tickvert_path 

781 

782 _tri_path = Path([[0.0, 0.0], [0.0, -1.0], 

783 [0.0, 0.0], [0.8, 0.5], 

784 [0.0, 0.0], [-0.8, 0.5]], 

785 [Path.MOVETO, Path.LINETO, 

786 Path.MOVETO, Path.LINETO, 

787 Path.MOVETO, Path.LINETO]) 

788 

789 def _set_tri_down(self): 

790 self._transform = Affine2D().scale(0.5) 

791 self._snap_threshold = 5.0 

792 self._filled = False 

793 self._path = self._tri_path 

794 

795 def _set_tri_up(self): 

796 self._set_tri_down() 

797 self._transform = self._transform.rotate_deg(180) 

798 

799 def _set_tri_left(self): 

800 self._set_tri_down() 

801 self._transform = self._transform.rotate_deg(270) 

802 

803 def _set_tri_right(self): 

804 self._set_tri_down() 

805 self._transform = self._transform.rotate_deg(90) 

806 

807 _caret_path = Path([[-1.0, 1.5], [0.0, 0.0], [1.0, 1.5]]) 

808 

809 def _set_caretdown(self): 

810 self._transform = Affine2D().scale(0.5) 

811 self._snap_threshold = 3.0 

812 self._filled = False 

813 self._path = self._caret_path 

814 self._joinstyle = self._user_joinstyle or JoinStyle.miter 

815 

816 def _set_caretup(self): 

817 self._set_caretdown() 

818 self._transform = self._transform.rotate_deg(180) 

819 

820 def _set_caretleft(self): 

821 self._set_caretdown() 

822 self._transform = self._transform.rotate_deg(270) 

823 

824 def _set_caretright(self): 

825 self._set_caretdown() 

826 self._transform = self._transform.rotate_deg(90) 

827 

828 _caret_path_base = Path([[-1.0, 0.0], [0.0, -1.5], [1.0, 0]]) 

829 

830 def _set_caretdownbase(self): 

831 self._set_caretdown() 

832 self._path = self._caret_path_base 

833 

834 def _set_caretupbase(self): 

835 self._set_caretdownbase() 

836 self._transform = self._transform.rotate_deg(180) 

837 

838 def _set_caretleftbase(self): 

839 self._set_caretdownbase() 

840 self._transform = self._transform.rotate_deg(270) 

841 

842 def _set_caretrightbase(self): 

843 self._set_caretdownbase() 

844 self._transform = self._transform.rotate_deg(90) 

845 

846 _plus_path = Path([[-1.0, 0.0], [1.0, 0.0], 

847 [0.0, -1.0], [0.0, 1.0]], 

848 [Path.MOVETO, Path.LINETO, 

849 Path.MOVETO, Path.LINETO]) 

850 

851 def _set_plus(self): 

852 self._transform = Affine2D().scale(0.5) 

853 self._snap_threshold = 1.0 

854 self._filled = False 

855 self._path = self._plus_path 

856 

857 _x_path = Path([[-1.0, -1.0], [1.0, 1.0], 

858 [-1.0, 1.0], [1.0, -1.0]], 

859 [Path.MOVETO, Path.LINETO, 

860 Path.MOVETO, Path.LINETO]) 

861 

862 def _set_x(self): 

863 self._transform = Affine2D().scale(0.5) 

864 self._snap_threshold = 3.0 

865 self._filled = False 

866 self._path = self._x_path 

867 

868 _plus_filled_path = Path._create_closed(np.array([ 

869 (-1, -3), (+1, -3), (+1, -1), (+3, -1), (+3, +1), (+1, +1), 

870 (+1, +3), (-1, +3), (-1, +1), (-3, +1), (-3, -1), (-1, -1)]) / 6) 

871 _plus_filled_path_t = Path._create_closed(np.array([ 

872 (+3, 0), (+3, +1), (+1, +1), (+1, +3), 

873 (-1, +3), (-1, +1), (-3, +1), (-3, 0)]) / 6) 

874 

875 def _set_plus_filled(self): 

876 self._transform = Affine2D() 

877 self._snap_threshold = 5.0 

878 self._joinstyle = self._user_joinstyle or JoinStyle.miter 

879 if not self._half_fill(): 

880 self._path = self._plus_filled_path 

881 else: 

882 # Rotate top half path to support all partitions 

883 self._path = self._alt_path = self._plus_filled_path_t 

884 fs = self.get_fillstyle() 

885 self._transform.rotate_deg( 

886 {'top': 0, 'left': 90, 'bottom': 180, 'right': 270}[fs]) 

887 self._alt_transform = self._transform.frozen().rotate_deg(180) 

888 

889 _x_filled_path = Path._create_closed(np.array([ 

890 (-1, -2), (0, -1), (+1, -2), (+2, -1), (+1, 0), (+2, +1), 

891 (+1, +2), (0, +1), (-1, +2), (-2, +1), (-1, 0), (-2, -1)]) / 4) 

892 _x_filled_path_t = Path._create_closed(np.array([ 

893 (+1, 0), (+2, +1), (+1, +2), (0, +1), 

894 (-1, +2), (-2, +1), (-1, 0)]) / 4) 

895 

896 def _set_x_filled(self): 

897 self._transform = Affine2D() 

898 self._snap_threshold = 5.0 

899 self._joinstyle = self._user_joinstyle or JoinStyle.miter 

900 if not self._half_fill(): 

901 self._path = self._x_filled_path 

902 else: 

903 # Rotate top half path to support all partitions 

904 self._path = self._alt_path = self._x_filled_path_t 

905 fs = self.get_fillstyle() 

906 self._transform.rotate_deg( 

907 {'top': 0, 'left': 90, 'bottom': 180, 'right': 270}[fs]) 

908 self._alt_transform = self._transform.frozen().rotate_deg(180)