Skip to content

Commit d3b156a

Browse files
committed
repro
1 parent ce226fa commit d3b156a

2 files changed

Lines changed: 168 additions & 0 deletions

File tree

advanced/backends/imageee.py

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# %% [markdown]
2+
# # Create your own Xarray Backend
3+
# In this lesson, we will learn about and how to create your own custom xarray backend
4+
#
5+
# :::{admonition} Learning Goals
6+
# - Learn about xarray's support for custom backends
7+
# - Learn how to use a custom `imageio` backend to open and manipulate GIFs
8+
# - Learn how to extend the `imagegio` backend to write out a GIF
9+
# :::
10+
#
11+
# ## Why should you create your own Xarray backend?
12+
#
13+
# - Allows you to use xarray's interface
14+
# - Attribute-like syntax, dict-like syntax and label based indexing
15+
# - You don’t need to integrate any code in Xarray
16+
# - Easy and fast!
17+
#
18+
19+
# %% [markdown]
20+
# ## Setting up the BackendEntrypoint
21+
#
22+
# To set up a `BackendEntrypoint` we can implement a subclass of `BackendEntrypoint` and expose the `open_dataset` method to it. For this tutorial we have the `ImageIOBackend` already defined but we will extend the functionally to write GIFS.
23+
24+
# %%
25+
image_path = "io.gif"
26+
27+
# %% [markdown]
28+
# We can write a simple image reader function that we can then plug into our `MyBackendEntrypoint` class. For this example we are going to use `imageio` an image reader and writer library. With `imageio` you can read an image file with `iio.imopen`
29+
#
30+
# :::{note}
31+
# The `ImageIOBackend` also defines a `ImageIOBackendArray` with basic indexing.
32+
# :
33+
34+
# %%
35+
import imageio as iio
36+
from xarray.backends import BackendEntrypoint
37+
38+
39+
def imageio_open(
40+
filename_or_obj,
41+
):
42+
img = iio.imopen(filename_or_obj, io_mode="r")
43+
return img.read()
44+
45+
46+
class MyImageReader(BackendEntrypoint):
47+
def open_dataset(
48+
self,
49+
filename_or_obj,
50+
*,
51+
drop_variables=None,
52+
):
53+
return imageio_open(filename_or_obj)
54+
55+
56+
type(MyImageReader().open_dataset(image_path))
57+
58+
# %% [markdown]
59+
# ## Reading image data
60+
#
61+
# Lets use our `ImageIOBackend` to open a GIF.
62+
#
63+
64+
# %%
65+
import xarray as xr
66+
from imageio_ import ImageIOBackend
67+
68+
gif_ds = xr.open_dataset(image_path, engine=ImageIOBackend)
69+
70+
# %% [markdown]
71+
# ### Examining our image dataset
72+
#
73+
# Since our image is a `Dataset` object we can use xarray's interface for `Dataset` objects.
74+
#
75+
# Let's try listing all of the variables, dimensions and selecting data
76+
77+
# %%
78+
79+
# %% [markdown]
80+
# We can list our dimensions
81+
82+
# %%
83+
84+
# %% [markdown]
85+
# Let's try getting our `DataArray`
86+
87+
# %%
88+
89+
# %% [markdown]
90+
# ## GIF metadata
91+
# We can examine, update and add metadata to our `Dataset` object.
92+
#
93+
# We can examine the attributes in our GIF "data" variable with the `.attrs` method
94+
95+
# %%
96+
97+
# %% [markdown]
98+
# ## Exercise
99+
100+
# %% [markdown]
101+
# ::::{admonition} Exercise
102+
# :class: tip
103+
#
104+
# Can you add a new attribute to our GIF "data" variable called "fps". This is the frames per second we can write our GIF to. You can set it to any value.
105+
#
106+
# :::{admonition} Solution
107+
# :class: dropdown
108+
#
109+
# ```python
110+
# gif_ds.data.attrs['fps'] = 100
111+
# ```
112+
# :::
113+
# ::::
114+
115+
# %% [markdown]
116+
# ### GIF writer
117+
# We can extend our backend with an GIF writer. Here we use `matplotlib`'s animation functions and `PillowWriter`
118+
119+
# %%
120+
import matplotlib.animation as animation
121+
import matplotlib.pyplot as plt
122+
import numpy as np
123+
from imageio_ import ImageIOBackend
124+
from matplotlib.animation import PillowWriter
125+
126+
127+
class SimpleImageWriter(ImageIOBackend):
128+
def to_giff(
129+
self,
130+
dataset,
131+
variable,
132+
time_dim,
133+
out_filename,
134+
**kwargs,
135+
):
136+
fig, ax = plt.subplots()
137+
138+
frames = []
139+
variable_da = dataset[variable]
140+
X, Y = np.meshgrid(variable_da.height, variable_da.width)
141+
for time in variable_da[time_dim]:
142+
variable_da = variable_da.transpose("time", "width", "height", "color")
143+
to_plot = ax.pcolormesh(
144+
X,
145+
Y,
146+
variable_da.sel(time=time).isel(color=0),
147+
# animated=True,
148+
shading="auto",
149+
**kwargs,
150+
)
151+
152+
frames.append([to_plot])
153+
154+
try:
155+
writer = PillowWriter(fps=variable_da.attrs["fps"], **kwargs)
156+
except KeyError:
157+
writer = PillowWriter(fps=50, **kwargs)
158+
159+
ani = animation.ArtistAnimation(fig, frames, blit=True, repeat=True)
160+
ani.save(filename=out_filename, writer=writer)
161+
162+
163+
# %%
164+
img_writer = SimpleImageWriter()
165+
img_writer.to_giff(gif_ds, "data", "time", "io_writer.gif")
166+
167+
# %%

task.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
`cd` into `advanced/backends` and run `pixi run python imageee.py`. The bug you'll encounter is due to the implementation of the function `basic_indexing` in `imageio_.py`. Fix it.

0 commit comments

Comments
 (0)