jbusecke / xmovie

A simple way of creating movies from xarray objects
https://xmovie.readthedocs.io/
MIT License
250 stars 38 forks source link

Farewell to my most infamous package #163

Open jbusecke opened 1 month ago

jbusecke commented 1 month ago

Hey everyone,

it is with a somewhat heavy heart that I have to announce that I am planning to retire this repo unless somebody else wants to take over the maintenance.

I have not had time to adequately maintain things here, and I wanted to apologize for the long wait times and unsolved issues/PRs that were a consequence of that.

Software maintenance is hard work, and even though I have made some of my most beloved animations with this package I actually believe there are now better options out there, and it presents a lot of overhead to maintain the custom logic here.

My current plan here is:

Thank you all for working and using this silly named package! Please let me know what you think about the plans here.

The alternatives I have in mind:

FuncAnimation Example

Example animation that overlays some contours over color on a "rotating" cartopy projection and produces this: mymovie

import xarray as xr
import numpy as np

x = xr.DataArray(np.arange(360), dims=['x'])
y = xr.DataArray(np.arange(-90, 90), dims=['y'])
data_a = xr.DataArray(np.random.rand(360, 180, 100), dims=['x', 'y', 'time'], coords={'x':x, 'y':y}) * np.sin(np.deg2rad(y)*5)
data_b = data_a * np.cos(np.deg2rad(x))
ds = xr.Dataset({'a':data_a, 'b':data_b})

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
from matplotlib.animation import FuncAnimation

levels = [0.05, 0.95]
colors = ['orange']
plot_kwargs = dict(transform=ccrs.PlateCarree(), x='x', y='y')

def frame_to_lon_lat(frame, ds):
    # simples linear scaling. You can be much fancier here and add ramps, stops, etc...
    lon_range = np.linspace(0,360, len(ds.time))
    lat_range = np.linspace(0,180, len(ds.time))
    return lon_range[frame], lat_range[frame] 

# make initial figure
init_lon, _ = frame_to_lon_lat(0, ds)
fig, ax = plt.subplots(subplot_kw={'projection':ccrs.Robinson(central_longitude=init_lon)})

# # make initial figure
# fig, ax = plt.subplots()

# ax = plt.gca()
ds_frame = ds.isel(time=0)
mesh = ds_frame.a.plot(vmax=1, **plot_kwargs)
contour = ds_frame.b.plot.contour(colors=colors,levels=levels, add_colorbar=False, **plot_kwargs)
pp=[mesh, contour]
ax.coastlines()

def update_plot_frame(frame, ds, ax):
    # You can probably update these more efficiently by just replacing the mesh.properties()['data'] but 
    # lets use the easiest thing for now
    # just make some new mesh and update the old one from that
    ds_frame = ds.isel(time=frame).squeeze()

    # How do i remove the mesh?
    # seems like I do not have to?
    pp[0].remove()

    # the contours need to be removed (otherwise they will all overplot each other)
    pp[1].remove()

    # # set projection to rotate
    lon_frame, _ = frame_to_lon_lat(frame, ds)
    ax.projection = ccrs.Robinson(central_longitude=lon_frame)

    pp[0] = ds_frame.a.plot(vmax=1, add_colorbar=False, **plot_kwargs)
    pp[1] = ds_frame.b.plot.contour(colors=colors,levels=levels, add_colorbar=False, **plot_kwargs)
    return pp

fa = FuncAnimation(fig, update_plot_frame, 200, fargs=[ds, ax])
fa.save("bye_bye_xmovie.gif")
tomchor commented 1 month ago

Sad to read this announcement!

For me the simplicity of using xarray to write images in parallel and string them together is unparalleled. Every other alternative that I've tried to use either ends up trying to reinvent the wheel in some way or I end up having to write too much code, so maintenance here will be missed.

FYI, a few months ago I actually forked this repo with a different name just to keep things functional and deal with some issues that weren't getting responses here: https://github.com/tomchor/xanimations. I'm not planning on adding features, just keep things from breaking. That said, people are obviously welcome to use that and if you want write access to that repo to help with development, let me know and I'd be glad to give it.

Adding to the list of alternatives, I've used hvplot a few times before and it's really good for interactively investigating data. It also has very a handy xarray API. The one issue with it (as a potential replacement for xmovie) is that it's really made to be an interactive exploration package using bokeh as a backend. Last I checked it could export things as an mp4, but it's really not meant for that, so sometimes the export doesn't go smoothly. But hey, if you want to do some interactive plotting, this is definitely a great option.

jbusecke commented 1 month ago

Thanks for the kind words @tomchor. If you would be willing to maintain here, I am happy to make you an admin (you could merge in the changes from xanimations, and maybe consider a name change?).

Also happy to have a quick chat about potential to keep things alive here, but maybe just prune out some of the functionality? Or even refactor on top of FuncAnimation... ah geez now I am nerd sniping myself haha. But either way, I just want to do what is best for the users, while freeing up some of my time. Let me know.