Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

skewT subplots assume celcius without a warning #1155

Closed
jibbals opened this issue Sep 11, 2019 · 9 comments · May be fixed by #1216
Closed

skewT subplots assume celcius without a warning #1155

jibbals opened this issue Sep 11, 2019 · 9 comments · May be fixed by #1216
Labels
Area: Plots Pertains to producing plots Type: Bug Something is not working like it should
Milestone

Comments

@jibbals
Copy link

jibbals commented Sep 11, 2019

import matplotlib.pyplot as plt
from metpy.units import units
from metpy.plots import SkewT
import numpy as np

# Pressure in hPa
p = np.array([1006.0437475 ,  995.76678167,  971.08324364,  932.77561992,
              882.03055039,  820.47928304,  750.09469793,  673.30749624,
              593.14227853,  512.06441041,  431.84615956,  343.13325525,
              206.98255942]) * units.hPa
# Temperature in Kelvin
T = np.array([308.75318763, 306.06809246, 303.6426414 , 300.10817166,
              295.43166071, 289.50015275, 283.0458144 , 276.37844266,
              272.42841696, 264.21209355, 254.43607077, 240.42762839,
              215.55300601]) * units.degK
# Dewpoint temperature in Kelvin
Td = np.array([287.13853628, 286.57071724, 286.14560658, 285.52678341,
               284.70488872, 283.57435228, 281.99306255, 274.24633018,
               254.00050803, 231.5517735 , 225.75652085, 220.79078678,
               206.97078861]) * units.degK

# figure with kelvin on x-axis
skew = SkewT(plt.figure())
skew.plot(p,T,'k')
skew.plot(p,Td,'g')
skew.plot_dry_adiabats() # 
skew.plot_moist_adiabats()
skew.plot_mixing_lines()
plt.title("F160 plot using Kelvin (wrong adiabats/mixing ratio)")
plt.savefig('mintest1.png')
plt.close()

# figure with celcius on x-axis
skew = SkewT(plt.figure())
skew.plot(p,T.to(units.degC),'k')
skew.plot(p,Td.to(units.degC),'g')
skew.plot_dry_adiabats() # 
skew.plot_moist_adiabats()
skew.plot_mixing_lines()
skew.ax.set_xlim(-30,60)
plt.title("F160 plot using Celcius")
plt.savefig('mintest2.png')
plt.close()

mintest1
mintest2

Problem:
If using degrees Kelvin for the SkewT plot, the axis is updated to 'kelvin' but the plot_dry_adiabats() plot_moist_adiabats() and plot_mixing_lines() assume the units are in degrees Celcius. This means that the adiabats are plotted wrongly, and the mixing rate lines are 273.15 degrees to the left of where they should be.

Expected output:
Either a warning that Celcius is required, or correct conversion of the x-axis to degrees Kelvin.

