<divid="unreleased-message"> You are reading an old version of the documentation (v2.2.0). For the latest version see <ahref="/stable/">https://matplotlib.org/stable/</a></div>
<spanid="sphx-glr-gallery-api-skewt-py"></span><h1>SkewT-logP diagram: using transforms and custom projections<aclass="headerlink" href="#skewt-logp-diagram-using-transforms-and-custom-projections" title="Permalink to this headline">¶</a></h1>
<p>This serves as an intensive exercise of matplotlib’s transforms and custom
projection API. This example produces a so-called SkewT-logP diagram, which is
a common plot in meteorology for displaying vertical profiles of temperature.
As far as matplotlib is concerned, the complexity comes from having X and Y
axes that are not orthogonal. This is handled by including a skew component to
the basic Axes transforms. Additional complexity comes in handling the fact
that the upper and lower X-axes have different data ranges, which necessitates
a bunch of custom classes for ticks,spines, and the axis to handle this.</p>
<spanclass="kn">from</span><spanclass="nn">matplotlib.projections</span><spanclass="kn">import</span><ahref="../../api/projections_api.html#matplotlib.projections.register_projection" title="View documentation for matplotlib.projections.register_projection"><spanclass="n">register_projection</span></a>
<spanclass="c1"># The sole purpose of this class is to look at the upper, lower, or total</span>
<spanclass="c1"># interval as appropriate and see what parts of the tick to draw, if any.</span>
<spanclass="k">class</span><spanclass="nc">SkewXTick</span><spanclass="p">(</span><ahref="../../api/axis_api.html#matplotlib.axis.XTick" title="View documentation for matplotlib.axis.XTick"><spanclass="n">maxis</span><spanclass="o">.</span><spanclass="n">XTick</span></a><spanclass="p">):</span>
<ahref="../../api/transformations.html#matplotlib.transforms.interval_contains" title="View documentation for matplotlib.transforms.interval_contains"><spanclass="n">transforms</span><spanclass="o">.</span><spanclass="n">interval_contains</span></a><spanclass="p">(</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">axes</span><spanclass="o">.</span><spanclass="n">lower_xlim</span><spanclass="p">,</span>
<ahref="../../api/transformations.html#matplotlib.transforms.interval_contains" title="View documentation for matplotlib.transforms.interval_contains"><spanclass="n">transforms</span><spanclass="o">.</span><spanclass="n">interval_contains</span></a><spanclass="p">(</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">axes</span><spanclass="o">.</span><spanclass="n">upper_xlim</span><spanclass="p">,</span>
<ahref="../../api/transformations.html#matplotlib.transforms.interval_contains" title="View documentation for matplotlib.transforms.interval_contains"><spanclass="n">transforms</span><spanclass="o">.</span><spanclass="n">interval_contains</span></a><spanclass="p">(</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">get_view_interval</span><spanclass="p">(),</span>
<spanclass="c1"># This class exists to provide two separate sets of intervals to the tick,</span>
<spanclass="c1"># as well as create instances of the custom tick</span>
<spanclass="k">class</span><spanclass="nc">SkewXAxis</span><spanclass="p">(</span><ahref="../../api/axis_api.html#matplotlib.axis.XAxis" title="View documentation for matplotlib.axis.XAxis"><spanclass="n">maxis</span><spanclass="o">.</span><spanclass="n">XAxis</span></a><spanclass="p">):</span>
<spanclass="c1"># This class exists to calculate the separate data range of the</span>
<spanclass="c1"># upper X-axis and draw the spine there. It also provides this range</span>
<spanclass="c1"># to the X-axis artist for ticking and gridlines</span>
<spanclass="k">class</span><spanclass="nc">SkewSpine</span><spanclass="p">(</span><ahref="../../api/spines_api.html#matplotlib.spines.Spine" title="View documentation for matplotlib.spines.Spine"><spanclass="n">mspines</span><spanclass="o">.</span><spanclass="n">Spine</span></a><spanclass="p">):</span>
<spanclass="c1"># This class handles registration of the skew-xaxes as a projection as well</span>
<spanclass="c1"># as setting up the appropriate transformations. It also overrides standard</span>
<spanclass="c1"># spines and axes instances as appropriate.</span>
<spanclass="k">class</span><spanclass="nc">SkewXAxes</span><spanclass="p">(</span><ahref="../../api/axes_api.html#matplotlib.axes.Axes" title="View documentation for matplotlib.axes.Axes"><spanclass="n">Axes</span></a><spanclass="p">):</span>
<spanclass="c1"># The projection must specify a name. This will be used be the</span>
<spanclass="c1"># user to select the projection, i.e. ``subplot(111,</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">yaxis</span><spanclass="o">=</span><ahref="../../api/axis_api.html#matplotlib.axis.YAxis" title="View documentation for matplotlib.axis.YAxis"><spanclass="n">maxis</span><spanclass="o">.</span><spanclass="n">YAxis</span></a><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">)</span>
<spanclass="s1">'bottom'</span><spanclass="p">:</span><ahref="../../api/spines_api.html#matplotlib.spines.Spine.linear_spine" title="View documentation for matplotlib.spines.Spine.linear_spine"><spanclass="n">mspines</span><spanclass="o">.</span><spanclass="n">Spine</span><spanclass="o">.</span><spanclass="n">linear_spine</span></a><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">,</span><spanclass="s1">'bottom'</span><spanclass="p">),</span>
<spanclass="s1">'left'</span><spanclass="p">:</span><ahref="../../api/spines_api.html#matplotlib.spines.Spine.linear_spine" title="View documentation for matplotlib.spines.Spine.linear_spine"><spanclass="n">mspines</span><spanclass="o">.</span><spanclass="n">Spine</span><spanclass="o">.</span><spanclass="n">linear_spine</span></a><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">,</span><spanclass="s1">'left'</span><spanclass="p">),</span>
<spanclass="s1">'right'</span><spanclass="p">:</span><ahref="../../api/spines_api.html#matplotlib.spines.Spine.linear_spine" title="View documentation for matplotlib.spines.Spine.linear_spine"><spanclass="n">mspines</span><spanclass="o">.</span><spanclass="n">Spine</span><spanclass="o">.</span><spanclass="n">linear_spine</span></a><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">,</span><spanclass="s1">'right'</span><spanclass="p">)}</span>
<spanclass="c1"># Get the standard transform setup from the Axes base class</span>
<ahref="../../api/axes_api.html#matplotlib.axes.Axes" title="View documentation for matplotlib.axes.Axes"><spanclass="n">Axes</span></a><spanclass="o">.</span><spanclass="n">_set_lim_and_transforms</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">)</span>
<spanclass="c1"># Need to put the skew in the middle, after the scale and limits,</span>
<spanclass="c1"># but before the transAxes. This way, the skew is done in Axes</span>
<spanclass="c1"># coordinates thus performing the transform around the proper origin</span>
<spanclass="c1"># We keep the pre-transAxes transform around for other users, like the</span>
<spanclass="c1"># spines for finding bounds</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">transLimits</span><spanclass="o">+</span><ahref="../../api/transformations.html#matplotlib.transforms.Affine2D" title="View documentation for matplotlib.transforms.Affine2D"><spanclass="n">transforms</span><spanclass="o">.</span><spanclass="n">Affine2D</span></a><spanclass="p">()</span><spanclass="o">.</span><spanclass="n">skew_deg</span><spanclass="p">(</span><spanclass="n">rot</span><spanclass="p">,</span><spanclass="mi">0</span><spanclass="p">)</span>
<spanclass="c1"># Create the full transform from Data to Pixels</span>
<spanclass="c1"># Blended transforms like this need to have the skewing applied using</span>
<spanclass="c1"># both axes, in axes coords like before.</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_xaxis_transform</span><spanclass="o">=</span><spanclass="p">(</span><ahref="../../api/transformations.html#matplotlib.transforms.blended_transform_factory" title="View documentation for matplotlib.transforms.blended_transform_factory"><spanclass="n">transforms</span><spanclass="o">.</span><spanclass="n">blended_transform_factory</span></a><spanclass="p">(</span>
<ahref="../../api/transformations.html#matplotlib.transforms.IdentityTransform" title="View documentation for matplotlib.transforms.IdentityTransform"><spanclass="n">transforms</span><spanclass="o">.</span><spanclass="n">IdentityTransform</span></a><spanclass="p">())</span><spanclass="o">+</span>
<ahref="../../api/transformations.html#matplotlib.transforms.Affine2D" title="View documentation for matplotlib.transforms.Affine2D"><spanclass="n">transforms</span><spanclass="o">.</span><spanclass="n">Affine2D</span></a><spanclass="p">()</span><spanclass="o">.</span><spanclass="n">skew_deg</span><spanclass="p">(</span><spanclass="n">rot</span><spanclass="p">,</span><spanclass="mi">0</span><spanclass="p">))</span><spanclass="o">+</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">transAxes</span>
<spanclass="c1"># Now register the projection with matplotlib so the user can select</span>
<spanclass="c1"># it.</span>
<ahref="../../api/projections_api.html#matplotlib.projections.register_projection" title="View documentation for matplotlib.projections.register_projection"><spanclass="n">register_projection</span></a><spanclass="p">(</span><spanclass="n">SkewXAxes</span><spanclass="p">)</span>
<spanclass="c1"># Now make a simple example using the custom projection.</span>
<spanclass="kn">from</span><spanclass="nn">matplotlib.ticker</span><spanclass="kn">import</span><spanclass="p">(</span><ahref="../../api/ticker_api.html#matplotlib.ticker.MultipleLocator" title="View documentation for matplotlib.ticker.MultipleLocator"><spanclass="n">MultipleLocator</span></a><spanclass="p">,</span><ahref="../../api/ticker_api.html#matplotlib.ticker.NullFormatter" title="View documentation for matplotlib.ticker.NullFormatter"><spanclass="n">NullFormatter</span></a><spanclass="p">,</span>
<ahref="../../api/ticker_api.html#matplotlib.ticker.ScalarFormatter" title="View documentation for matplotlib.ticker.ScalarFormatter"><spanclass="n">ScalarFormatter</span></a><spanclass="p">)</span>
<spanclass="n">p</span><spanclass="p">,</span><spanclass="n">h</span><spanclass="p">,</span><spanclass="n">T</span><spanclass="p">,</span><spanclass="n">Td</span><spanclass="o">=</span><ahref="https://docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html#numpy.loadtxt" title="View documentation for numpy.loadtxt"><spanclass="n">np</span><spanclass="o">.</span><spanclass="n">loadtxt</span></a><spanclass="p">(</span><spanclass="n">sound_data</span><spanclass="p">,</span><spanclass="n">usecols</span><spanclass="o">=</span><spanclass="nb">range</span><spanclass="p">(</span><spanclass="mi">0</span><spanclass="p">,</span><spanclass="mi">4</span><spanclass="p">),</span><spanclass="n">unpack</span><spanclass="o">=</span><spanclass="bp">True</span><spanclass="p">)</span>
<spanclass="c1"># Create a new figure. The dimensions here give a good aspect ratio</span>
<spanclass="n">fig</span><spanclass="o">=</span><ahref="../../api/_as_gen/matplotlib.pyplot.figure.html#matplotlib.pyplot.figure" title="View documentation for matplotlib.pyplot.figure"><spanclass="n">plt</span><spanclass="o">.</span><spanclass="n">figure</span></a><spanclass="p">(</span><spanclass="n">figsize</span><spanclass="o">=</span><spanclass="p">(</span><spanclass="mf">6.5875</span><spanclass="p">,</span><spanclass="mf">6.2125</span><spanclass="p">))</span>
<ahref="../../api/_as_gen/matplotlib.pyplot.grid.html#matplotlib.pyplot.grid" title="View documentation for matplotlib.pyplot.grid"><spanclass="n">plt</span><spanclass="o">.</span><spanclass="n">grid</span></a><spanclass="p">(</span><spanclass="bp">True</span><spanclass="p">)</span>
<spanclass="c1"># Plot the data using normal plotting functions, in this case using</span>
<spanclass="c1"># log scaling in Y, as dictated by the typical meteorological plot</span>
<spanclass="c1"># Disables the log-formatting that comes with semilogy</span>
<spanclass="n">ax</span><spanclass="o">.</span><spanclass="n">yaxis</span><spanclass="o">.</span><spanclass="n">set_major_formatter</span><spanclass="p">(</span><ahref="../../api/ticker_api.html#matplotlib.ticker.ScalarFormatter" title="View documentation for matplotlib.ticker.ScalarFormatter"><spanclass="n">ScalarFormatter</span></a><spanclass="p">())</span>
<spanclass="n">ax</span><spanclass="o">.</span><spanclass="n">yaxis</span><spanclass="o">.</span><spanclass="n">set_minor_formatter</span><spanclass="p">(</span><ahref="../../api/ticker_api.html#matplotlib.ticker.NullFormatter" title="View documentation for matplotlib.ticker.NullFormatter"><spanclass="n">NullFormatter</span></a><spanclass="p">())</span>
<spanclass="n">ax</span><spanclass="o">.</span><spanclass="n">set_yticks</span><spanclass="p">(</span><ahref="https://docs.scipy.org/doc/numpy/reference/generated/numpy.linspace.html#numpy.linspace" title="View documentation for numpy.linspace"><spanclass="n">np</span><spanclass="o">.</span><spanclass="n">linspace</span></a><spanclass="p">(</span><spanclass="mi">100</span><spanclass="p">,</span><spanclass="mi">1000</span><spanclass="p">,</span><spanclass="mi">10</span><spanclass="p">))</span>
<spanclass="n">ax</span><spanclass="o">.</span><spanclass="n">xaxis</span><spanclass="o">.</span><spanclass="n">set_major_locator</span><spanclass="p">(</span><ahref="../../api/ticker_api.html#matplotlib.ticker.MultipleLocator" title="View documentation for matplotlib.ticker.MultipleLocator"><spanclass="n">MultipleLocator</span></a><spanclass="p">(</span><spanclass="mi">10</span><spanclass="p">))</span>
<ahref="../../api/_as_gen/matplotlib.pyplot.show.html#matplotlib.pyplot.show" title="View documentation for matplotlib.pyplot.show"><spanclass="n">plt</span><spanclass="o">.</span><spanclass="n">show</span></a><spanclass="p">()</span>