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

Reply via email to