-
Notifications
You must be signed in to change notification settings - Fork 38
Suggestion for xarray integration #1
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| import numpy as np | ||
| import xarray as xr | ||
| import matplotlib.pyplot as plt | ||
| from animatplot.xanim import animated_plot | ||
|
|
||
|
|
||
| # Create data set | ||
| x = np.linspace(-2, 2, 41) | ||
| y = np.linspace(-2, 2, 41) | ||
| t = np.linspace(0, 2*np.pi, 30) | ||
| X, Y, T = np.meshgrid(x, y, t) | ||
| data = np.sin(X*X+Y*Y-T) | ||
| da = xr.DataArray(data, coords=[('horizontal position', x), | ||
| ('vertical position', y), | ||
| ('time', t)]) | ||
|
|
||
| # Create animated 2D plot | ||
| anim, block, timeline = animated_plot(da) | ||
| anim.controls() | ||
| anim.save_gif('../xarray_imshow') | ||
| plt.show() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| import animatplot as amp | ||
| import xarray as xr | ||
|
|
||
|
|
||
| def animated_plot(da, anim_over='__guess__', x='x', y='y', plot_type='imshow', fps=10): | ||
| """ | ||
| Function to plot an animated plot from an xarray DataArray. | ||
|
|
||
| The intention is that this would form the basis of a xr.DataArray.plot.animate() method. | ||
| """ | ||
|
|
||
| if not isinstance(da, xr.DataArray): | ||
| raise TypeError('First argument must be an xarray DataArray object') | ||
|
|
||
| timeline, evolving_coord = _timeline_from_coords(da.coords, anim_over, fps) | ||
| t_axis = da.dims.index(evolving_coord) | ||
|
|
||
| if len(da.dims) is not 3: | ||
| raise NotImplementedError('Currently only plots 2D dataarrays') | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this say "only plots 3D dataarrays"?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well it currently only plots 2D DataArrays which evolve over a 3rd dimension... Not sure what the clearest way to write that is.
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Only animates 3D arrays"? |
||
|
|
||
| if plot_type is 'imshow': | ||
| # TODO ideally the blocks method should call the xarray plotting method da.plot.imshow() | ||
| print(da.values.shape) | ||
| print(t_axis) | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove the print statements please |
||
| block = amp.blocks.Imshow(da.values, t_axis=t_axis) | ||
| else: | ||
| # TODO deal with other kinds of plot (lines, quiver...) here | ||
| raise NotImplementedError('Currently only plots using imshow') | ||
|
|
||
| # TODO if we can't call the xarray plotting method directly then add titles, axes labels etc here | ||
| anim = amp.Animation([block]) | ||
|
|
||
| return anim, block, timeline | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I really like the way you return things here. It bodes well for future functions like this. But, I sort of think it should be a list of blocks (because future convenience functions could return multiple blocks). OTOH, advanced tuple unpacking is a thing. OTOH, is also possible. That's a tough decision. Keep with this and I'll make a decision befor 0.3 release.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I personally like the variant more, but this is something that would be easy to change anyway.
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Easy to change, but annoying to change after release. Ya, make it return a list of blocks. It will be easier to explain in the docs too. |
||
|
|
||
|
|
||
| def _timeline_from_coords(coords, anim_over, fps): | ||
| """Create the animatplot Timeline object from the information in the coordinates attribute of the DataArray.""" | ||
|
|
||
| # Determine coordinate over which plot should be animated | ||
| if anim_over is '__guess__': | ||
| # Attempt to automatically determine coordinate over which to animate plot | ||
| guesses = {'t', 'T', 'time', 'Time'} | ||
| matches = list(guesses & set(coords)) | ||
| if len(matches) is 1: | ||
| evolving_coord = matches[0] | ||
| else: | ||
| raise ValueError('Could not automatically determine coordinate to animate over - ' | ||
| 'multiple possibilities found: ' + str(matches)) | ||
| elif anim_over in coords: | ||
| evolving_coord = anim_over | ||
| else: | ||
| raise ValueError('Could not determine coordinate to animate over') | ||
|
|
||
| print(evolving_coord) | ||
| t = coords[evolving_coord].values | ||
|
|
||
| # TODO Attempt to determine units from metadata in dataarray attributes, according to CF conventions | ||
|
|
||
| timeline = amp.Timeline(t, units=None, fps=fps) | ||
|
|
||
| return timeline, evolving_coord | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The core of xarray is still a numpy array. I sort of think that
anim_overshould bet_axis. That said, the xarray docs keep using the term "coods", so maybet_coord? I think I prefert_axisfor api consistency. OTOH, t_axis is usually an integer....Either way, the default value should be
None, and you can checkAlso, could you add the numpydoc style parameter to the docstring? Looks like:
You can read about numpydoc here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would defeat a lot of the purpose of using xarray. The point of xarray is that the dimensions of the data are labelled in a human-readable manner, and you can interact with the data without specifying seemingly-arbitrary numbers (as in
axis=0).The xarray docs use the term
coordbecause that is one of the fundamental objects in xarray, and it's not the same thing as a dimension (which is not the same thing as an axis!).To be honest when I first started using xarray I was like "is all this extra jargon really necessary?", but having used it for a while it makes way more sense.
Yep you're right.
I didn't use the word "axis" because that implies an integer numpy axis, which is what xarray allows you move past. I didn't use the letter "t" because
t_axisonly represents time in the sense that a gif evolves over real time. In general thent_axiscould refer to something which isn't time at all. For example, I could have a DataArray of temperature T(x,y,z,t) in the atmosphere for each day in a month. If I want to plot a gif of the variation of temperature with height ona particular day then it would be much clearer to be able to writeanimate(da, anim_over='z')or evenanimate(da, anim_over='height')then to writeanimate(da, t_axis='z')(or worse,animate(da, t_axis=3). I chose "anim_over" because it's literally the dimension of the data over which the gif is to be animated. What do you think?Yep, I am more than happy to conform to animatplot's commenting and documenting style (and write some unit tests), I just wanted to get the general idea of the layout worked out first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok,
anim_overit is.