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

Allow passing figure handle to FacetGrid #7401

Open
daliagachc opened this issue Dec 24, 2022 · 6 comments
Open

Allow passing figure handle to FacetGrid #7401

daliagachc opened this issue Dec 24, 2022 · 6 comments

Comments

@daliagachc
Copy link

daliagachc commented Dec 24, 2022

Is your feature request related to a problem?

Sometimes i need to combine xarray Facet grids with other ax plots. It would be amazing if I could pass a created figure to the plot function. Event better a subfigure so that the possibilities are infinite!

Describe the solution you'd like

for example:

  da = xr.tutorial.open_dataset("air_temperature")['air']
  f = plt.figure()
  (
      da
      [{'time':[1,2,4]}]
      .plot.contourf(col='time',fig = f)
  )

Describe alternatives you've considered

an alternative is to manually to all plots in a created figure, but this becomes cumbersome.
I quickly checked the source code, and it does not seem very difficult to implement. mostly a modification to the
get_axis function so that it accepts an already created figure. I managed to quickly make it work in seaborn (see image below)

image

Additional context

No response

@mathause
Copy link
Collaborator

I think the usual workflow is to create the figure with gridspec and then update the created subplots and figure. Is there something that is not possible if done this way around?

@daliagachc
Copy link
Author

thanks for the reply. Somehow i don't find an elegant way that does not involve many loops and hoops. Lets consider the following short example:
I want to produce a figure that takes the xr.tutorial.open_dataset("air_temperature") and produces a mean grouped by season and hour in the same figure:
image
Creating the top and bottom rows independently is super efficient with xarray:

import xarray as xr
import matplotlib.pyplot as plt

da = xr.tutorial.open_dataset("air_temperature")['air']

(
    da.groupby(da['time'].dt.season)
    .mean()
    .plot(col='season')
)

(
    da.groupby(da['time'].dt.hour)
    .mean()
    .plot(col='hour')
)

image

but combining both seems quite complicated to me. I wish I could pass a subfigure to the plot function in the following way

fig:plt.Figure = plt.figure()
(fig_top,fig_bot) = fig.subfigures(2,1)

(
    da.groupby(da['time'].dt.season)
    .mean()
    .plot(col='season',fig=fig_top)
)

(
    da.groupby(da['time'].dt.hour)
    .mean()
    .plot(col='hour', fig=fig_bot)
)

image

maybe I am missing a smart way of doing this?
cheers

@daliagachc
Copy link
Author

I have actually manage to make it work with minimal modification of the source xarray code:

import xarray as xr
import matplotlib.pyplot as plt
import matplotlib as mpl


def _pass(*_,**__):
    pass

mpl.figure.SubFigure.tight_layout = _pass

da = xr.tutorial.open_dataset("air_temperature")['air']
fig:plt.Figure = plt.figure(
    constrained_layout=True,
    figsize = (2*4,2*2)
)

(fig_top,fig_bot) = fig.subfigures(2,1)

(
    da.groupby(da['time'].dt.season)
    .mean()
    .plot(col='season',fig=fig_top)
)

(
    da.groupby(da['time'].dt.hour)
    .mean()
    .plot(col='hour', fig=fig_bot)
)

image

@daliagachc daliagachc changed the title include that ability to pass an already created figure as a parameter to the many plot methods when plotting with xarray allow to pass a mpl.figure as a parameter. This adds a lot of flexibility when combined with mpl's new mpl.figure.subfigure class. Dec 25, 2022
@mathause
Copy link
Collaborator

Good point. Combining two FacetGrids is a good use case. My intuition would be to allow passing exactly the correct number of axes and not the figure. But then I have not heard from subfigure before now and this may also be a valid option.

f, axs = plt.subplots(2, 4)
da1.plot(col='season', ax=axs[0, :])
da2.plot(col='season', ax=axs[1, :])

@dcherian dcherian changed the title when plotting with xarray allow to pass a mpl.figure as a parameter. This adds a lot of flexibility when combined with mpl's new mpl.figure.subfigure class. Allow passing figure handle to FacetGrid Jan 17, 2023
@dcherian
Copy link
Contributor

dcherian commented Jan 17, 2023

Seems like a good addition to me.

I'm not sure about passing Axes handles. IIRC FacetGrid does call a bunch of Figure methods, so there may be unintended consequences

@tomchor
Copy link
Contributor

tomchor commented Oct 25, 2023

Is this still on the table? I think being able to pass a figure handle would be good for all the reasons mentioned above, but also it would allow us to use xmovie to plot FacetGrids out of the box since (if I'm not missing anything) xmovie asks only that fig gets passed along to the plotting function (that's probably not to waste time creating several figures per animation). At the moment this is impossible with FacetGrid.

CC @jbusecke

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants