|
2 | 2 | import matplotlib |
3 | 3 | import matplotlib.pyplot as plt |
4 | 4 | import warnings |
5 | | - |
| 5 | +from mpl_toolkits.axes_grid1 import make_axes_locatable |
6 | 6 | import animatplot as amp |
7 | 7 |
|
8 | 8 | from .utils import ( |
@@ -679,3 +679,203 @@ def animate_line( |
679 | 679 | return anim |
680 | 680 |
|
681 | 681 | return line_block |
| 682 | + |
| 683 | +def animate_polygon( |
| 684 | + da, |
| 685 | + ax=None, |
| 686 | + cax=None, |
| 687 | + cmap="viridis", |
| 688 | + norm=None, |
| 689 | + logscale=False, |
| 690 | + antialias=False, |
| 691 | + vmin=None, |
| 692 | + vmax=None, |
| 693 | + extend="neither", |
| 694 | + add_colorbar=True, |
| 695 | + colorbar_label=None, |
| 696 | + separatrix=True, |
| 697 | + separatrix_kwargs={"color": "white", "linestyle": "-", "linewidth": 2}, |
| 698 | + targets=False, |
| 699 | + add_limiter_hatching=False, |
| 700 | + grid_only=False, |
| 701 | + linewidth=0, |
| 702 | + linecolor="black", |
| 703 | +): |
| 704 | + """ |
| 705 | + Nice looking 2D plots which have no visual artifacts around the X-point. |
| 706 | +
|
| 707 | + Parameters |
| 708 | + ---------- |
| 709 | + da : xarray.DataArray |
| 710 | + A 2D (x,y) DataArray of data to plot |
| 711 | + ax : Axes, optional |
| 712 | + Axes to plot on. If not provided, will make its own. |
| 713 | + cax : Axes, optional |
| 714 | + Axes to plot colorbar on. If not provided, will plot on the same axes as the plot. |
| 715 | + cmap : str or matplotlib.colors.Colormap, default "viridis" |
| 716 | + Colormap to use for the plot |
| 717 | + norm : matplotlib.colors.Normalize, optional |
| 718 | + Normalization to use for the color scale |
| 719 | + logscale : bool, default False |
| 720 | + If True, use a symlog color scale |
| 721 | + antialias : bool, default False |
| 722 | + Enables antialiasing. Note: this also shows mesh cell edges - it's unclear how to disable this. |
| 723 | + vmin : float, optional |
| 724 | + Minimum value for the color scale |
| 725 | + vmax : float, optional |
| 726 | + Maximum value for the color scale |
| 727 | + extend : str, optional, default "neither" |
| 728 | + Extend the colorbar. Options are "neither", "both", "min", "max" |
| 729 | + add_colorbar : bool, default True |
| 730 | + Enable colorbar in figure? |
| 731 | + colorbar_label : str, optional |
| 732 | + Label for the colorbar |
| 733 | + separatrix : bool, default True |
| 734 | + Add lines showing separatrices |
| 735 | + separatrix_kwargs : dict |
| 736 | + Keyword arguments to pass custom style to the separatrices plot |
| 737 | + targets : bool, default True |
| 738 | + Draw solid lines at the target surfaces |
| 739 | + add_limiter_hatching : bool, default True |
| 740 | + Draw hatched areas at the targets |
| 741 | + grid_only : bool, default False |
| 742 | + Only plot the grid, not the data. This sets all the polygons to have a white face. |
| 743 | + linewidth : float, default 0 |
| 744 | + Width of the gridlines on cell edges |
| 745 | + linecolor : str, default "black" |
| 746 | + Color of the gridlines on cell edges |
| 747 | + """ |
| 748 | + |
| 749 | + if ax is None: |
| 750 | + fig, ax = plt.subplots(figsize=(3, 6), dpi=120) |
| 751 | + else: |
| 752 | + fig = ax.get_figure() |
| 753 | + |
| 754 | + if cax is None: |
| 755 | + cax = ax |
| 756 | + |
| 757 | + if vmin is None: |
| 758 | + vmin = np.nanmin(da.values) |
| 759 | + |
| 760 | + if vmax is None: |
| 761 | + vmax = np.nanmax(da.max().values) |
| 762 | + |
| 763 | + if colorbar_label is None: |
| 764 | + if "short_name" in da.attrs: |
| 765 | + colorbar_label = da.attrs["short_name"] |
| 766 | + elif da.name is not None: |
| 767 | + colorbar_label = da.name |
| 768 | + else: |
| 769 | + colorbar_label = "" |
| 770 | + |
| 771 | + if "units" in da.attrs: |
| 772 | + colorbar_label += f" [{da.attrs['units']}]" |
| 773 | + |
| 774 | + if "Rxy_lower_right_corners" in da.coords: |
| 775 | + r_nodes = [ |
| 776 | + "R", |
| 777 | + "Rxy_lower_left_corners", |
| 778 | + "Rxy_lower_right_corners", |
| 779 | + "Rxy_upper_left_corners", |
| 780 | + "Rxy_upper_right_corners", |
| 781 | + ] |
| 782 | + z_nodes = [ |
| 783 | + "Z", |
| 784 | + "Zxy_lower_left_corners", |
| 785 | + "Zxy_lower_right_corners", |
| 786 | + "Zxy_upper_left_corners", |
| 787 | + "Zxy_upper_right_corners", |
| 788 | + ] |
| 789 | + cell_r = np.concatenate( |
| 790 | + [np.expand_dims(da[x], axis=2) for x in r_nodes], axis=2 |
| 791 | + ) |
| 792 | + cell_z = np.concatenate( |
| 793 | + [np.expand_dims(da[x], axis=2) for x in z_nodes], axis=2 |
| 794 | + ) |
| 795 | + else: |
| 796 | + raise Exception("Cell corners not present in mesh, cannot do polygon plot") |
| 797 | + |
| 798 | + Nx = len(cell_r) |
| 799 | + Ny = len(cell_r[0]) |
| 800 | + patches = [] |
| 801 | + |
| 802 | + # https://matplotlib.org/2.0.2/examples/api/patch_collection.html |
| 803 | + |
| 804 | + idx = [np.array([1, 2, 4, 3, 1])] |
| 805 | + patches = [] |
| 806 | + for i in range(Nx): |
| 807 | + for j in range(Ny): |
| 808 | + p = matplotlib.patches.Polygon( |
| 809 | + np.concatenate((cell_r[i][j][tuple(idx)], cell_z[i][j][tuple(idx)])) |
| 810 | + .reshape(2, 5) |
| 811 | + .T, |
| 812 | + fill=False, |
| 813 | + closed=True, |
| 814 | + facecolor=None, |
| 815 | + ) |
| 816 | + patches.append(p) |
| 817 | + |
| 818 | + norm = _create_norm(logscale, norm, vmin, vmax) |
| 819 | + |
| 820 | + if grid_only is True: |
| 821 | + cmap = matplotlib.colors.ListedColormap(["white"]) |
| 822 | + polys = matplotlib.collections.PatchCollection( |
| 823 | + patches, |
| 824 | + alpha=1, |
| 825 | + norm=norm, |
| 826 | + cmap=cmap, |
| 827 | + antialiaseds=antialias, |
| 828 | + edgecolors=linecolor, |
| 829 | + linewidths=linewidth, |
| 830 | + joinstyle="bevel", |
| 831 | + ) |
| 832 | + |
| 833 | + colors = da.data[0,:,:].flatten() |
| 834 | + polys.set_array(colors) |
| 835 | + ax.add_collection(polys) |
| 836 | + |
| 837 | + #def update(frame): |
| 838 | + # # for each frame, update the data stored on each artist. |
| 839 | + # colors = da.data[frame,:,:].flatten() |
| 840 | + # polys.set_array(colors) |
| 841 | + # return polys |
| 842 | + def update(frame): |
| 843 | + colors = da.data[frame,:,:].flatten() |
| 844 | + polys.set_array(colors) |
| 845 | + print(da.data[0,0,0].compute()) |
| 846 | + print(frame) |
| 847 | + #update(0) |
| 848 | + |
| 849 | + if add_colorbar: |
| 850 | + # This produces a "foolproof" colorbar which |
| 851 | + # is always the height of the plot |
| 852 | + # From https://joseph-long.com/writing/colorbars/ |
| 853 | + divider = make_axes_locatable(ax) |
| 854 | + cax = divider.append_axes("right", size="5%", pad=0.05) |
| 855 | + fig.colorbar(polys, cax=cax, label=colorbar_label, extend=extend) |
| 856 | + cax.grid(which="both", visible=False) |
| 857 | + |
| 858 | + |
| 859 | + |
| 860 | + ax.set_aspect("equal", adjustable="box") |
| 861 | + ax.set_xlabel("R [m]") |
| 862 | + ax.set_ylabel("Z [m]") |
| 863 | + ax.set_ylim(cell_z.min(), cell_z.max()) |
| 864 | + ax.set_xlim(cell_r.min(), cell_r.max()) |
| 865 | + ax.set_title(da.name) |
| 866 | + |
| 867 | + if separatrix: |
| 868 | + plot_separatrices(da, ax, x="R", y="Z", **separatrix_kwargs) |
| 869 | + |
| 870 | + if targets: |
| 871 | + plot_targets(da, ax, x="R", y="Z", hatching=add_limiter_hatching) |
| 872 | + |
| 873 | + #print(np.shape(da.data)) |
| 874 | + #colors = da.data[0,:,:].flatten() |
| 875 | + #polys.set_array(colors) |
| 876 | + #ax.add_collection(polys) |
| 877 | + |
| 878 | + |
| 879 | + ani = matplotlib.animation.FuncAnimation(fig=fig, func=update, frames=np.shape(da.data)[0], interval=3000) |
| 880 | + return ani |
| 881 | + |
0 commit comments