Repository: wright-group/WrightTools

Issue:
Test artist methods
https://github.com/matplotlib/pytest-mpl

Pytest plugin to help, recommended by matplotlib core contributor (also the release maintainer of h5py)
interact2D:  additional documentation
A general overview of the interact2D functionality should be made on ReadTheDocs.


Discussion:

Resolving patch:
diff --git a/WrightTools/artists/_interact.py b/WrightTools/artists/_interact.py
--- a/WrightTools/artists/_interact.py
+++ b/WrightTools/artists/_interact.py
@@ -85,11 +85,11 @@ def get_clim(channel, current_state):
 def gen_ticklabels(points, signed=None):
     step = np.nanmin(np.diff(points))
     if step == 0:  # zeros everywhere
-        ticklabels = ['' for i in range(11)]
+        ticklabels = ["" for i in range(11)]
         if signed:
-            ticklabels[5] = '0'
+            ticklabels[5] = "0"
         else:
-            ticklabels[0] = '0'
+            ticklabels[0] = "0"
         return ticklabels
     ordinal = np.log10(np.abs(step))
     ndigits = -int(np.floor(ordinal))
@@ -408,7 +408,7 @@ def update(info):
             if x0 > xlim[0] and x0 < xlim[1] and y0 > ylim[0] and y0 < ylim[1]:
                 current_state.xpos = info.xdata
                 current_state.ypos = info.ydata
-                if info.button == 1:  # left click
+                if info.button == 1 or info.button is None:  # left click
                     if verbose:
                         print(current_state.xpos, current_state.ypos)
                     update_sideplot_slices()
diff --git a/WrightTools/artists/_quick.py b/WrightTools/artists/_quick.py
--- a/WrightTools/artists/_quick.py
+++ b/WrightTools/artists/_quick.py
@@ -117,7 +117,20 @@ def quick1D(
         ax.set_xlabel(axis.label, fontsize=18)
         ax.set_ylabel(channel.name, fontsize=18)
         plt.xticks(rotation=45)
+        plt.axvline(0, lw=2, c="k")
         plt.xlim(xi.min(), xi.max())
+        # add constants to title
+        ls = []
+        for constant in d.constants:
+            ls.append(constant.label)
+        title = ", ".join(ls)
+        ax.set_title(title)
+        # variable marker lines
+        for constant in d.constants:
+            if constant.units is not None:
+                if axis.units_kind == constant.units_kind:
+                    constant.convert(axis.units)
+                    plt.axvline(constant.value, color="k", linewidth=4, alpha=0.25)
         # save ------------------------------------------------------------------------------------
         if autosave:
             if fname:
@@ -230,7 +243,7 @@ def quick2D(
         xaxis = d.axes[0]
         xlim = xaxis.min(), xaxis.max()
         yaxis = d.axes[1]
-        ylim = xaxis.min(), yaxis.max()
+        ylim = yaxis.min(), yaxis.max()
         channel = d.channels[channel_index]
         zi = channel[:]
         zi = np.ma.masked_invalid(zi)
@@ -274,7 +287,6 @@ def quick2D(
                     levels = np.linspace(data_channel.null, data_channel.max(), 200)
         # colors ----------------------------------------------------------------------------------
         if pixelated:
-            # print(channel.name, d.channel_names, channel, channel_index)
             ax.pcolor(d, channel=channel_index, cmap=cmap, vmin=levels.min(), vmax=levels.max())
         else:
             ax.contourf(d, channel=channel_index, cmap=cmap, levels=levels)
@@ -286,10 +298,35 @@ def quick2D(
         plt.yticks(fontsize=14)
         ax.set_xlabel(xaxis.label, fontsize=18)
         ax.set_ylabel(yaxis.label, fontsize=18)
+        ax.grid()
+        # lims
+        ax.set_xlim(xlim)
+        ax.set_ylim(ylim)
+        # add zero lines
+        plt.axvline(0, lw=2, c="k")
+        plt.axhline(0, lw=2, c="k")
+        # add constants to title
+        ls = []
+        for constant in d.constants:
+            ls.append(constant.label)
+        title = ", ".join(ls)
+        ax.set_title(title)
+        # variable marker lines
+        for constant in d.constants:
+            if constant.units is not None:
+                # x axis
+                if xaxis.units_kind == constant.units_kind:
+                    constant.convert(xaxis.units)
+                    plt.axvline(constant.value, color="k", linewidth=4, alpha=0.25)
+                # y axis
+                if yaxis.units_kind == constant.units_kind:
+                    constant.convert(yaxis.units)
+                    plt.axhline(constant.value, color="k", linewidth=4, alpha=0.25)
         # colorbar
         cax = plt.subplot(gs[1])
         cbar_ticks = np.linspace(levels.min(), levels.max(), 11)
         plot_colorbar(cax=cax, ticks=cbar_ticks, label=channel.natural_name, cmap=cmap)
+        plt.sca(ax)
         # save figure -----------------------------------------------------------------------------
         if autosave:
             if fname:


Test patch:
diff --git a/tests/artists/test_interact2D.py b/tests/artists/test_interact2D.py
--- a/tests/artists/test_interact2D.py
+++ b/tests/artists/test_interact2D.py
@@ -7,7 +7,14 @@
 
 def test_perovskite():
     p = datasets.wt5.v1p0p0_perovskite_TA  # axes w1=wm, w2, d2
-    data = wt.open(p)
+    # A race condition exists where multiple tests access the same file in short order
+    # this loop will open the file when it becomes available.
+    while True:
+        try:
+            data = wt.open(p)
+            break
+        except:
+            pass
     return wt.artists.interact2D(data, xaxis=2, yaxis=1)
 
 
diff --git a/tests/artists/test_quick1D.py b/tests/artists/test_quick1D.py
new file mode 100755
--- /dev/null
+++ b/tests/artists/test_quick1D.py
@@ -0,0 +1,40 @@
+#! /usr/bin/env python3
+
+import numpy as np
+import WrightTools as wt
+from WrightTools import datasets
+
+
+def test_perovskite():
+    p = datasets.wt5.v1p0p0_perovskite_TA  # axes w1=wm, w2, d2
+    # A race condition exists where multiple tests access the same file in short order
+    # this loop will open the file when it becomes available.
+    while True:
+        try:
+            data = wt.open(p)
+            break
+        except:
+            pass
+    return wt.artists.quick1D(data, axis=0, at={"w2": [1.7, "eV"], "d2": [0, "fs"]})
+
+
+def test_2D():
+    w1 = np.linspace(-3, 3, 51)
+    w2 = np.linspace(-1, 1, 3)
+    signal = w1[:, None] + w2[None, :]
+    data = wt.data.Data(name="data")
+    data.create_channel("signal", values=signal, signed=True)
+    data.create_variable("w1", values=w1[:, None], units="wn", label="1")
+    data.create_variable("w2", values=w2[None, :], units="wn", label="2")
+    data.transform("w1", "w2")
+    return wt.artists.quick1D(data)
+
+
+if __name__ == "__main__":
+    import matplotlib.pyplot as plt
+
+    plt.close("all")
+    # store to variable to prevent garbage collection
+    t0 = test_perovskite()
+    t1 = test_2D()
+    plt.show()
diff --git a/tests/artists/test_quick2D.py b/tests/artists/test_quick2D.py
new file mode 100755
--- /dev/null
+++ b/tests/artists/test_quick2D.py
@@ -0,0 +1,49 @@
+#! /usr/bin/env python3
+
+import numpy as np
+import WrightTools as wt
+from WrightTools import datasets
+
+
+def test_perovskite():
+    p = datasets.wt5.v1p0p0_perovskite_TA  # axes w1=wm, w2, d2
+    # A race condition exists where multiple tests access the same file in short order
+    # this loop will open the file when it becomes available.
+    while True:
+        try:
+            data = wt.open(p)
+            break
+        except:
+            pass
+    return wt.artists.quick2D(data, xaxis=0, yaxis=2, at={"w2": [1.7, "eV"]})
+
+
+def test_4D():
+    w1 = np.linspace(-3, 3, 3)
+    w2 = np.linspace(-2, 2, 3)
+    w3 = np.linspace(-1, 1, 3)
+    tau = np.linspace(-1, 3, 2)
+    signal = (
+        w1[:, None, None, None]
+        + w2[None, :, None, None]
+        + w3[None, None, :, None]
+        + tau[None, None, None, :]
+    )
+    data = wt.data.Data(name="data")
+    data.create_channel("signal", values=signal, signed=True)
+    data.create_variable("w1", values=w1[:, None, None, None], units="wn", label="1")
+    data.create_variable("w2", values=w2[None, :, None, None], units="wn", label="2")
+    data.create_variable("w3", values=w3[None, None, :, None], units="wn", label="3")
+    data.create_variable("d1", values=tau[None, None, None, :], units="ps")
+    data.transform("w1", "w2", "w3", "d1")
+    return wt.artists.quick2D(data, xaxis=0, yaxis=1)
+
+
+if __name__ == "__main__":
+    import matplotlib.pyplot as plt
+
+    plt.close("all")
+    # store to variable to prevent garbage collection
+    t0 = test_perovskite()
+    t1 = test_4D()
+    plt.show()