diff --git a/CHANGELOG.md b/CHANGELOG.md index bd1e54d5..197cba6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/). - refactor of artists.quick1D and artists.quick2D - quick2D and quick1D will not force `autosave=True` if the number of figures is large. Instead, interactive plotting will be truncated if the number of figures is large. - artists now gets turbo colormap straight from matplotlib +- deprecating `artists.plot_colorbar`: instead use matplotlib's `colorbar` implementations directly - artists.interact2D now returns a `types.SimpleNamespace` object (rather than a tuple) ## [3.5.2] diff --git a/WrightTools/artists/_base.py b/WrightTools/artists/_base.py index cddc6a26..9714fe20 100644 --- a/WrightTools/artists/_base.py +++ b/WrightTools/artists/_base.py @@ -154,7 +154,8 @@ def _parse_plot_args(self, *args, **kwargs): data=data, channel_index=channel_index, dynamic_range=dynamic_range, **kwargs ) if plot_type == "contourf": - if "levels" not in kwargs.keys(): + if ("levels" not in kwargs.keys()) and ("norm" not in kwargs): + # because of _parse_limits, we ensur we always have vmin and vmax to use kwargs["levels"] = np.linspace(kwargs["vmin"], kwargs["vmax"], 256) elif plot_type == "contour": if "levels" not in kwargs.keys(): diff --git a/WrightTools/artists/_helpers.py b/WrightTools/artists/_helpers.py index 9b2e6a5c..1d019681 100644 --- a/WrightTools/artists/_helpers.py +++ b/WrightTools/artists/_helpers.py @@ -30,18 +30,19 @@ __all__ = [ "_title", + "axis_label_from_data", "add_sideplot", "corner_text", "create_figure", "diagonal_line", "get_scaled_bounds", "norm_from_channel", - "pcolor_helper", - "plot_colorbar", + "pcolor_helper", # deprecation imminent + "plot_colorbar", # to be deprecated (use mpl methods) "plot_margins", - "plot_gridlines", + "plot_gridlines", # to be deprecated (use mpl methods, styles) "savefig", - "set_ax_labels", + "set_ax_labels", # to be deprecated (use mpl methods, styles) "set_ax_spines", "set_fig_labels", "subplots_adjust", @@ -53,6 +54,34 @@ # --- functions ----------------------------------------------------------------------------------- +def axis_label_from_data(data, ax=None, cax=None, which="both", channel_index=0): + """Apply x and/or y labels to axes. + Parameters + ---------- + data : WrightTools.Data + data from which to extract the label(s) + ax : Axis object (optional) + Default is current axis + autolabel : {'none', 'both', 'x', 'y'} (optional) + Label(s) to apply from data. Default is none. + channel_index : integer (optional) + Channel index. Default is 0. Only important for 2D data + """ + if ax is None: + ax = plt.gca() + if which in ["both", "x"]: + xlabel = data.axes[0].label + ax.set_xlabel(xlabel) + if which in ["both", "y"]: + if data.ndim == 1: + ylabel = data.channels[channel_index].label + elif data.ndim == 2: + ylabel = data.axes[1].label + else: + raise wt_exceptions.DimensionalityError("<=3", data.ndim) + ax.set_ylabel(ylabel) + + def _title(fig, title, subtitle="", *, margin=1, fontsize=20, subfontsize=18): """Add a title to a figure. @@ -657,6 +686,11 @@ def plot_colorbar( matplotlib.colorbar.ColorbarBase object The created colorbar. """ + warnings.warn( + "`plot_colorbar` is planned for deprecation. " + + "Use `matplotlib.pyplot.colorbar` instead.", + wt_exceptions.VisibleDeprecationWarning, + ) # parse cax if cax is None: cax = plt.gca() @@ -807,6 +841,12 @@ def plot_gridlines(ax=None, c="grey", lw=1, diagonal=False, zorder=2, makegrid=T zorder : number (optional) zorder of plotted grid. Default is 2. """ + warnings.warn( + "``plot_gridlines`` is deprecated and will be removed in a future version. " + + "Use matplotlib's ``grid`` methods instead", + wt_exceptions.VisibleDeprecationWarning, + ) + # get ax if ax is None: ax = plt.gca() @@ -913,6 +953,11 @@ def set_ax_labels(ax=None, xlabel=None, ylabel=None, xticks=None, yticks=None, l -------- set_fig_labels """ + warnings.warn( + "``set_ax_labels`` is deprecated and will be removed in a future version. " + + "Use matplotlib's ``set_xlabel`` and ``set_ylabel`` methods instead", + wt_exceptions.VisibleDeprecationWarning, + ) # get ax if ax is None: ax = plt.gca() @@ -1024,14 +1069,8 @@ def set_fig_labels( for ax in fig.axes: if ax.is_sideplot: continue - try: - # [row|col]span were introduced in matplotlib 3.2 - # this try/except can be removed when supprot for mpl < 3.2 is dropped - rowNum = ax.get_subplotspec().rowspan.start - colNum = ax.get_subplotspec().colspan.start - except AttributeError: - rowNum = ax.rowNum - colNum = ax.colNum + rowNum = ax.get_subplotspec().rowspan.start + colNum = ax.get_subplotspec().colspan.start if row_start <= rowNum <= row_stop and col_start <= colNum <= col_stop: if colNum == col_start: set_ax_labels(ax=ax, ylabel=ylabel, yticks=yticks, label_fontsize=label_fontsize) @@ -1047,8 +1086,11 @@ def set_fig_labels( def subplots_adjust(fig=None, inches=1): - """Enforce margins for generated figure, starting at subplots. - .. note:: + """ + Enforce margins for generated figure, starting at subplots. + + Note + ---- You probably should be using wt.artists.create_figure instead. Parameters diff --git a/WrightTools/artists/_interact.py b/WrightTools/artists/_interact.py index 645ed8c9..35b40833 100644 --- a/WrightTools/artists/_interact.py +++ b/WrightTools/artists/_interact.py @@ -326,7 +326,9 @@ def interact2D( # colorbar ticks = current_state.norm.ticks ticklabels = gen_ticklabels(ticks, channel.signed) - colorbar = plot_colorbar(cax, cmap=cmap, label=channel.natural_name, ticks=ticks) + colorbar = fig.colorbar( + mappable=obj2D, cax=cax, cmap=cmap, label=channel.natural_name, ticks=ticks + ) colorbar.set_ticklabels(ticklabels) fig.canvas.draw_idle() diff --git a/WrightTools/data/_join.py b/WrightTools/data/_join.py index dc0a7fc5..9b272d37 100644 --- a/WrightTools/data/_join.py +++ b/WrightTools/data/_join.py @@ -26,7 +26,8 @@ def join( datas, *, atol=None, rtol=None, name="join", parent=None, method="first", verbose=True ) -> Data: - """Join a list of data objects into one data object. + """ + Join a list of data objects into one data object. The underlying dataset arrays are merged. Joined datas must have the same axes and axes order. diff --git a/WrightTools/datasets/__init__.py b/WrightTools/datasets/__init__.py index b29bd2f3..9fc58789 100644 --- a/WrightTools/datasets/__init__.py +++ b/WrightTools/datasets/__init__.py @@ -4,6 +4,7 @@ import pathlib +from types import SimpleNamespace from .. import kit as wt_kit @@ -17,8 +18,27 @@ # --- container class ----------------------------------------------------------------------------- -class DatasetContainer(object): - def _from_files(self, dirname, prefix=""): +BrunoldrRaman = SimpleNamespace() +Cary = SimpleNamespace() +COLORS = SimpleNamespace() +JASCO = SimpleNamespace() +KENT = SimpleNamespace() +LabRAM = SimpleNamespace() +ocean_optics = SimpleNamespace() +PyCMDS = SimpleNamespace() +Shimadzu = SimpleNamespace() +Solis = SimpleNamespace() +spcm = SimpleNamespace() +Tensor27 = SimpleNamespace() +wt5 = SimpleNamespace() + + +# --- fill ---------------------------------------------------------------------------------------- + + +def _populate_containers(): + + def _from_files(obj, dirname, prefix=""): """Add datasets from files in a directory. Parameters @@ -30,9 +50,9 @@ def _from_files(self, dirname, prefix=""): """ for p in (here / dirname).iterdir(): n = prefix + wt_kit.string2identifier(p.name.split(".")[0]) - setattr(self, n, p) + setattr(obj, n, p) - def _from_directory(self, dirname, prefix=""): + def _from_directory(obj, dirname, prefix=""): """Add dataset from files in a directory. Parameters @@ -44,55 +64,40 @@ def _from_directory(self, dirname, prefix=""): """ ps = list((here / dirname).iterdir()) n = prefix + wt_kit.string2identifier(dirname.name) - setattr(self, n, ps) - - -# --- fill ---------------------------------------------------------------------------------------- + setattr(obj, n, ps) + _from_files(BrunoldrRaman, here / "BrunoldrRaman") -BrunoldrRaman = DatasetContainer() -BrunoldrRaman._from_files(here / "BrunoldrRaman") + _from_files(Cary, "Cary") -Cary = DatasetContainer() -Cary._from_files("Cary") + _from_files(COLORS, here / "COLORS" / "v0.2", prefix="v0p2_") + _from_files(COLORS, here / "COLORS" / "v2.2", prefix="v2p2_") -COLORS = DatasetContainer() -COLORS._from_files(here / "COLORS" / "v0.2", prefix="v0p2_") -COLORS._from_files(here / "COLORS" / "v2.2", prefix="v2p2_") + _from_files(JASCO, "JASCO") -JASCO = DatasetContainer() -JASCO._from_files("JASCO") + _from_directory(KENT, here / "KENT" / "LDS821 TRSF") + _from_directory(KENT, here / "KENT" / "LDS821 DOVE") + _from_directory(KENT, here / "KENT" / "PbSe 2D delay B") -KENT = DatasetContainer() -KENT._from_directory(here / "KENT" / "LDS821 TRSF") -KENT._from_directory(here / "KENT" / "LDS821 DOVE") -KENT._from_directory(here / "KENT" / "PbSe 2D delay B") + _from_files(LabRAM, here / "LabRAM") -LabRAM = DatasetContainer() -LabRAM._from_files(here / "LabRAM") + _from_files(ocean_optics, "ocean_optics") -ocean_optics = DatasetContainer() -ocean_optics._from_files("ocean_optics") + _from_files(PyCMDS, "PyCMDS") -PyCMDS = DatasetContainer() -PyCMDS._from_files("PyCMDS") + _from_files(Shimadzu, "Shimadzu") -Shimadzu = DatasetContainer() -Shimadzu._from_files("Shimadzu") + _from_files(Solis, "Solis") -Solis = DatasetContainer() -Solis._from_files("Solis") + _from_files(spcm, "spcm") -spcm = DatasetContainer() -spcm._from_files("spcm") + _from_files(Tensor27, "Tensor27") -Tensor27 = DatasetContainer() -Tensor27._from_files("Tensor27") + _from_files(wt5, here / "wt5" / "v1.0.0", prefix="v1p0p0_") + _from_files(wt5, here / "wt5" / "v1.0.1", prefix="v1p0p1_") -wt5 = DatasetContainer() -wt5._from_files(here / "wt5" / "v1.0.0", prefix="v1p0p0_") -wt5._from_files(here / "wt5" / "v1.0.1", prefix="v1p0p1_") +_populate_containers() # --- pretty namespace ---------------------------------------------------------------------------- @@ -103,9 +108,12 @@ def _from_directory(self, dirname, prefix=""): "COLORS", "JASCO", "KENT", + "LabRAM", "ocean_optics", "PyCMDS", + "Shimadzu", "Solis", + "spcm", "Tensor27", "wt5", ] diff --git a/docs/api/WrightTools.artists.rst b/docs/api/WrightTools.artists.rst index 25ddce56..a0d49d51 100644 --- a/docs/api/WrightTools.artists.rst +++ b/docs/api/WrightTools.artists.rst @@ -23,7 +23,6 @@ WrightTools\.artists module interact2D overline_colors pcolor_helper - plot_colorbar plot_colormap_components plot_gridlines plot_margins diff --git a/docs/artists.rst b/docs/artists.rst index 343e6312..19859107 100644 --- a/docs/artists.rst +++ b/docs/artists.rst @@ -277,7 +277,6 @@ In addition, ``WrightTools`` defines some small helper functions for common task - Pairs well with :attr:`WrightTools.data.Constant.label` -- :meth:`~WrightTools.artists.plot_colorbar` Add a colorbar in a single function call - :meth:`~WrightTools.artists.set_fig_labels` Label axes in a whole row/column of a figure - Allows the use of slice objects to limit range affected @@ -311,7 +310,7 @@ In addition, ``WrightTools`` defines some small helper functions for common task # plot colormap cax = plt.subplot(gs[1:3, -1]) ticks = np.linspace(data.ai0.min(), data.ai0.max(), 11) - wt.artists.plot_colorbar(cax=cax, label="amplitude", cmap="default", ticks=ticks) + plt.colorbar(cax=cax, label="amplitude", cmap="default", ticks=ticks) # set axis labels wt.artists.set_fig_labels(xlabel=data.w1__e__wm.label, ylabel=data.d2.label, col=slice(0, 1)) diff --git a/docs/cli.rst b/docs/cli.rst index a88e8202..22cc72a4 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -14,6 +14,7 @@ wt-convert Use ``wt-convert`` to explore the WrightTools units system and the conversions of units. .. code-block:: shell + > wt-units 1330 nm wn 7692.3 wn 0.95372 eV diff --git a/docs/conf.py b/docs/conf.py index eb57526a..7efb4323 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -105,7 +105,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = "en" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -236,9 +236,11 @@ def reset_wt(gallery_conf, fname): # This is an awful hack because python does not allow unloading modules # This is, however, the same thing upstream sphinx-gallery does for # seaborn, so it's not _so_ bad I guess. 2019-04-07 KFS - for module in list(sys.modules.keys()): - if module.startswith("WrightTools.datasets"): - del sys.modules[module] + from WrightTools import datasets + + datasets_module = sys.modules.get("WrightTools.datasets") + if datasets_module is not None: + datasets._populate_containers() sphinx_gallery_conf = { @@ -247,6 +249,7 @@ def reset_wt(gallery_conf, fname): "gallery_dirs": "auto_examples", "backreferences_dir": os.path.join("gen_modules", "backreferences"), "reset_modules": ["matplotlib", reset_wt], + "reset_module_order": "before", } diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 0832a391..9087db34 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -360,7 +360,7 @@ To choose a specific time point, you can of course just make the chopping more s data = wt.open(p) data.transform('w1=wm', 'w2-wm', 'd2') data.convert('eV') - data1 = data.chop('w2', at={'w1=wm':[1.5, 'eV'], 'd2':[0, 'fs']})[0] + data1 = data.chop('w2-wm', at={'w1=wm':[1.5, 'eV'], 'd2':[0, 'fs']})[0] wt.artists.quick1D(data1) plt.show() diff --git a/examples/DOVE_transform.py b/examples/DOVE_transform.py index 7bc21316..8346081e 100644 --- a/examples/DOVE_transform.py +++ b/examples/DOVE_transform.py @@ -13,6 +13,7 @@ p = datasets.KENT.LDS821_DOVE data = wt.data.from_KENT(p, ignore=["d1", "d2", "wm"], verbose=False) +data.channels[0].normalize() fig, gs = wt.artists.create_figure(width="double", cols=[1, 1, "cbar"], wspace=0.7) @@ -27,11 +28,11 @@ # transformed ax = plt.subplot(gs[0, 1]) data.transform("w2", "w1-w2") -ax.pcolor(data) +art = ax.pcolor(data) wt.artists.set_ax_labels(xlabel=data.w2.label) ax.grid() ax.set_title("transformed", fontsize=20) # colorbar cax = plt.subplot(gs[0, -1]) -wt.artists.plot_colorbar(cax, label="Intensity") +fig.colorbar(art, cax=cax, label="Intensity") diff --git a/examples/colormaps.py b/examples/colormaps.py index b7e25964..166a74c9 100644 --- a/examples/colormaps.py +++ b/examples/colormaps.py @@ -30,10 +30,10 @@ def fill_row(row, cmap): ax.pcolor(data, cmap=wt.artists.grayify_cmap(cmap)) # color ax = plt.subplot(gs[row, 1]) - ax.pcolor(data, cmap=cmap) + art = ax.pcolor(data, cmap=cmap) # cbar cax = plt.subplot(gs[row, 2]) - wt.artists.plot_colorbar(cax=cax, label=cmap.name, cmap=cmap) + fig.colorbar(art, cax=cax, label=cmap.name) wt.artists.set_ax_labels(cax, yticks=False) diff --git a/examples/custom_fig.py b/examples/custom_fig.py index e5074125..73ef6c8d 100644 --- a/examples/custom_fig.py +++ b/examples/custom_fig.py @@ -8,6 +8,7 @@ """ import matplotlib.pyplot as plt +from matplotlib.colors import Normalize import numpy as np @@ -23,6 +24,7 @@ data.smooth([2, 2, 2]) data.ai0.symmetric_root(2) data.ai0.normalize() +norm = Normalize(vmin=0, vmax=1) data.ai0.clip(min=0, replace="value") # chop out data of interest d2_vals = [-50, -500] @@ -48,7 +50,7 @@ indxs = [(row, col) for row in range(1, 3) for col in range(2)] for indx, wigner, color in zip(indxs, wigners, wigner_colors): ax = plt.subplot(gs[indx]) - ax.pcolor(wigner, vmin=0, vmax=1) # global colormpa + art = ax.pcolormesh(wigner, norm=norm) # global colormpa ax.contour(wigner) # local contours ax.grid() wt.artists.set_ax_spines(ax=ax, c=color) @@ -73,7 +75,7 @@ # plot colormap cax = plt.subplot(gs[1:3, -1]) ticks = np.linspace(data.ai0.min(), data.ai0.max(), 11) -wt.artists.plot_colorbar(cax=cax, label="amplitude", cmap="default", ticks=ticks) +fig.colorbar(art, cax=cax, label="amplitude", cmap="default", ticks=ticks) # set axis labels wt.artists.set_fig_labels(xlabel=data.w1__e__wm.label, ylabel=data.d2.label, col=slice(0, 1)) # ylabel of zeroth row diff --git a/examples/fill_types.py b/examples/fill_types.py index 85b228e8..42ce3614 100644 --- a/examples/fill_types.py +++ b/examples/fill_types.py @@ -15,6 +15,7 @@ from WrightTools import datasets cmap = wt.artists.colormaps["default"] +norm = matplotlib.colors.Normalize(vmin=0, vmax=1) fig, gs = wt.artists.create_figure(width="double", nrows=2, cols=[1, 1, 1, 1, "cbar"]) @@ -39,11 +40,11 @@ def decorate(ax): # pcolor ax = plt.subplot(gs[0, 0]) -ax.pcolor(data, cmap=cmap) +ax.pcolor(data, cmap=cmap, norm=norm) ax.set_title("pcolor", fontsize=20) decorate(ax) ax = plt.subplot(gs[1, 0]) -ax.pcolor(data, cmap=cmap, edgecolors="k") +art = ax.pcolor(data, cmap=cmap, edgecolors="k", norm=norm) dot_pixel_centers(ax, data.d1.points, data.d2.points) decorate(ax) @@ -54,11 +55,11 @@ def decorate(ax): ax = plt.subplot(gs[0, 1]) points = [xi, yi] x, y = tuple(np.meshgrid(*points, indexing="ij")) -ax.tripcolor(x.flatten(), y.flatten(), zi.T.flatten(), cmap=cmap, vmin=0, vmax=1) +ax.tripcolor(x.flatten(), y.flatten(), zi.T.flatten(), cmap=cmap, norm=norm) decorate(ax) ax.set_title("tripcolor", fontsize=20) ax = plt.subplot(gs[1, 1]) -ax.tripcolor(x.flatten(), y.flatten(), zi.T.flatten(), edgecolor="k", cmap=cmap, vmin=0, vmax=1) +ax.tripcolor(x.flatten(), y.flatten(), zi.T.flatten(), edgecolor="k", cmap=cmap, norm=norm) decorate(ax) dot_pixel_centers(ax, xi, yi) @@ -76,11 +77,11 @@ def plot_delaunay_edges(ax, xi, yi, zi): # contourf ax = plt.subplot(gs[0, 2]) -ax.contourf(data, vmin=-1e-3) +ax.contourf(data, norm=norm, levels=265) decorate(ax) ax.set_title("contourf", fontsize=20) ax = plt.subplot(gs[1, 2]) -ax.contourf(data, vmin=-1e-3) +ax.contourf(data, norm=norm, levels=256) plot_delaunay_edges(ax, xi, yi, zi) dot_pixel_centers(ax, xi, yi) decorate(ax) @@ -102,4 +103,4 @@ def plot_delaunay_edges(ax, xi, yi, zi): # colorbar cax = plt.subplot(gs[:, -1]) -wt.artists.plot_colorbar(cax=cax, label="amplitude") +fig.colorbar(art, cax=cax, label="amplitude") diff --git a/examples/fringes_transform.py b/examples/fringes_transform.py index dce93d45..3c57fda8 100644 --- a/examples/fringes_transform.py +++ b/examples/fringes_transform.py @@ -12,6 +12,8 @@ from WrightTools import datasets p = datasets.PyCMDS.w2_w1_000 + +# p = datasets.here / "PyCMDS" / "w2 w1 000.data" data = wt.data.from_PyCMDS(p) data.signal_mean.symmetric_root(2) # to amplitude level @@ -30,11 +32,11 @@ ax = plt.subplot(gs[0, 1]) data.transform("wm", "w1") data.convert("wn") -ax.pcolor(data) +art = ax.pcolor(data) wt.artists.set_ax_labels(xlabel=data.wm.label, yticks=False) ax.grid() ax.set_title("transformed", fontsize=20) # colorbar cax = plt.subplot(gs[0, -1]) -wt.artists.plot_colorbar(cax, label="amplitude") +fig.colorbar(art, cax, label="amplitude") diff --git a/examples/label_delay_space.py b/examples/label_delay_space.py index 2b4ade83..94dab209 100644 --- a/examples/label_delay_space.py +++ b/examples/label_delay_space.py @@ -7,6 +7,7 @@ """ import matplotlib.pyplot as plt +from matplotlib.colors import Normalize import WrightTools as wt from WrightTools import datasets @@ -19,6 +20,8 @@ def set_lim(ax): ax.set_ylim(-175, 175) +norm = Normalize(vmin=0, vmax=1, clip=True) + # traditional delay space ax = plt.subplot(gs[0, 0]) p = datasets.PyCMDS.d1_d2_000 @@ -26,8 +29,7 @@ def set_lim(ax): data.convert("fs") data.channels[0].symmetric_root(2) data.channels[0].normalize() -data.channels[0].clip(min=0, replace="value") -ax.pcolor(data) +ax.pcolor(data, norm=norm) wt.diagrams.delay.label_sectors(ax=ax) # using default labels set_lim(ax) ax.set_title(r"$\mathsf{\vec{k}_1 - \vec{k}_2 + \vec{k}_{2^\prime}}$", fontsize=20) @@ -39,8 +41,7 @@ def set_lim(ax): data.convert("fs") data.channels[0].symmetric_root(2) data.channels[0].normalize() -data.channels[0].clip(min=0, replace="value") -ax.pcolor(data) +art = ax.pcolor(data, norm=norm) labels = ["II", "I", "III", "V", "VI", "IV"] wt.diagrams.delay.label_sectors(ax=ax, labels=labels) set_lim(ax) @@ -51,4 +52,4 @@ def set_lim(ax): # colorbar cax = plt.subplot(gs[:, -1]) -wt.artists.plot_colorbar(cax=cax, label="amplitude") +fig.colorbar(art, cax=cax, label="amplitude") diff --git a/examples/level.py b/examples/level.py index 4e4a4adf..9e89e8fc 100644 --- a/examples/level.py +++ b/examples/level.py @@ -22,7 +22,7 @@ ax = plt.subplot(gs[0, 0]) chop = data.chop("w1=wm", "d2", at={"w2": [1.7, "eV"]})[0] chop.ai0.null = chop.ai0.min() # only for example -ax.pcolor(chop) +art = ax.pcolor(chop) ax.contour(chop) # leveled @@ -38,5 +38,5 @@ # colorbar cax = plt.subplot(gs[0, -1]) -wt.artists.plot_colorbar(cax=cax, label="amplitude") +fig.colorbar(art, cax=cax, label="amplitude") wt.artists.set_ax_labels(cax, yticks=False) diff --git a/examples/moment_sideplot.py b/examples/moment_sideplot.py index 99b93c5d..7d6c662b 100644 --- a/examples/moment_sideplot.py +++ b/examples/moment_sideplot.py @@ -22,6 +22,7 @@ def S(x): d.create_variable("d1", values=d1, units="ps", label="1") d.create_variable("d2", values=d2, units="ps", label="2") d.create_channel("z", values=arr) +d.z.normalize() d.transform("d1", "d2") # calculate moments @@ -38,7 +39,7 @@ def S(x): axcorrx = ax.add_sideplot(along="x", pad=0.1, ymin=-0.1, ymax=1.1) axcorry = ax.add_sideplot(along="y", pad=0.1, ymin=-0.1, ymax=1.1) # plot data -ax.pcolor(d, autolabel="both") +art = ax.pcolor(d, autolabel="both") # plot integral moments in sideplot axcorrx.plot(d, channel="z_d2_moment_0", color="k", linewidth=3) # this sideplot is uncouth. @@ -55,4 +56,4 @@ def S(x): ax_.grid() # plot colorbar cax = plt.subplot(gs[-1]) -wt.artists.plot_colorbar(cax=cax, label="amplitude") +fig.colorbar(art, cax=cax, label="amplitude") diff --git a/examples/norms.py b/examples/norms.py new file mode 100644 index 00000000..9026b177 --- /dev/null +++ b/examples/norms.py @@ -0,0 +1,138 @@ +""" +use the right combination of colorbar and matplotlib norms +to communicate your data! +""" + +import WrightTools as wt +from WrightTools import datasets + +import matplotlib.colors as mpl_colors +from matplotlib import colormaps as colormaps + +import numpy as np + + +# --- colormaps ----------------------------------------------------------------------------------- +unsigned_cmap = [ + wt.artists.colormaps["default"].copy(), + colormaps["cubehelix_r"], + colormaps["magma_r"], + colormaps["viridis_r"], +][0] +unsigned_cmap.set_under([0.9, 0.9, 0.9, 1]) + +cyclic_cmap = "twilight" + +signed_cmap = ["twilight_shifted", "RdBu", "coolwarm", "seismic"][1] + + +# --- data ---------------------------------------------------------------------------------------- +p = datasets.wt5.v1p0p0_perovskite_TA +signed = wt.open(p).at(d2=[-15, "fs"]).split("w1", [1.6])[1] +signed.bring_to_front("signal_diff") + +unsigned = wt.data.from_PyCMDS(r"https://osf.io/75vny/download") +unsigned.bring_to_front("signal_diff") +unsigned.convert("eV") +unsigned.signal_diff.normalize() + + +# --- plot ---------------------------------------------------------------------------------------- +label_kwargs = dict(fontsize=14, corner="LR", background_alpha=0.6) +fig, gs = wt.artists.create_figure(width=8, cols=[1, 1], nrows=4, wspace=1.3) + + +# --- unsigned data ------------------------------------------------------------------------------- +# --- --- linear ---------------------------------------------------------------------------------- +ax00 = fig.add_subplot(gs[0, 0], label="00 - unsigned linear") +wt.artists.corner_text("linear", **label_kwargs) +art = ax00.pcolormesh(unsigned, cmap=unsigned_cmap, autolabel="y") +fig.colorbar(art, ax=ax00, extend="min") + +ax00.set_title("unsigned data") + +# --- --- sqrt ------------------------------------------------------------------------------------ +ax10 = fig.add_subplot(gs[1, 0], label="10 - unsigned sqrt") +wt.artists.corner_text("sqrt", **label_kwargs) +# norm = mpl_colors.PowerNorm(gamma=0.5, vmin=0) +""" +NOTE: a bug with PowerNorm makes the colorbar extend arrow incorrect color +as recently as mpl 3.8.3. +a fix has been applied upstream; we just have to wait for it +https://github.com/matplotlib/matplotlib/pull/27589 +in the meantime, we can define a custom norm to get past the issue +""" +_forward = lambda x: np.sign(x) * np.sqrt(np.abs(x)) +_inverse = lambda x: np.sign(x) * x**2 +norm = mpl_colors.FuncNorm((_forward, _inverse), vmin=0, clip=False) +art = ax10.pcolormesh(unsigned, norm=norm, cmap=unsigned_cmap, autolabel="y") +fig.colorbar(art, ax=ax10, extend="min") + +# --- --- log10 ----------------------------------------------------------------------------------- +ax20 = fig.add_subplot(gs[2, 0], label="20 - unsigned log") +wt.artists.corner_text("log10", **label_kwargs) +norm = mpl_colors.LogNorm(vmin=5e-4, clip=False) +art = ax20.pcolormesh(unsigned, norm=norm, cmap=unsigned_cmap, autolabel="y") +cblog = fig.colorbar(art, ax=ax20, extend="min") + +# --- --- log10, decadic cycles ------------------------------------------------------------------- +# currently a bit hackish, but works. We could make tools for this +ax30 = fig.add_subplot(gs[3, 0], label="30 - unsigned log cyclic") +wt.artists.corner_text("log10, cyclic", **label_kwargs) +mantissa = lambda x: np.mod(np.log10(x), -1) +unsigned.create_channel("mantissa", values=10 ** mantissa(unsigned.signal_diff[:])) +norm = mpl_colors.LogNorm() +art = ax30.pcolormesh(unsigned, channel="mantissa", norm=norm, cmap=cyclic_cmap, autolabel="both") +cb = fig.colorbar(art, ax=ax30) +cb.ax.yaxis.set_minor_formatter("{x:0.1f}") +cb.ax.set_yticks([0.1, 0.2, 0.5], minor=True) # , labels=["0.2", "0.5"], minor=True) + +# --- plot signed data --------------------------------------------------------------------------- +# --- --- linear norm ---------------------------------------------------------------------------- +ax01 = fig.add_subplot(gs[0, 1], label="01 - signed linear") +ax01.set_title("signed data") +wt.artists.corner_text("linear", **label_kwargs) +art = ax01.pcolormesh(signed, cmap=signed_cmap, autolabel="y") +fig.colorbar(art, ax=ax01) + +# --- --- bilinear norm -------------------------------------------------------------------------- +ax11 = fig.add_subplot(gs[1, 1], label="11 - signed bilinear") +wt.artists.corner_text("bilinear", **label_kwargs) +norm = mpl_colors.TwoSlopeNorm(vcenter=signed.signal_diff.null) +art = ax11.pcolormesh(signed, norm=norm, cmap=signed_cmap, autolabel="y") +cb = fig.colorbar(art, ax=ax11) +cb.ax.set_yscale("linear") + +# --- --- asinh norm ------------------------------------------------------------------------------ +ax21 = fig.add_subplot(gs[2, 1], label="21 - signed asinh") +wt.artists.corner_text("asinh", **label_kwargs) +norm = mpl_colors.AsinhNorm( + linear_width=1e-3, vmin=-signed.signal_diff.mag(), vmax=signed.signal_diff.mag() +) +art = ax21.pcolormesh(signed, norm=norm, cmap=signed_cmap, autolabel="y") +fig.colorbar(art, ax=ax21) + +# --- --- symlog norm ----------------------------------------------------------------------------- +ax31 = fig.add_subplot(gs[3, 1], label="31 - signed symlog") +wt.artists.corner_text("symLog", **label_kwargs) +norm = mpl_colors.SymLogNorm( + linthresh=1e-3, vmin=-signed.signal_diff.mag(), vmax=signed.signal_diff.mag() +) +art = ax31.pcolormesh(signed, norm=norm, cmap=signed_cmap, autolabel="both") +fig.colorbar(art, ax=ax31) + + +# --- final decorations --------------------------------------------------------------------------- + +for ax in fig.axes: + label = ax.get_label() + if label == "": + continue + ax.grid(c="k", lw=1, ls="-.", alpha=0.5) + if label[0] != "3": # not bottom row + ax.set_xticks(ax.get_xticks(), ax.get_xticklabels(), visible=False) + ax.set_xticks(ax.get_yticks()) + if label[1] == "0": # unsigned + ax.set_xlim(unsigned.w2.min(), unsigned.w2.max()) + else: + ax.set_xlim(signed.w1.min(), signed.w1.max()) diff --git a/examples/split.py b/examples/split.py index db704335..04ace424 100644 --- a/examples/split.py +++ b/examples/split.py @@ -9,7 +9,9 @@ import WrightTools as wt from WrightTools import datasets -d = wt.data.from_PyCMDS(datasets.PyCMDS.w2_w1_000) + +p = datasets.PyCMDS.w2_w1_000 +d = wt.data.from_PyCMDS(p) d.convert("wn", convert_variables=True) diff --git a/examples/tune_test.py b/examples/tune_test.py index e9a9bd15..5d1581e4 100644 --- a/examples/tune_test.py +++ b/examples/tune_test.py @@ -26,11 +26,11 @@ # transformed ax = plt.subplot(gs[0, 2]) data.transform("w1", "wa-w1") -ax.pcolor(data) +art = ax.pcolor(data) wt.artists.set_ax_labels(xlabel=data.w1.label, ylabel=data.wa__m__w1.label) ax.grid() ax.set_title("transformed", fontsize=20) # colorbar cax = plt.subplot(gs[0, -1]) -wt.artists.plot_colorbar(cax, label="intensity") +fig.colorbar(art, cax=cax, label="intensity")