|
24 | 24 | import matplotlib.colors as mcolors
|
25 | 25 | import matplotlib.docstring as docstring
|
26 | 26 | import matplotlib.scale as mscale
|
| 27 | +import matplotlib.transforms as mtransforms |
27 | 28 | from matplotlib.axes import Axes, rcParams
|
28 | 29 | from matplotlib.axes._base import _axis_method_wrapper
|
29 | 30 | from matplotlib.transforms import Bbox
|
@@ -99,6 +100,7 @@ def __init__(
|
99 | 100 | self._shared_z_axes.join(self, sharez)
|
100 | 101 | self._adjustable = 'datalim'
|
101 | 102 |
|
| 103 | + kwargs.setdefault('aspect', 'auto_pb') |
102 | 104 | super().__init__(fig, rect, frameon=True, *args, **kwargs)
|
103 | 105 | # Disable drawing of axes by base class
|
104 | 106 | super().set_axis_off()
|
@@ -261,10 +263,99 @@ def tunit_edges(self, vals=None, M=None):
|
261 | 263 | (tc[7], tc[4])]
|
262 | 264 | return edges
|
263 | 265 |
|
| 266 | + def set_aspect(self, aspect, adjustable=None, anchor=None, share=False): |
| 267 | + """ |
| 268 | + Set the aspect of the axis scaling. |
| 269 | +
|
| 270 | + Parameters |
| 271 | + ---------- |
| 272 | + aspect : {'auto_pb', 'auto'} |
| 273 | + Possible values: |
| 274 | +
|
| 275 | + ======== ================================================= |
| 276 | + value description |
| 277 | + ======== ================================================= |
| 278 | + 'auto_pb' This will make the size of the axes have a fixed |
| 279 | + ratio |
| 280 | + 'auto' automatic; fill the position rectangle with data. |
| 281 | + This will let the ratio between the size of the |
| 282 | + (pseudo-) bounding box be free and will not adjust |
| 283 | + anything at draw time. |
| 284 | + ======== ================================================= |
| 285 | +
|
| 286 | + adjustable : None or {'box', 'datalim'}, optional |
| 287 | + If not ``None``, this defines which parameter will be adjusted to |
| 288 | + meet the required aspect. See `.set_adjustable` for further |
| 289 | + details. |
| 290 | +
|
| 291 | + Currently ignored by Axes3D |
| 292 | +
|
| 293 | + anchor : None or str or 2-tuple of float, optional |
| 294 | + If not ``None``, this defines where the Axes will be drawn if there |
| 295 | + is extra space due to aspect constraints. The most common way to |
| 296 | + to specify the anchor are abbreviations of cardinal directions: |
| 297 | +
|
| 298 | + ===== ===================== |
| 299 | + value description |
| 300 | + ===== ===================== |
| 301 | + 'C' centered |
| 302 | + 'SW' lower left corner |
| 303 | + 'S' middle of bottom edge |
| 304 | + 'SE' lower right corner |
| 305 | + etc. |
| 306 | + ===== ===================== |
| 307 | +
|
| 308 | + See `.set_anchor` for further details. |
| 309 | +
|
| 310 | + share : bool, default: False |
| 311 | + If ``True``, apply the settings to all shared Axes. |
| 312 | +
|
| 313 | + """ |
| 314 | + if aspect not in {'auto', 'auto_pb'}: |
| 315 | + raise NotImplementedError( |
| 316 | + "Axes3D currently only support the aspect arguments " |
| 317 | + "{'auto', 'auto_pb'}. " + f"You passed in {aspect!r}." |
| 318 | + ) |
| 319 | + |
| 320 | + if share: |
| 321 | + axes = {*self._shared_x_axes.get_siblings(self), |
| 322 | + *self._shared_y_axes.get_siblings(self), |
| 323 | + *self._shared_z_axes.get_siblings(self), |
| 324 | + } |
| 325 | + else: |
| 326 | + axes = {self} |
| 327 | + |
| 328 | + for ax in axes: |
| 329 | + ax._aspect = aspect |
| 330 | + ax.stale = True |
| 331 | + |
| 332 | + if anchor is not None: |
| 333 | + self.set_anchor(anchor, share=share) |
| 334 | + |
| 335 | + def set_anchor(self, anchor, share=False): |
| 336 | + # docstring inherited |
| 337 | + if not (anchor in mtransforms.Bbox.coefs or len(anchor) == 2): |
| 338 | + raise ValueError('argument must be among %s' % |
| 339 | + ', '.join(mtransforms.Bbox.coefs)) |
| 340 | + if share: |
| 341 | + axes = {*self._shared_x_axes.get_siblings(self), |
| 342 | + *self._shared_y_axes.get_siblings(self), |
| 343 | + *self._shared_z_axes.get_siblings(self), |
| 344 | + } |
| 345 | + else: |
| 346 | + axes = {self} |
| 347 | + for ax in axes: |
| 348 | + ax._anchor = anchor |
| 349 | + ax.stale = True |
| 350 | + |
264 | 351 | def apply_aspect(self, position=None):
|
265 | 352 | if position is None:
|
266 | 353 | position = self.get_position(original=True)
|
267 | 354 |
|
| 355 | + aspect = self.get_aspect() |
| 356 | + if aspect == 'auto': |
| 357 | + return |
| 358 | + |
268 | 359 | # in the superclass, we would go through and actually deal with axis
|
269 | 360 | # scales and box/datalim. Those are all irrelevant - all we need to do
|
270 | 361 | # is make sure our coordinate system is square.
|
|
0 commit comments