NCAR / ctsm_python_gallery

A place to put sample workflows and tools that use ctsm model output
Apache License 2.0
18 stars 28 forks source link

efficient plotting #24

Open wwieder opened 4 years ago

wwieder commented 4 years ago

how do we make panel plots efficiently?

jhamman commented 4 years ago

Hi @wwieder,

I'll just drop a few comments off the top of my head.

  1. For multi-panel plots that are "good enough" for exploratory analysis, you may checkout out xarray's facet grid functionality: http://xarray.pydata.org/en/stable/plotting.html#faceting. I find these are super useful until I need to make the final publication quality tweaks often required.

  2. When you need more control or you have a very custom plot to make, I generally follow this pattern:

import numpy as np
import matplotlib.pyplot as plt
...

def plot_function(da, ax=None, title=None, ...):
    '''a function to make one subplot'''
    if ax is None:
        ax = plt.gca()
    da.plot(ax=ax, ...)  # more custom args
    ax.set_title(title)

fig, axes = plt.subplots(nrows=4, ncols=2, ...)

for index, ax in np.ndenumerate(axes):
    # there are various ways to do this part, index in this case is a tuple (ie `(0, 0)`)
    plot_function(ds['varname'].isel(time=index), ax=ax, title=index, ...)

fig.suptitle('Super Title')
fig.save(...)
wwieder commented 4 years ago

very helpful, Joe. I'm still confused where different information goes to make these plots look nice. Maybe this can be a topic for the call on thursday?

I'm including some of the code chunks i've used previously, but I'm not good enough with matplotlib to know where they should be dropped into my code? projection=ccrs.Robinson() transform=ccrs.PlateCarree(), ax1.coastlines() ax1.set_title('weighted correlation climo w/ GPP, SV1 = Amplification vector') ax1.set_extent([-180,180,-65,80],crs=ccrs.PlateCarree()) vmax=... vmin=...

-------------------

Code i"m running from is below

-------------------

def plot_function(da, ax=None, title=None): '''a function to make one subplot''' if ax is None: ax = plt.gca() da.plot(ax=ax) # more custom args ax.set_title(title)

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(14,12))

i = 0 var2 = ['maxGPP_season']+var for index, ax in np.ndenumerate(axes):

there are various ways to do this part, index in this case is a tuple

(ie (0, 0)) plot_function(max_season_corr[var2[i]].isel(sv=0), ax=ax, title=var2[i]) i = i+1

On Fri, Feb 7, 2020 at 3:11 PM Joe Hamman notifications@github.com wrote:

Hi @wwieder https://github.com/wwieder,

I'll just drop a few comments off the top of my head.

1.

For multi-panel plots that are "good enough" for exploratory analysis, you may checkout out xarray's facet grid functionality: http://xarray.pydata.org/en/stable/plotting.html#faceting. I find these are super useful until I need to make the final publication quality tweaks often required. 2.

When you need more control or you have a very custom plot to make, I generally follow this pattern:

import numpy as npimport matplotlib.pyplot as plt... def plot_function(da, ax=None, title=None, ...): '''a function to make one subplot''' if ax is None: ax = plt.gca() da.plot(ax=ax, ...) # more custom args ax.set_title(title)

fig, axes = plt.subplots(nrows=4, ncols=2, ...) for index, ax in np.ndenumerate(axes):

there are various ways to do this part, index in this case is a tuple (ie (0, 0))

plot_function(ds['varname'].isel(time=index), ax=ax, title=index, ...)

fig.suptitle('Super Title') fig.save(...)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/NCAR/ctsm_py/issues/24?email_source=notifications&email_token=AB5IWJHD62ZY7R7GIJSEUX3RBXMBDA5CNFSM4KREELB2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOELEZ3FI#issuecomment-583638421, or unsubscribe https://github.com/notifications/unsubscribe-auth/AB5IWJEM7EVS6N5A6G5AHT3RBXMBDANCNFSM4KREELBQ .

-- Will Wieder Project Scientist CGD, NCAR 303-497-1352

jhamman commented 4 years ago

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(14,12))

I think you want to breakdown which parameters go on the subplot and which ones go on the plot itself:

projection=ccrs.Robinson()   # goes on the subplot
transform=ccrs.PlateCarree()  # goes to the plot function

The way the subplots function works is that you will pass in the arguments required for each subplot via the subplot_kw keyword argument:

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(14,12), subplot_kw=dict(projection=ccrs.Robinson()))

plt.pcolormesh(..., ax=ax, transform=ccrs.PlateCarree())
wwieder commented 4 years ago

sorry where does the plt.pcolormesh bit go? your previous suggested had me using the xarray.plot function instead?

currently I'm looking at this:

def plot_function(da, ax=None, title=None): '''a function to make one subplot''' if ax is None: ax = plt.gca() da.plot(ax=ax) # more custom args ax.set_title(title)

On Thu, Feb 13, 2020 at 1:56 PM Joe Hamman notifications@github.com wrote:

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(14,12))

I think you want to breakdown which parameters go on the subplot and which ones go on the plot itself:

projection=ccrs.Robinson() # goes on the subplot transform=ccrs.PlateCarree() # goes to the plot function

The way the subplots function works is that you will pass in the arguments required for each subplot via the subplot_kw keyword argument:

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(14,12), subplot_kw=dict(projection=ccrs.Robinson()))

plt.pcolormesh(..., ax=ax, transform=ccrs.PlateCarree())

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/NCAR/ctsm_py/issues/24?email_source=notifications&email_token=AB5IWJDP4PDJFBYSVGEOJFDRCWXZRA5CNFSM4KREELB2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOELWSRSA#issuecomment-585967816, or unsubscribe https://github.com/notifications/unsubscribe-auth/AB5IWJBP7YT67PGPCIL5F7DRCWXZRANCNFSM4KREELBQ .

-- Will Wieder Project Scientist CGD, NCAR 303-497-1352

jhamman commented 4 years ago

sorry... the pcolormesh line is basically the same as the the DataArray.plot method call:

plt.pcolormesh <->  da.plot