Eric Firing wrote:
Ryan May wrote:
Hi,
I'll continue my current flood of emails to the list. :) I'm finally
getting back to my work on Skew-T plots, and I have a semi-working
implementation (attached.) It runs, and as is, plots up some of the
grid, with the x-value grid lines skewed 45 degrees to the right (as
they should be.) The problem is as you resize the plot horizontally,
some weird things happen. First, some of the lines that start
overlaid end up separating as you expand the plot. The difference is
between what is added using ax.plot and what is added using
ax.vlines. The former adds Line2D objects while the latter adds a
LineCollection which is holding path objects. I'm really not sure
what's going on there. I'm not done checking it out yet, but I'm
curious if anyone has any ideas off the top of their head.
The second issue, which is more pressing, is when you resize
vertically, the axes limits of the plot don't change (good), but
unfortunately the lines don't stay connected to their lower
y-coordinate in data space (bad). I'm really needing to draw things
in a coordinate system that's independant of the data scale but also
doesn't depend on the aspect ratio of the axes, so that I can get
lines (and data plots) where the x gridlines are always at a 45 degree
angle and the lower Y-value point stays fixed. By problem right now
is that while I can find the lower left corner in pixel space and use
that to do the proper adjustments, this changes when you resize. This
changing is especially important in the y-direction. What I need is
either of:
1) Axes space adjusted for aspect ratio (and updated with resizes)
2) Pixel space relative to some corner of the axes
Or something similar that I don't know about. Any thoughts, or do I
just need to come up with some magical combination of transforms that
works? You can see what I have so far in my attached file.
Ryan, based only on your description of the problems, and of what you
need, I think the answer, or at least part of it, may be in good old
quiver. Look at the way the transform is being generated depending on
the units chosen, and note that preserving a specified angle on the page
is part of it. Also note that the transform has to be regenerated on
resize events, so a custom draw method is required.
Ok, I've attached code that works for my purpose. It includes text data
so that you can see what the plot is supposed to look like. It turned
out to be rather simple once I figured out exactly what needed to happen
and how the matplotlib API stacked up. As noted in the file, I still
have much to do, like add proper gridlines and somehow fix the nastiness
when you try to pan or zoom. I now at least have a plot that gives me
what I want and resizes correctly (the fact that it looks weird to my
meteorologist eyes when resized is a consequence of the transform's
dependence on data ranges and physical size of the plot).
I ended up going with an approach that just overrides draw to call a
function to update the Axes.transData attribute. I also set transData
to be a transformWrapper() so that any objects that grab the transform
will have access the the updated transform when a resize occurs. BIG
THANKS to Mike for creating such an awesome transform framework. Once
you get the hang of the coordinate systems and know what's actually
possible, it's *extremely* powerful.
Now my bigger question is where the heck to put what I have when I'm
finished...
Ryan
--
Ryan May
Graduate Research Assistant
School of Meteorology
University of Oklahoma
from matplotlib.axes import Axes
from matplotlib.path import Path
from matplotlib.lines import Line2D
from matplotlib.ticker import Formatter, Locator, NullLocator, FixedLocator, \
NullFormatter, AutoLocator, ScalarFormatter
from matplotlib import transforms
from matplotlib.projections import register_projection
import numpy as np
#TODO:
# *Panning and zooming are horribly broken, probably because the
# skewed data are used as bounds. Needs to be disabled (especially panning)
# or updated to work sensibly
# *Gridlines for the x-axis need to be redone to use the skewed ones
# *New functions/methods needed to add the various significant lines:
# -Water vapor mixing ratio
# -Dry adiabats
# -Moist adiabats
# Will these work as new kinds of gridlines?
class SkewXAxes(Axes):
# The projection must specify a name. This will be used be the
# user to select the projection, i.e. ``subplot(111,
# projection='skewx')``.
name = 'skewx'
def draw(self, *args):
'''
draw() is overridden here to allow the data transform to be updated
before calling the Axes.draw() method. This allows resizes to be
properly handled without registering callbacks. The amount of
work done here is kept to a minimum.
'''
self._update_data_transform()
Axes.draw(self, *args)
def _update_data_transform(self):
'''
This separates out the creating of the data transform so that
it alone is updated at draw time.
'''
# This transforms x in pixel space to be x + the offset in y from
# the lower left corner - producing an x-axis sloped 45 degrees
# down, or x-axis grid lines sloped 45 degrees to the right
self.transProjection = transforms.Affine2D(
np.array([[1, 1, -self.bbox.ymin], [0, 1, 0], [0, 0, 1]]))
# Full data transform
self.transData.set(self._transDataNonskew + self.transProjection)
def _set_lim_and_transforms(self):
"""
This is called once when the plot is created to set up all the
transforms for the data, text and grids.
"""
#Get the standard transform setup from the Axes base class
Axes._set_lim_and_transforms(self)
#Save the unskewed data transform for our own use when regenerating
#the data transform. The user might want this as well
self._transDataNonskew = self.transData
#Create a wrapper for the data transform, so that any object that
#grabs this transform will see an updated version when we change it
self.transData = transforms.TransformWrapper(
transforms.IdentityTransform())
#Use the helper method to actually set the skewed data transform
self._update_data_transform()
# Now register the projection with matplotlib so the user can select
# it.
register_projection(SkewXAxes)
if __name__ == '__main__':
data = '''
978.0 345 7.8 0.8 61 4.16 325 14 282.7 294.6 283.4
971.0 404 7.2 0.2 61 4.01 327 17 282.7 294.2 283.4
946.7 610 5.2 -1.8 61 3.56 335 26 282.8 293.0 283.4
944.0 634 5.0 -2.0 61 3.51 336 27 282.8 292.9 283.4
925.0 798 3.4 -2.6 65 3.43 340 32 282.8 292.7 283.4
911.8 914 2.4 -2.7 69 3.46 345 37 282.9 292.9 283.5
906.0 966 2.0 -2.7 71 3.47 348 39 283.0 293.0 283.6
877.9 1219 0.4 -3.2 77 3.46 0 48 283.9 293.9 284.5
850.0 1478 -1.3 -3.7 84 3.44 0 47 284.8 294.8 285.4
841.0 1563 -1.9 -3.8 87 3.45 358 45 285.0 295.0 285.6
823.0 1736 1.4 -0.7 86 4.44 353 42 290.3 303.3 291.0
813.6 1829 4.5 1.2 80 5.17 350 40 294.5 309.8 295.4
809.0 1875 6.0 2.2 77 5.57 347 39 296.6 313.2 297.6
798.0 1988 7.4 -0.6 57 4.61 340 35 299.2 313.3 300.1
791.0 2061 7.6 -1.4 53 4.39 335 33 300.2 313.6 301.0
783.9 2134 7.0 -1.7 54 4.32 330 31 300.4 313.6 301.2
755.1 2438 4.8 -3.1 57 4.06 300 24 301.2 313.7 301.9
727.3 2743 2.5 -4.4 60 3.81 285 29 301.9 313.8 302.6
700.5 3048 0.2 -5.8 64 3.57 275 31 302.7 313.8 303.3
700.0 3054 0.2 -5.8 64 3.56 280 31 302.7 313.8 303.3
698.0 3077 0.0 -6.0 64 3.52 280 31 302.7 313.7 303.4
687.0 3204 -0.1 -7.1 59 3.28 281 31 304.0 314.3 304.6
648.9 3658 -3.2 -10.9 55 2.59 285 30 305.5 313.8 305.9
631.0 3881 -4.7 -12.7 54 2.29 289 33 306.2 313.6 306.6
600.7 4267 -6.4 -16.7 44 1.73 295 39 308.6 314.3 308.9
592.0 4381 -6.9 -17.9 41 1.59 297 41 309.3 314.6 309.6
577.6 4572 -8.1 -19.6 39 1.41 300 44 310.1 314.9 310.3
555.3 4877 -10.0 -22.3 36 1.16 295 39 311.3 315.3 311.5
536.0 5151 -11.7 -24.7 33 0.97 304 39 312.4 315.8 312.6
533.8 5182 -11.9 -25.0 33 0.95 305 39 312.5 315.8 312.7
500.0 5680 -15.9 -29.9 29 0.64 290 44 313.6 315.9 313.7
472.3 6096 -19.7 -33.4 28 0.49 285 46 314.1 315.8 314.1
453.0 6401 -22.4 -36.0 28 0.39 300 50 314.4 315.8 314.4
400.0 7310 -30.7 -43.7 27 0.20 285 44 315.0 315.8 315.0
399.7 7315 -30.8 -43.8 27 0.20 285 44 315.0 315.8 315.0
387.0 7543 -33.1 -46.1 26 0.16 281 47 314.9 315.5 314.9
382.7 7620 -33.8 -46.8 26 0.15 280 48 315.0 315.6 315.0
342.0 8398 -40.5 -53.5 23 0.08 293 52 316.1 316.4 316.1
320.4 8839 -43.7 -56.7 22 0.06 300 54 317.6 317.8 317.6
318.0 8890 -44.1 -57.1 22 0.05 301 55 317.8 318.0 317.8
310.0 9060 -44.7 -58.7 19 0.04 304 61 319.2 319.4 319.2
306.1 9144 -43.9 -57.9 20 0.05 305 63 321.5 321.7 321.5
305.0 9169 -43.7 -57.7 20 0.05 303 63 322.1 322.4 322.1
300.0 9280 -43.5 -57.5 20 0.05 295 64 323.9 324.2 323.9
292.0 9462 -43.7 -58.7 17 0.05 293 67 326.2 326.4 326.2
276.0 9838 -47.1 -62.1 16 0.03 290 74 326.6 326.7 326.6
264.0 10132 -47.5 -62.5 16 0.03 288 79 330.1 330.3 330.1
251.0 10464 -49.7 -64.7 16 0.03 285 85 331.7 331.8 331.7
250.0 10490 -49.7 -64.7 16 0.03 285 85 332.1 332.2 332.1
247.0 10569 -48.7 -63.7 16 0.03 283 88 334.7 334.8 334.7
244.0 10649 -48.9 -63.9 16 0.03 280 91 335.6 335.7 335.6
243.3 10668 -48.9 -63.9 16 0.03 280 91 335.8 335.9 335.8
220.0 11327 -50.3 -65.3 15 0.03 280 85 343.5 343.6 343.5
212.0 11569 -50.5 -65.5 15 0.03 280 83 346.8 346.9 346.8
210.0 11631 -49.7 -64.7 16 0.03 280 83 349.0 349.1 349.0
200.0 11950 -49.9 -64.9 15 0.03 280 80 353.6 353.7 353.6
194.0 12149 -49.9 -64.9 15 0.03 279 78 356.7 356.8 356.7
183.0 12529 -51.3 -66.3 15 0.03 278 75 360.4 360.5 360.4
164.0 13233 -55.3 -68.3 18 0.02 277 69 365.2 365.3 365.2
152.0 13716 -56.5 -69.5 18 0.02 275 65 371.1 371.2 371.1
150.0 13800 -57.1 -70.1 18 0.02 275 64 371.5 371.6 371.5
136.0 14414 -60.5 -72.5 19 0.02 268 54 376.0 376.1 376.0
132.0 14600 -60.1 -72.1 19 0.02 265 51 380.0 380.1 380.0
131.4 14630 -60.2 -72.2 19 0.02 265 51 380.3 380.4 380.3
128.0 14792 -60.9 -72.9 19 0.02 266 50 381.9 382.0 381.9
125.0 14939 -60.1 -72.1 19 0.02 268 49 385.9 386.0 385.9
119.0 15240 -62.2 -73.8 20 0.01 270 48 387.4 387.5 387.4
112.0 15616 -64.9 -75.9 21 0.01 265 53 389.3 389.3 389.3
108.0 15838 -64.1 -75.1 21 0.01 265 58 394.8 394.9 394.8
107.8 15850 -64.1 -75.1 21 0.01 265 58 395.0 395.1 395.0
105.0 16010 -64.7 -75.7 21 0.01 272 50 396.9 396.9 396.9
103.0 16128 -62.9 -73.9 21 0.02 277 45 402.5 402.6 402.5
100.0 16310 -62.5 -73.5 21 0.02 285 36 406.7 406.8 406.7
97.7 16454 -60.5 -72.5 19 0.02 274 30 413.3 413.4 413.3
92.9 16764 -61.5 -73.1 20 0.02 250 17 417.4 417.5 417.4
88.4 17069 -62.4 -73.6 21 0.02 225 30 421.5 421.6 421.5
80.0 17678 -64.3 -74.7 23 0.02 260 35 429.7 429.8 429.7
76.2 17983 -65.3 -75.3 24 0.02 240 29 433.8 433.9 433.8
76.0 17997 -65.3 -75.3 24 0.02 240 29 434.0 434.1 434.0
72.5 18288 -63.6 -74.3 22 0.02 240 24 443.6 443.8 443.6
71.1 18404 -62.9 -73.9 21 0.02 237 20 447.5 447.6 447.5
70.0 18500 -62.9 -73.9 21 0.02 235 16 449.5 449.6 449.5
69.0 18593 -63.2 -74.1 22 0.02 230 16 450.7 450.9 450.7
62.4 19202 -65.5 -75.7 23 0.02 225 2 458.7 458.9 458.7
60.7 19375 -66.1 -76.1 23 0.02 195 5 461.0 461.2 461.0
56.5 19812 -64.4 -75.4 21 0.02 120 12 474.3 474.5 474.4
56.2 19846 -64.3 -75.3 21 0.02 119 12 475.4 475.6 475.4
53.0 20205 -66.3 -76.3 23 0.02 114 16 478.8 478.9 478.8
51.1 20422 -65.7 -75.7 24 0.03 110 18 485.1 485.3 485.1
50.0 20560 -65.3 -75.3 24 0.03 489.2 489.4 489.2
49.8 20584 -65.5 -75.5 24 0.03 489.3 489.5 489.3
48.7 20721 -63.1 -74.1 21 0.03 498.1 498.3 498.1
'''
# Now make a simple example using the custom projection.
import matplotlib.pyplot as plt
from StringIO import StringIO
fig = plt.figure(1, figsize=(6.5875, 6.2125))
fig.clf()
ax = fig.add_subplot(111, projection='skewx')
plt.grid(True)
p,h,T,Td = np.loadtxt(StringIO(data), usecols=range(0,4), unpack=True)
ax.semilogy(T, p, 'r')
ax.semilogy(Td, p, 'g')
ax.yaxis.set_major_locator(AutoLocator())
ax.yaxis.set_major_formatter(ScalarFormatter())
ax.vlines(np.arange(-40,45,10), 1050, 100)
ax.autoscale_view(False)
ax.set_xlim(-40,45)
ax.set_ylim(1050,100)
plt.draw()
plt.show()
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel