|
18 | 18 | ``ax`` is a :class:`~matplotlib.axes.Axes` instance, and ``fig`` is a
|
19 | 19 | :class:`~matplotlib.figure.Figure` instance.
|
20 | 20 |
|
21 |
| -+-----------+-----------------------------+-----------------------------------+ |
22 |
| -|Coordinates|Transformation object |Description | |
23 |
| -+-----------+-----------------------------+-----------------------------------+ |
24 |
| -|"data" |``ax.transData`` |The coordinate system for the data,| |
25 |
| -| | |controlled by xlim and ylim. | |
26 |
| -+-----------+-----------------------------+-----------------------------------+ |
27 |
| -|"axes" |``ax.transAxes`` |The coordinate system of the | |
28 |
| -| | |`~matplotlib.axes.Axes`; (0, 0) | |
29 |
| -| | |is bottom left of the axes, and | |
30 |
| -| | |(1, 1) is top right of the axes. | |
31 |
| -+-----------+-----------------------------+-----------------------------------+ |
32 |
| -|"figure" |``fig.transFigure`` |The coordinate system of the | |
33 |
| -| | |`.Figure`; (0, 0) is bottom left | |
34 |
| -| | |of the figure, and (1, 1) is top | |
35 |
| -| | |right of the figure. | |
36 |
| -+-----------+-----------------------------+-----------------------------------+ |
37 |
| -|"display" |``None``, or |The pixel coordinate system of the | |
38 |
| -| |``IdentityTransform()`` |display; (0, 0) is bottom left of | |
39 |
| -| | |the display, and (width, height) is| |
40 |
| -| | |top right of the display in pixels.| |
41 |
| -+-----------+-----------------------------+-----------------------------------+ |
42 |
| -|"xaxis", |``ax.get_xaxis_transform()``,|Blended coordinate systems; use | |
43 |
| -|"yaxis" |``ax.get_yaxis_transform()`` |data coordinates on one of the axis| |
44 |
| -| | |and axes coordinates on the other. | |
45 |
| -+-----------+-----------------------------+-----------------------------------+ |
| 21 | ++----------------+-----------------------------+-----------------------------------+ |
| 22 | +|Coordinates |Transformation object |Description | |
| 23 | ++----------------+-----------------------------+-----------------------------------+ |
| 24 | +|"data" |``ax.transData`` |The coordinate system for the data,| |
| 25 | +| | |controlled by xlim and ylim. | |
| 26 | ++----------------+-----------------------------+-----------------------------------+ |
| 27 | +|"axes" |``ax.transAxes`` |The coordinate system of the | |
| 28 | +| | |`~matplotlib.axes.Axes`; (0, 0) | |
| 29 | +| | |is bottom left of the axes, and | |
| 30 | +| | |(1, 1) is top right of the axes. | |
| 31 | ++----------------+-----------------------------+-----------------------------------+ |
| 32 | +|"figure" |``fig.transFigure`` |The coordinate system of the | |
| 33 | +| | |`.Figure`; (0, 0) is bottom left | |
| 34 | +| | |of the figure, and (1, 1) is top | |
| 35 | +| | |right of the figure. | |
| 36 | ++----------------+-----------------------------+-----------------------------------+ |
| 37 | +|"figure-inches" |``fig.dpi_scale_trans`` |The coordinate system of the | |
| 38 | +| | |`.Figure` in inches; (0, 0) is | |
| 39 | +| | |bottom left of the figure, and | |
| 40 | +| | |(width, height) is the top right | |
| 41 | +| | |of the figure ininches. | |
| 42 | ++----------------+-----------------------------+-----------------------------------+ |
| 43 | +|"display" |``None``, or |The pixel coordinate system of the | |
| 44 | +| |``IdentityTransform()`` |display window; (0, 0) is bottom | |
| 45 | +| | |left of the window, and (width, | |
| 46 | +| | |height) is top right of the | |
| 47 | +| | |display window in pixels. | |
| 48 | ++----------------+-----------------------------+-----------------------------------+ |
| 49 | +|"xaxis", |``ax.get_xaxis_transform()``,|Blended coordinate systems; use | |
| 50 | +|"yaxis" |``ax.get_yaxis_transform()`` |data coordinates on one of the axis| |
| 51 | +| | |and axes coordinates on the other. | |
| 52 | ++----------------+-----------------------------+-----------------------------------+ |
46 | 53 |
|
47 | 54 | All of the transformation objects in the table above take inputs in
|
48 |
| -their coordinate system, and transform the input to the `display` |
49 |
| -coordinate system. That is why the `display` coordinate system has |
50 |
| -`None` for the `Transformation Object` column -- it already is in |
| 55 | +their coordinate system, and transform the input to the ``display`` |
| 56 | +coordinate system. That is why the ``display`` coordinate system has |
| 57 | +``None`` for the ``Transformation Object`` column -- it already is in |
51 | 58 | display coordinates. The transformations also know how to invert
|
52 |
| -themselves, to go from `display` back to the native coordinate system. |
| 59 | +themselves, to go from ``display`` back to the native coordinate system. |
53 | 60 | This is particularly useful when processing events from the user
|
54 | 61 | interface, which typically occur in display space, and you want to
|
55 | 62 | know where the mouse click or key-press occurred in your data
|
56 | 63 | coordinate system.
|
57 | 64 |
|
| 65 | +Note that specifying objects in ``display`` coordinates will change their |
| 66 | +location if the ``dpi`` of the figure changes. This can cause confusion when |
| 67 | +printing or changing screen resolution, because the object can change location |
| 68 | +and size. Therefore it is most common |
| 69 | +for artists placed in an axes or figure to have their transform set to |
| 70 | +something *other* than the ``IdentityTransform()``; the default when an artist |
| 71 | +is placed on an axes using ``~Axes.axes.add_artist`` is for the transform to be |
| 72 | +`ax.transData`. |
| 73 | +
|
58 | 74 | .. _data-coords:
|
59 | 75 |
|
60 | 76 | Data coordinates
|
|
71 | 87 |
|
72 | 88 | import numpy as np
|
73 | 89 | import matplotlib.pyplot as plt
|
| 90 | +import matplotlib.patches as mpatches |
74 | 91 |
|
75 | 92 | x = np.arange(0, 10, 0.005)
|
76 | 93 | y = np.exp(-x/2.) * np.sin(2*np.pi*x)
|
|
143 | 160 | (xdata, ydata), xytext=(-2*offset, offset), textcoords='offset points',
|
144 | 161 | bbox=bbox, arrowprops=arrowprops)
|
145 | 162 |
|
146 |
| - |
147 | 163 | disp = ax.annotate('display = (%.1f, %.1f)' % (xdisplay, ydisplay),
|
148 | 164 | (xdisplay, ydisplay), xytext=(0.5*offset, -offset),
|
149 | 165 | xycoords='figure pixels',
|
150 | 166 | textcoords='offset points',
|
151 | 167 | bbox=bbox, arrowprops=arrowprops)
|
152 | 168 |
|
153 |
| - |
154 | 169 | plt.show()
|
155 | 170 |
|
156 | 171 | ###############################################################################
|
|
229 | 244 | # move, but the circle will remain fixed because it is not in `data`
|
230 | 245 | # coordinates and will always remain at the center of the axes.
|
231 | 246 |
|
232 |
| -import matplotlib.patches as patches |
233 |
| - |
234 | 247 | fig = plt.figure()
|
235 | 248 | ax = fig.add_subplot(111)
|
236 | 249 | x, y = 10*np.random.rand(2, 1000)
|
237 |
| -ax.plot(x, y, 'go') # plot some data in data coordinates |
| 250 | +ax.plot(x, y, 'go', alpha=0.2) # plot some data in data coordinates |
238 | 251 |
|
239 |
| -circ = patches.Circle((0.5, 0.5), 0.25, transform=ax.transAxes, |
240 |
| - facecolor='yellow', alpha=0.5) |
| 252 | +circ = mpatches.Circle((0.5, 0.5), 0.25, transform=ax.transAxes, |
| 253 | + facecolor='blue', alpha=0.75) |
241 | 254 | ax.add_patch(circ)
|
242 | 255 | plt.show()
|
243 | 256 |
|
|
281 | 294 | # highlight the 1..2 stddev region with a span.
|
282 | 295 | # We want x to be in data coordinates and y to
|
283 | 296 | # span from 0..1 in axes coords
|
284 |
| -rect = patches.Rectangle((1, 0), width=1, height=1, |
| 297 | +rect = mpatches.Rectangle((1, 0), width=1, height=1, |
285 | 298 | transform=trans, color='yellow',
|
286 | 299 | alpha=0.5)
|
287 | 300 |
|
|
303 | 316 | #
|
304 | 317 | # trans = ax.get_xaxis_transform()
|
305 | 318 | #
|
| 319 | +# .. _transforms-fig-scale-dpi: |
| 320 | +# |
| 321 | +# Plotting in physical units |
| 322 | +# ========================== |
| 323 | +# |
| 324 | +# Sometimes we want an object to be a certain physical size on the plot. |
| 325 | +# Here we draw the same circle as above, but in physical units. If done |
| 326 | +# interactively, you can see that changing the size of the figure does |
| 327 | +# not change the offset of the circle from the lower-left corner, |
| 328 | +# does not change its size, and the circle remains a circle regardless of |
| 329 | +# the aspect ratio of the axes. |
| 330 | + |
| 331 | +fig, ax = plt.subplots(figsize=(5, 4)) |
| 332 | +x, y = 10*np.random.rand(2, 1000) |
| 333 | +ax.plot(x, y*10., 'go', alpha=0.2) # plot some data in data coordinates |
| 334 | +# add a circle in fixed-units |
| 335 | +circ = mpatches.Circle((2.5, 2), 1.0, transform=fig.dpi_scale_trans, |
| 336 | + facecolor='blue', alpha=0.75) |
| 337 | +ax.add_patch(circ) |
| 338 | +plt.show() |
| 339 | + |
| 340 | +############################################################################### |
| 341 | +# If we change the figure size... |
| 342 | + |
| 343 | +fig, ax = plt.subplots(figsize=(7, 2)) |
| 344 | +x, y = 10*np.random.rand(2, 1000) |
| 345 | +ax.plot(x, y*10., 'go', alpha=0.2) # plot some data in data coordinates |
| 346 | +# add a circle in fixed-units |
| 347 | +circ = mpatches.Circle((2.5, 2), 1.0, transform=fig.dpi_scale_trans, |
| 348 | + facecolor='blue', alpha=0.75) |
| 349 | +ax.add_patch(circ) |
| 350 | +plt.show() |
| 351 | + |
| 352 | +############################################################################### |
| 353 | +# Another use is putting a patch with a set physical dimmension around a |
| 354 | +# data point on the axes. Here we add together two transforms. The |
| 355 | +# first sets the scaling of how large the ellipse should be and the second |
| 356 | +# sets its position. The ellipse is then placed at the origin, and then |
| 357 | +# we use the helper transform :class:`~matplotlib.transforms.ScaledTranslation` |
| 358 | +# to move it |
| 359 | +# to the right place in the ``ax.transData`` coordinate system. |
| 360 | +# This helper is instantiated with:: |
| 361 | +# |
| 362 | +# trans = ScaledTranslation(xt, yt, scale_trans) |
| 363 | +# |
| 364 | +# where `xt` and `yt` are the translation offsets, and `scale_trans` is |
| 365 | +# a transformation which scales `xt` and `yt` at transformation time |
| 366 | +# before applying the offsets. |
| 367 | +# |
| 368 | +# Note that in interactive use, the ellipse stays the same size even if the |
| 369 | +# axes limits are changed via zoom, but the ellipse's size doesn't change. |
| 370 | +# |
| 371 | +# Also note that the order of transformation matters. Here the ellipse |
| 372 | +# is given the right dimensions in display space *first* and then moved |
| 373 | +# in data space to the correct spot. |
| 374 | +# If we had done the ``ScaledTranslation`` first, then |
| 375 | +# ``xdata[0]`` and ``ydata[0]`` would |
| 376 | +# first be transfromed to ``display`` coordinates (``[ 358.4 475.2]`` on |
| 377 | +# a 200-dpi monitor) and then those coordinates |
| 378 | +# would be scaled by ``fig.dpi_scale_trans`` pushing the center of |
| 379 | +# the ellipse well off the screen (i.e. ``[ 71680. 95040.]``). |
| 380 | + |
| 381 | +fig, ax = plt.subplots() |
| 382 | +xdata, ydata = (0.2, 0.7), (0.5, 0.5) |
| 383 | +ax.plot(xdata, ydata, "o") |
| 384 | +ax.set_xlim((0, 1)) |
| 385 | + |
| 386 | +trans = fig.dpi_scale_trans + \ |
| 387 | + mtransforms.ScaledTranslation(xdata[0], ydata[0], ax.transData) |
| 388 | + |
| 389 | +# plot an ellipse around the point that is 150 x 130 points in diameter... |
| 390 | +circle = mpatches.Ellipse((0, 0), 150/72, 130/72, angle=40, fill=None, |
| 391 | + transform=trans) |
| 392 | +ax.add_patch(circle) |
| 393 | +plt.show() |
| 394 | + |
| 395 | +############################################################################### |
306 | 396 | # .. _offset-transforms-shadow:
|
307 | 397 | #
|
308 | 398 | # Using offset transforms to create a shadow effect
|
309 | 399 | # =================================================
|
310 | 400 | #
|
311 |
| -# One use of transformations is to create a new transformation that is |
| 401 | +# Another use of :class:`~matplotlib.transforms.ScaledTranslation` is to create |
| 402 | +# a new transformation that is |
312 | 403 | # offset from another transformation, e.g., to place one object shifted a
|
313 | 404 | # bit relative to another object. Typically you want the shift to be in
|
314 | 405 | # some physical dimension, like points or inches rather than in data
|
|
318 | 409 | # One use for an offset is to create a shadow effect, where you draw one
|
319 | 410 | # object identical to the first just to the right of it, and just below
|
320 | 411 | # it, adjusting the zorder to make sure the shadow is drawn first and
|
321 |
| -# then the object it is shadowing above it. The transforms module has a |
322 |
| -# helper transformation |
323 |
| -# :class:`~matplotlib.transforms.ScaledTranslation`. It is |
324 |
| -# instantiated with:: |
325 |
| -# |
326 |
| -# trans = ScaledTranslation(xt, yt, scale_trans) |
| 412 | +# then the object it is shadowing above it. |
327 | 413 | #
|
328 |
| -# where `xt` and `yt` are the translation offsets, and `scale_trans` is |
329 |
| -# a transformation which scales `xt` and `yt` at transformation time |
330 |
| -# before applying the offsets. A typical use case is to use the figure |
331 |
| -# ``fig.dpi_scale_trans`` transformation for the `scale_trans` argument, |
332 |
| -# to first scale `xt` and `yt` specified in points to `display` space |
| 414 | +# As above, in :class:`~matplotlib.transforms.ScaledTranslation` we use |
| 415 | +# ``fig.dpi_scale_trans`` transformation for the ``scale_trans`` argument, |
| 416 | +# to first scale ``xt`` and ``yt`` specified in points to ``display`` space |
333 | 417 | # before doing the final offset. The dpi and inches offset is a
|
334 | 418 | # common-enough use case that we have a special helper function to
|
335 | 419 | # create it in :func:`matplotlib.transforms.offset_copy`, which returns
|
|
348 | 432 | # 1/72 inches, and by specifying your offsets in points, your figure
|
349 | 433 | # will look the same regardless of the dpi resolution it is saved in.
|
350 | 434 |
|
351 |
| -fig = plt.figure() |
352 |
| -ax = fig.add_subplot(111) |
| 435 | +fig, ax = plt.subplots() |
353 | 436 |
|
354 | 437 | # make a simple sine wave
|
355 | 438 | x = np.arange(0., 2., 0.01)
|
|
0 commit comments