Run environment:
Anaconda on windows:

  • python --version Python 3.7.4
  • `python -c 'import metpy; print(metpy.version)' 0.10.2
@jibbals jibbals added the Type: Bug Something is not working like it should label Sep 11, 2019
@jibbals
Copy link
Author

jibbals commented Sep 11, 2019

I would be happy to attempt a fix, for instance changing the plot_dry_adiabats as follows?

def plot_dry_adiabats(self, t0=None, p=None, **kwargs):
        """ ... """
        # Determine set of starting temps if necessary
        xmin, xmax = self.ax.get_xlim() # MOVED THIS LINE OUT OF IF
        kelvin=xmin>150 # is there a better way for this to be flagged?
        if t0 is None:
            t0 = np.arange(xmin, xmax + 1, 10) * units.degC
            if kelvin: # ADDED THIS LINE
                t0 = np.arange(xmin, xmax + 1, 10) * units.degK

        # Get pressure levels based on ylims if necessary
        if p is None:
            p = np.linspace(*self.ax.get_ylim()) * units.mbar

        # Assemble into data for plotting
        t = dry_lapse(p, t0[:, np.newaxis].to(units.degC), 1000. * units.mbar).to(units.degC)
        if kelvin: # ADDED
            t = t.to(units.degK) # ADDED 
        linedata = [np.vstack((ti, p)).T for ti in t]

        # Add to plot
        kwargs.setdefault('colors', 'r')
        kwargs.setdefault('linestyles', 'dashed')
        kwargs.setdefault('alpha', 0.5)
        return self.ax.add_collection(LineCollection(linedata, **kwargs))

@jthielen
Copy link
Collaborator

jthielen commented Sep 11, 2019

This bug is definitely worrisome, but it isn't surprising given the current absence of proper unit handling in SkewT plotting. In relation to @zbruick's recent side question in #1149, I think this is a good demonstration of how the current approach is problematic and why units for SkewT should be required.

@zbruick
Copy link
Contributor

zbruick commented Sep 11, 2019

Yeah I've seen this before (way before I got to Unidata) when I forgot to convert to Celsius. I hadn't actually looked at these methods before to see that Celsius was hardcoded in. Definitely worrisome as we should handle this easily, as a lot of research SkewTs use Kelvin. Thanks @jibbals for documenting and reporting this bug.

As to fixing it, setting a flag to catch when the minimum is above a certain number is a good idea, but I see that solution running into the problem identified in #195 (which might as well be solved at the same time as this bug if possible). I don't know if patching this bug in this manner, but leaving #195, is a good option at this point. Seems like we should somehow default to a normal Celsius range (most common scale IMO) when SkewT is called, and then recognize Kelvin if the x-range if higher. The other option would be to have a kwarg for which unit scale to use, but this seems like something that should be identified without needing that. Thoughts?

@zbruick
Copy link
Contributor

zbruick commented Sep 11, 2019

After investigating this a bit, here are my conclusions:

@jibbals do you want to tackle this? @dopplershift, any other thoughts or better way?

@zbruick zbruick added the Area: Plots Pertains to producing plots label Sep 11, 2019
@zbruick
Copy link
Contributor

zbruick commented Sep 11, 2019

This patch got a thumbs up from @dopplershift. We're going to open an issue with matplotlib to gain unit support for ax.get_xlim() to clean up the hard-coding. In the meantime, @jibbals I think you're good to go with your suggestion, if you have the time. If you could just add a # TODO: Refactor if get_xlim() supports units eventually comment line in each method so that we remember to refactor once any changes to matplotlib are added.

@dopplershift
Copy link
Member

So to capture the conversation I had with @zbruick:

  • Matplotlib really should be supporting our units (it has pluggable unit support) and this should be fine, but it seems get_xlim() does not return values with units
  • I'm not sure why plot_mixing_ratio isn't using a plot method (which would trigger matplotlib's unit handling), but is instead using np.vstack and manually creating a LineCollection, which is not doing anything unit-aware
  • I think the correct solution is to make these proper gridlines and make sure that all plays well with matplotlib's unit handling--that's not a quick fix unless I have a really good day
  • In the short term, I think a heuristic to guess at whether we have Kelvin or Celsius is reasonable--it's better than having fundamentally broken plots with Kelvin
  • We need to have a test for plotting in Kelvin

@dopplershift
Copy link
Member

Actually, here's another option to get the proper xunits that's not a hack:

self.ax.xaxis.get_xunits()

@jibbals
Copy link
Author

jibbals commented Sep 11, 2019

I’ll have a go at this, thanks for all the feedback and I’ll try to use that get_xunits too

jibbals added a commit to jibbals/MetPy that referenced this issue Oct 24, 2019
Wet and dry adiabats, along with mixing lines, do not correctly
plot unless everything is in degrees celcius. This is especially
a problem when the plots show the wrong values without giving
any sort of warning. This fix makes the subroutines plot onto
units matching the xaxis or input temperature.
Checklist

Closes Unidata#1155
test added
dopplershift pushed a commit that referenced this issue Dec 3, 2021
Wet and dry adiabats, along with mixing lines, do not correctly
plot unless everything is in degrees celcius. This is especially
a problem when the plots show the wrong values without giving
any sort of warning. This fix makes the subroutines plot onto
units matching the xaxis or input temperature.
Checklist

Closes #1155
test added
dopplershift pushed a commit to jibbals/MetPy that referenced this issue Dec 3, 2021
Wet and dry adiabats, along with mixing lines, do not correctly
plot unless everything is in degrees celcius. This is especially
a problem when the plots show the wrong values without giving
any sort of warning. This fix makes the subroutines plot onto
units matching the xaxis or input temperature.
Checklist

Closes Unidata#1155
test added
@dopplershift dopplershift added this to the 1.2.0 milestone Dec 17, 2021
@dcamron
Copy link
Member

dcamron commented Jan 21, 2022

Though we should potentially hold on to #1216 for some of its other additions, this no longer occurs on newer versions!

@dcamron dcamron closed this as completed Jan 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: Plots Pertains to producing plots Type: Bug Something is not working like it should
Projects
None yet
5 participants