From 2555d41e30ed0cc63fa8fee06b5b3f7b351c30b4 Mon Sep 17 00:00:00 2001 From: Hudanyun Sheng Date: Thu, 11 Mar 2021 16:15:44 -0600 Subject: [PATCH 01/19] Create show_spectra.py Initial basic implementation of interactively show spectra --- plantcv/plantcv/visualize/show_spectra.py | 79 +++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 plantcv/plantcv/visualize/show_spectra.py diff --git a/plantcv/plantcv/visualize/show_spectra.py b/plantcv/plantcv/visualize/show_spectra.py new file mode 100644 index 000000000..da41dafa6 --- /dev/null +++ b/plantcv/plantcv/visualize/show_spectra.py @@ -0,0 +1,79 @@ +# Show spectral or spectra of mouse selected pixel(s) for a given hyperspectral image + +from scipy.spatial import distance +import numpy as np + + +def _find_closest(pt, pts): + """ Given coordinates of a point and a list of coordinates of a bunch of points, find the point that has the smallest Euclidean to the given point + + :param pt: (tuple) coordinates of a point + :param pts: (a list of tuples) coordinates of a list of points + :return: index of the closest point and the coordinates of that point + """ + if pt in pts: + return pt + dists = distance.cdist([pt], pts, 'euclidean') + idx = np.argmin(dists) + return idx, pts[idx] + + +class ShowSpectra(object): + """ + An interactive visualization tool that shows spectral (spectra) for selected pixel(s). + """ + + def __init__(self, spectral_data, figsize=(12,6)): + """ + Initialization + :param spectral_data: hyperspectral image data + :param figsize: desired figure size, (12,6) by default + """ + print("Warning: this tool is under development and is expected to have updates frequently, please check the documentation page to make sure you are using the correct version!") + self.fig, self.axes = plt.subplots(1, 2, figsize=figsize) + self.axes[0].imshow(array.pseudo_rgb) + self.axes[0].set_title("Please click on interested pixels\n Right click for removal") + + self.axes[1].set_xlabel("wavelength (nm)") + self.axes[1].set_ylabel("reflectance") + self.axes[1].set_title("Spectra") + self.axes[1].set_ylim([0, 1]) + + # Set useblit=True on most backends for enhanced performance. + # cursor = Cursor(axes[0], horizOn=True, vertOn=True, useblit=True, color='red', linewidth=2) + + self.points = [] + self.spectra = [] + self.events = [] + + self.array_data = spectral_data.array_data + self.wvs = [k for k in spectral_data.wavelength_dict.keys()] + + + # onclick = functools.partial(_onclick_, fig, axes, array_data, wvs) + + self.fig.canvas.mpl_connect('button_press_event', self.onclick) + + + def onclick(self, event): + self.events.append(event) + if event.button == 1: + + self.axes[0].plot(event.xdata, event.ydata, 'x', c='red') + spectral = self.array_data[int(event.ydata), int(event.xdata), :] + self.spectra.append(spectral) + self.axes[1].plot(self.wvs, spectral) + self.points.append((event.xdata, event.ydata)) + + else: + idx_remove, _ = _find_closest((event.xdata, event.ydata), self.points) + # remove the last added point + # idx_remove = -1 + + # remove the closest point to the user right clicked one + self.points.pop(idx_remove) + ax0plots = self.axes[0].lines + ax1plots = self.axes[1].lines + self.axes[0].lines.remove(ax0plots[idx_remove]) + self.axes[1].lines.remove(ax1plots[idx_remove]) + self.fig.canvas.draw() \ No newline at end of file From 2747bc08da58365a8c94c8863a43d60979c38a2a Mon Sep 17 00:00:00 2001 From: Hudanyun Sheng Date: Thu, 11 Mar 2021 16:16:24 -0600 Subject: [PATCH 02/19] Update __init__.py Update __init__ for added ShowSpectra --- plantcv/plantcv/visualize/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plantcv/plantcv/visualize/__init__.py b/plantcv/plantcv/visualize/__init__.py index 77b8cbddb..cbe592457 100644 --- a/plantcv/plantcv/visualize/__init__.py +++ b/plantcv/plantcv/visualize/__init__.py @@ -5,6 +5,7 @@ from plantcv.plantcv.visualize.colorspaces import colorspaces from plantcv.plantcv.visualize.auto_threshold_methods import auto_threshold_methods from plantcv.plantcv.visualize.overlay_two_imgs import overlay_two_imgs +from plantcv.plantcv.visualize.show_spectra import ShowSpectra __all__ = ["pseudocolor", "colorize_masks", "histogram", "clustered_contours", "colorspaces", "auto_threshold_methods", - "overlay_two_imgs"] + "overlay_two_imgs", "ShowSpectra"] From 8e09a2c1c441e3893239d1f8159629cdcdd01074 Mon Sep 17 00:00:00 2001 From: Hudanyun Sheng Date: Thu, 11 Mar 2021 16:16:34 -0600 Subject: [PATCH 03/19] Create visualize_show_spectra.md --- docs/visualize_show_spectra.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/visualize_show_spectra.md diff --git a/docs/visualize_show_spectra.md b/docs/visualize_show_spectra.md new file mode 100644 index 000000000..6158ac6d7 --- /dev/null +++ b/docs/visualize_show_spectra.md @@ -0,0 +1,27 @@ +## Show Spectra for Selected Pixels (Developing) + +`ShowSpectra` is a class that is capable of handling user's selecting and clicking behaviour by showing spectra of user selected pixels and storing selected coordinates as well as spectra. + +*class* **plantcv.visualize.ShowSpectra(spectral_data, figsize=(12,6))** +- To initialize the ShowSpectra class, the only required parameter is `spectral_data`, which is of type `__main__.Spectral_data`. +- Another optional parameter is the desired figure size `figsize`, by default `figsize=(12,6)`. + +### Attributes +**spectral_data** (`__main__.Spectral_data`, required): input hyperspectral image. + +**spectra** (`list`): spectra for all selected pixels. + +**points** (`list`): list of coordinates of selected pixels. + +```python + +from plantcv import plantcv as pcv + +show_spectra = pcv.visualize.ShowSpectra(array) + +``` + +Check out this video for a sample usage: + + +**Source Code:** [Here](https://github.com/danforthcenter/plantcv/blob/master/plantcv/plantcv/visualize/show_spectra.py) From 082200686b00ba59045cf3cee74d6c665402adac Mon Sep 17 00:00:00 2001 From: Hudanyun Sheng Date: Thu, 11 Mar 2021 17:39:15 -0600 Subject: [PATCH 04/19] Update show_spectra.py --- plantcv/plantcv/visualize/show_spectra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/plantcv/visualize/show_spectra.py b/plantcv/plantcv/visualize/show_spectra.py index da41dafa6..4c4157117 100644 --- a/plantcv/plantcv/visualize/show_spectra.py +++ b/plantcv/plantcv/visualize/show_spectra.py @@ -2,7 +2,7 @@ from scipy.spatial import distance import numpy as np - +import matplotlib.pyplot as plt def _find_closest(pt, pts): """ Given coordinates of a point and a list of coordinates of a bunch of points, find the point that has the smallest Euclidean to the given point From 0df8a91b0343f00a0858ea2ef6432fe1d75c5c29 Mon Sep 17 00:00:00 2001 From: Hudanyun Sheng Date: Fri, 12 Mar 2021 08:13:26 -0600 Subject: [PATCH 05/19] Update visualize_show_spectra.md Update vimeo video embed code --- docs/visualize_show_spectra.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/visualize_show_spectra.md b/docs/visualize_show_spectra.md index 6158ac6d7..9dc8ea214 100644 --- a/docs/visualize_show_spectra.md +++ b/docs/visualize_show_spectra.md @@ -22,6 +22,6 @@ show_spectra = pcv.visualize.ShowSpectra(array) ``` Check out this video for a sample usage: - + **Source Code:** [Here](https://github.com/danforthcenter/plantcv/blob/master/plantcv/plantcv/visualize/show_spectra.py) From edc6a49c0101ac363191f410ae483b6bea319294 Mon Sep 17 00:00:00 2001 From: Hudanyun Sheng Date: Fri, 12 Mar 2021 08:54:33 -0600 Subject: [PATCH 06/19] bug fix for show_spectra.py --- plantcv/plantcv/visualize/show_spectra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/plantcv/visualize/show_spectra.py b/plantcv/plantcv/visualize/show_spectra.py index 4c4157117..21fc13820 100644 --- a/plantcv/plantcv/visualize/show_spectra.py +++ b/plantcv/plantcv/visualize/show_spectra.py @@ -31,7 +31,7 @@ def __init__(self, spectral_data, figsize=(12,6)): """ print("Warning: this tool is under development and is expected to have updates frequently, please check the documentation page to make sure you are using the correct version!") self.fig, self.axes = plt.subplots(1, 2, figsize=figsize) - self.axes[0].imshow(array.pseudo_rgb) + self.axes[0].imshow(spectral_data.pseudo_rgb) self.axes[0].set_title("Please click on interested pixels\n Right click for removal") self.axes[1].set_xlabel("wavelength (nm)") From 8fc0339322bcc2e8e52fc770d41afb379e9f4ae1 Mon Sep 17 00:00:00 2001 From: Hudanyun Sheng Date: Mon, 15 Mar 2021 12:19:13 -0500 Subject: [PATCH 07/19] add test for visualize_show_spectra --- tests/tests.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/tests.py b/tests/tests.py index 5502ebd0d..a8d06daec 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -6193,6 +6193,26 @@ def test_plantcv_visualize_overlay_two_imgs_bad_alpha(): with pytest.raises(RuntimeError): _ = pcv.visualize.overlay_two_imgs(img1=img1, img2=img2, alpha=alpha) +def test_plantcv_visualize_show_spectra(): + # read hypersectral data + spectral_filename = os.path.join(HYPERSPECTRAL_TEST_DATA, HYPERSPECTRAL_DATA) + array_data = pcv.hyperspectral.read_data(filename=spectral_filename) + + # initialization + show_spectra = pcv.visualize.ShowSpectra(array_data, figsize=(12, 6)) + assert len(show_spectra.events) == 0 + + # create mock events + e1 = matplotlib.backend_bases.MouseEvent(name="button_press_event", canvas=show_spectra.fig.canvas, x=0, y=0,button=1) + e1.xdata = 0 + e1.ydata = 0 + + e2 = matplotlib.backend_bases.MouseEvent(name="button_press_event", canvas=show_spectra.fig.canvas, x=0, y=0, button=3) + e1.xdata = 0 + e1.ydata = 0 + show_spectra.onclick(e1) + show_spectra.onclick(e2) + assert len(show_spectra.events) == 2 def test_plantcv_visualize_overlay_two_imgs_size_mismatch(): pcv.params.debug = None From 7b9cc2d45aa6b57c17e24eaea8f6807d0da5ab86 Mon Sep 17 00:00:00 2001 From: Hudanyun Sheng Date: Mon, 15 Mar 2021 13:40:35 -0500 Subject: [PATCH 08/19] Update show_spectra.py --- plantcv/plantcv/visualize/show_spectra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/plantcv/visualize/show_spectra.py b/plantcv/plantcv/visualize/show_spectra.py index 21fc13820..8fadb643e 100644 --- a/plantcv/plantcv/visualize/show_spectra.py +++ b/plantcv/plantcv/visualize/show_spectra.py @@ -12,7 +12,7 @@ def _find_closest(pt, pts): :return: index of the closest point and the coordinates of that point """ if pt in pts: - return pt + return pts.index(pt), pt dists = distance.cdist([pt], pts, 'euclidean') idx = np.argmin(dists) return idx, pts[idx] From eb1b2aa4246e6c4a78ba21628568e718270ce7da Mon Sep 17 00:00:00 2001 From: Hudanyun Sheng Date: Mon, 15 Mar 2021 13:40:38 -0500 Subject: [PATCH 09/19] Update tests.py --- tests/tests.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index a8d06daec..2160a5c13 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -6208,8 +6208,9 @@ def test_plantcv_visualize_show_spectra(): e1.ydata = 0 e2 = matplotlib.backend_bases.MouseEvent(name="button_press_event", canvas=show_spectra.fig.canvas, x=0, y=0, button=3) - e1.xdata = 0 - e1.ydata = 0 + e2.xdata = 0 + e2.ydata = 0 + show_spectra.onclick(e1) show_spectra.onclick(e2) assert len(show_spectra.events) == 2 From 8f8db101054b715cc20a2ee6fc53241082150a9d Mon Sep 17 00:00:00 2001 From: Hudanyun Sheng Date: Mon, 15 Mar 2021 14:19:36 -0500 Subject: [PATCH 10/19] Update tests.py --- tests/tests.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/tests.py b/tests/tests.py index 2160a5c13..26fe72bf7 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -6211,9 +6211,14 @@ def test_plantcv_visualize_show_spectra(): e2.xdata = 0 e2.ydata = 0 + e3 = matplotlib.backend_bases.MouseEvent(name="button_press_event", canvas=show_spectra.fig.canvas, x=1, y=0, button=1) + e3.xdata = 1 + e3.ydata = 0 + show_spectra.onclick(e1) show_spectra.onclick(e2) - assert len(show_spectra.events) == 2 + show_spectra.onclick(e3) + assert len(show_spectra.events) == 3 def test_plantcv_visualize_overlay_two_imgs_size_mismatch(): pcv.params.debug = None From 0c63f3647f412a656653937b7892a5b2bf2614d3 Mon Sep 17 00:00:00 2001 From: Hudanyun Sheng Date: Mon, 15 Mar 2021 14:46:46 -0500 Subject: [PATCH 11/19] Update tests.py --- tests/tests.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 26fe72bf7..4c8cbc833 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -6211,14 +6211,19 @@ def test_plantcv_visualize_show_spectra(): e2.xdata = 0 e2.ydata = 0 - e3 = matplotlib.backend_bases.MouseEvent(name="button_press_event", canvas=show_spectra.fig.canvas, x=1, y=0, button=1) + e1_ = matplotlib.backend_bases.MouseEvent(name="button_press_event", canvas=show_spectra.fig.canvas, x=0, y=0,button=1) + e1_.xdata = 0 + e1_.ydata = 0 + + e3 = matplotlib.backend_bases.MouseEvent(name="button_press_event", canvas=show_spectra.fig.canvas, x=1, y=0, button=3) e3.xdata = 1 e3.ydata = 0 show_spectra.onclick(e1) show_spectra.onclick(e2) + show_spectra.onclick(e1_) show_spectra.onclick(e3) - assert len(show_spectra.events) == 3 + assert len(show_spectra.events) == 4 def test_plantcv_visualize_overlay_two_imgs_size_mismatch(): pcv.params.debug = None From 78d152d6208a01aade386cf3bddb06cf74fec492 Mon Sep 17 00:00:00 2001 From: Hudanyun Sheng Date: Mon, 5 Apr 2021 18:46:02 -0500 Subject: [PATCH 12/19] Update show_spectra.py ensure the shown RGB image's color bands is in sequence of R-G-B --- plantcv/plantcv/visualize/show_spectra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/plantcv/visualize/show_spectra.py b/plantcv/plantcv/visualize/show_spectra.py index 8fadb643e..2a1a436ae 100644 --- a/plantcv/plantcv/visualize/show_spectra.py +++ b/plantcv/plantcv/visualize/show_spectra.py @@ -31,7 +31,7 @@ def __init__(self, spectral_data, figsize=(12,6)): """ print("Warning: this tool is under development and is expected to have updates frequently, please check the documentation page to make sure you are using the correct version!") self.fig, self.axes = plt.subplots(1, 2, figsize=figsize) - self.axes[0].imshow(spectral_data.pseudo_rgb) + self.axes[0].imshow(cv2.cvtColor(spectral_data.pseudo_rgb, cv2.COLOR_BGR2RGB)) self.axes[0].set_title("Please click on interested pixels\n Right click for removal") self.axes[1].set_xlabel("wavelength (nm)") From df367d17df591ac515ea1f5090facba072005375 Mon Sep 17 00:00:00 2001 From: Hudanyun Sheng Date: Mon, 5 Apr 2021 18:55:50 -0500 Subject: [PATCH 13/19] Update show_spectra.py --- plantcv/plantcv/visualize/show_spectra.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plantcv/plantcv/visualize/show_spectra.py b/plantcv/plantcv/visualize/show_spectra.py index 2a1a436ae..1187c014b 100644 --- a/plantcv/plantcv/visualize/show_spectra.py +++ b/plantcv/plantcv/visualize/show_spectra.py @@ -3,6 +3,7 @@ from scipy.spatial import distance import numpy as np import matplotlib.pyplot as plt +from cv2 import cvtColor, COLOR_BGR2RGB def _find_closest(pt, pts): """ Given coordinates of a point and a list of coordinates of a bunch of points, find the point that has the smallest Euclidean to the given point @@ -31,7 +32,7 @@ def __init__(self, spectral_data, figsize=(12,6)): """ print("Warning: this tool is under development and is expected to have updates frequently, please check the documentation page to make sure you are using the correct version!") self.fig, self.axes = plt.subplots(1, 2, figsize=figsize) - self.axes[0].imshow(cv2.cvtColor(spectral_data.pseudo_rgb, cv2.COLOR_BGR2RGB)) + self.axes[0].imshow(cvtColor(spectral_data.pseudo_rgb, COLOR_BGR2RGB)) self.axes[0].set_title("Please click on interested pixels\n Right click for removal") self.axes[1].set_xlabel("wavelength (nm)") From eb044af2ed1a58ef25a5c7ba2ce9028c7d8a8675 Mon Sep 17 00:00:00 2001 From: Hudanyun Sheng Date: Wed, 7 Apr 2021 15:49:02 -0500 Subject: [PATCH 14/19] update show_spectra function such that adjustment of region using slider is possible --- plantcv/plantcv/visualize/show_spectra.py | 134 +++++++++++++++++----- 1 file changed, 104 insertions(+), 30 deletions(-) diff --git a/plantcv/plantcv/visualize/show_spectra.py b/plantcv/plantcv/visualize/show_spectra.py index 1187c014b..914445ea3 100644 --- a/plantcv/plantcv/visualize/show_spectra.py +++ b/plantcv/plantcv/visualize/show_spectra.py @@ -3,7 +3,10 @@ from scipy.spatial import distance import numpy as np import matplotlib.pyplot as plt -from cv2 import cvtColor, COLOR_BGR2RGB +import matplotlib.patches as patches +from matplotlib.widgets import Slider +import cv2 + def _find_closest(pt, pts): """ Given coordinates of a point and a list of coordinates of a bunch of points, find the point that has the smallest Euclidean to the given point @@ -13,8 +16,8 @@ def _find_closest(pt, pts): :return: index of the closest point and the coordinates of that point """ if pt in pts: - return pts.index(pt), pt - dists = distance.cdist([pt], pts, 'euclidean') + return pt + dists = distance.cdist([pt], pts, 'euclidean') idx = np.argmin(dists) return idx, pts[idx] @@ -24,57 +27,128 @@ class ShowSpectra(object): An interactive visualization tool that shows spectral (spectra) for selected pixel(s). """ - def __init__(self, spectral_data, figsize=(12,6)): + def __init__(self, spectral_data, figsize=(12, 8)): """ Initialization :param spectral_data: hyperspectral image data - :param figsize: desired figure size, (12,6) by default + :param figsize: desired figure size, (12,8) by default """ print("Warning: this tool is under development and is expected to have updates frequently, please check the documentation page to make sure you are using the correct version!") + + # initialize the pseudocolor rgb data (convert from BGR to RGB) + self.pseudo_rgb = cv2.cvtColor(spectral_data.pseudo_rgb, cv2.COLOR_BGR2RGB) + self.fig, self.axes = plt.subplots(1, 2, figsize=figsize) - self.axes[0].imshow(cvtColor(spectral_data.pseudo_rgb, COLOR_BGR2RGB)) - self.axes[0].set_title("Please click on interested pixels\n Right click for removal") + self.axes[0].imshow(self.pseudo_rgb) + self.axes[0].set_title("Please click on interested pixels\n Right click to remove") self.axes[1].set_xlabel("wavelength (nm)") self.axes[1].set_ylabel("reflectance") self.axes[1].set_title("Spectra") self.axes[1].set_ylim([0, 1]) + # adjust the main plot to make room for the sliders + plt.subplots_adjust(left=0.25, bottom=0.25) + + # make a horizontal slider to control the radius + axradius = self.fig.add_axes([0.15, 0.035, 0.3, 0.035], facecolor='lightgoldenrodyellow') # [left, bottom, width, height] + self.radius_slider = Slider( + ax=axradius, + label="radius", + valmin=0, + valmax=500, + valinit=1, + orientation="horizontal" + ) + # Set useblit=True on most backends for enhanced performance. # cursor = Cursor(axes[0], horizOn=True, vertOn=True, useblit=True, color='red', linewidth=2) - self.points = [] + self.points = [] self.spectra = [] - self.events = [] + self.events = [] self.array_data = spectral_data.array_data self.wvs = [k for k in spectral_data.wavelength_dict.keys()] + self.spectral_std = None + self.spectral_mean = None - # onclick = functools.partial(_onclick_, fig, axes, array_data, wvs) + # initialize radius + self.r = 0 + self.x = None + self.y = None + self.rectangle = None self.fig.canvas.mpl_connect('button_press_event', self.onclick) + self.radius_slider.on_changed(self.update) + + def spectra_roi(self): + """Pull out the spectra inside a square ROI + """ + r = int(self.r) + y = int(self.y) + x = int(self.x) + kernel_ = np.ones((2 * r + 1, 2 * r + 1)) / (4 * r * r + 4 * r + 1) + + square = self.array_data[(y - r):(y + r + 1), (x - r):(x + r + 1), :] + + num_bands = square.shape[2] + + kernel = np.repeat(kernel_[:, :, np.newaxis], num_bands, axis=2) + + multiplied = np.multiply(square, kernel) + multiplied_spectra = np.reshape(multiplied, (-1, num_bands)) + self.spectral_mean = multiplied_spectra.sum(axis=0) + self.spectral_std = multiplied_spectra.std(axis=0) + # only prepare the patch for plotting if r>1 (not only one pixel, but a square of pixels) + if r > 0: + self.rectangle = patches.Rectangle((x - r, y - r), 2 * r, 2 * r, edgecolor="red", fill=False) def onclick(self, event): self.events.append(event) - if event.button == 1: - - self.axes[0].plot(event.xdata, event.ydata, 'x', c='red') - spectral = self.array_data[int(event.ydata), int(event.xdata), :] - self.spectra.append(spectral) - self.axes[1].plot(self.wvs, spectral) - self.points.append((event.xdata, event.ydata)) - - else: - idx_remove, _ = _find_closest((event.xdata, event.ydata), self.points) - # remove the last added point - # idx_remove = -1 - - # remove the closest point to the user right clicked one - self.points.pop(idx_remove) - ax0plots = self.axes[0].lines - ax1plots = self.axes[1].lines - self.axes[0].lines.remove(ax0plots[idx_remove]) - self.axes[1].lines.remove(ax1plots[idx_remove]) - self.fig.canvas.draw() \ No newline at end of file + if str(event.inaxes._subplotspec) == 'GridSpec(1, 2)[0:1, 0:1]': + if event.button == 1: + self.x, self.y = event.xdata, event.ydata + self.axes[0].plot(event.xdata, event.ydata, 'x', c='red') + self.spectra_roi() + if self.r > 1: + self.axes[0].add_patch(self.rectangle) + + self.axes[1].errorbar(self.wvs, self.spectral_mean, xerr=self.spectral_std / 2) + self.points.append((event.xdata, event.ydata)) + else: + idx_remove, _ = _find_closest((event.xdata, event.ydata), self.points) + # remove the last added point + # idx_remove = -1 + + # remove the closest point to the user right clicked one + self.points.pop(idx_remove) + if len(self.points) > 0: + self.x, self.y = self.points[-1] + ax0plots = self.axes[0].lines + ax0patches = self.axes[0].patches + ax1plots = self.axes[1].lines + self.axes[0].lines.remove(ax0plots[idx_remove]) + if len(ax0patches) > 0: + self.axes[0].patches.remove(ax0patches[idx_remove]) + self.axes[1].lines.remove(ax1plots[idx_remove]) + self.fig.canvas.draw() + + def update(self, val): + self.r = self.radius_slider.val + self.spectra_roi() + + # remove old plots + idx_remove = -1 + ax0patches = self.axes[0].patches + if len(ax0patches) > 0: + self.axes[0].patches.remove(ax0patches[idx_remove]) + ax1plots = self.axes[1].lines + self.axes[1].lines.remove(ax1plots[idx_remove]) + + # add new plots + self.axes[0].add_patch(self.rectangle) + self.axes[1].errorbar(self.wvs, self.spectral_mean, xerr=self.spectral_std / 2) + self.fig.canvas.draw_idle() From 2e1662cf7638737a980204e899528cf9f23f2fb1 Mon Sep 17 00:00:00 2001 From: Hudanyun Sheng Date: Wed, 7 Apr 2021 15:49:04 -0500 Subject: [PATCH 15/19] Update tests.py --- tests/tests.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/tests.py b/tests/tests.py index 4c8cbc833..4edfff018 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -6204,18 +6204,26 @@ def test_plantcv_visualize_show_spectra(): # create mock events e1 = matplotlib.backend_bases.MouseEvent(name="button_press_event", canvas=show_spectra.fig.canvas, x=0, y=0,button=1) + e1.inaxes = show_spectra.axes[0] + e1.inaxes._subplotspec = show_spectra.axes[0]._subplotspec e1.xdata = 0 e1.ydata = 0 e2 = matplotlib.backend_bases.MouseEvent(name="button_press_event", canvas=show_spectra.fig.canvas, x=0, y=0, button=3) + e2.inaxes = show_spectra.axes[0] + e2.inaxes._subplotspec = show_spectra.axes[0]._subplotspec e2.xdata = 0 e2.ydata = 0 e1_ = matplotlib.backend_bases.MouseEvent(name="button_press_event", canvas=show_spectra.fig.canvas, x=0, y=0,button=1) + e1_.inaxes = show_spectra.axes[0] + e1_.inaxes._subplotspec = show_spectra.axes[0]._subplotspec e1_.xdata = 0 e1_.ydata = 0 e3 = matplotlib.backend_bases.MouseEvent(name="button_press_event", canvas=show_spectra.fig.canvas, x=1, y=0, button=3) + e3.inaxes = show_spectra.axes[0] + e3.inaxes._subplotspec = show_spectra.axes[0]._subplotspec e3.xdata = 1 e3.ydata = 0 @@ -6223,8 +6231,26 @@ def test_plantcv_visualize_show_spectra(): show_spectra.onclick(e2) show_spectra.onclick(e1_) show_spectra.onclick(e3) + assert len(show_spectra.events) == 4 + # test for updating + # initialization + array_d = array_data.array_data + array_data.array_data = np.concatenate((array_d, array_d, array_d, array_d, array_d), axis=0) + show_spectra = pcv.visualize.ShowSpectra(array_data, figsize=(12, 6)) + e1 = matplotlib.backend_bases.MouseEvent(name="button_press_event", canvas=show_spectra.fig.canvas, x=1, y=1,button=1) + e1.inaxes = show_spectra.axes[0] + e1.inaxes._subplotspec = show_spectra.axes[0]._subplotspec + e1.xdata = 2 + e1.ydata = 2 + show_spectra.onclick(e1) + val = 1 + show_spectra.radius_slider.val = val + show_spectra.update(val) + # assert show_spectra.r > 0 + assert len(show_spectra.axes[0].patches) > 0 + def test_plantcv_visualize_overlay_two_imgs_size_mismatch(): pcv.params.debug = None cache_dir = os.path.join(TEST_TMPDIR, "test_plantcv_visualize_overlay_two_imgs_size_mismatch") From 37b4b6f6ea3a1b0c78855f206b7534dfb2421dbd Mon Sep 17 00:00:00 2001 From: Hudanyun Sheng Date: Wed, 7 Apr 2021 17:49:39 -0500 Subject: [PATCH 16/19] Update tests.py --- tests/tests.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 4edfff018..f369b1fc0 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -6230,9 +6230,10 @@ def test_plantcv_visualize_show_spectra(): show_spectra.onclick(e1) show_spectra.onclick(e2) show_spectra.onclick(e1_) + show_spectra.onclick(e1_) show_spectra.onclick(e3) - assert len(show_spectra.events) == 4 + assert len(show_spectra.events) == 5 # test for updating # initialization @@ -6245,10 +6246,14 @@ def test_plantcv_visualize_show_spectra(): e1.xdata = 2 e1.ydata = 2 show_spectra.onclick(e1) - val = 1 + val = 2 show_spectra.radius_slider.val = val show_spectra.update(val) - # assert show_spectra.r > 0 + show_spectra.onclick(e1) + show_spectra.update(val) + show_spectra.onclick(e2) + assert len(show_spectra.axes[0].patches) > 0 + show_spectra.onclick(e1) assert len(show_spectra.axes[0].patches) > 0 def test_plantcv_visualize_overlay_two_imgs_size_mismatch(): From 357f9a0843445cd89cee8d31c8c3e30c9e796d07 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Wed, 15 Sep 2021 09:18:59 -0500 Subject: [PATCH 17/19] minor doc page updates --- docs/visualize_show_spectra.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/visualize_show_spectra.md b/docs/visualize_show_spectra.md index 9dc8ea214..168ddcf55 100644 --- a/docs/visualize_show_spectra.md +++ b/docs/visualize_show_spectra.md @@ -1,6 +1,6 @@ ## Show Spectra for Selected Pixels (Developing) -`ShowSpectra` is a class that is capable of handling user's selecting and clicking behaviour by showing spectra of user selected pixels and storing selected coordinates as well as spectra. +`ShowSpectra` is a class that is capable of handling user's selecting and clicking behavior by showing spectra of user selected pixels and storing selected coordinates as well as spectra. *class* **plantcv.visualize.ShowSpectra(spectral_data, figsize=(12,6))** - To initialize the ShowSpectra class, the only required parameter is `spectral_data`, which is of type `__main__.Spectral_data`. @@ -17,7 +17,7 @@ from plantcv import plantcv as pcv -show_spectra = pcv.visualize.ShowSpectra(array) +show_spectra = pcv.visualize.ShowSpectra(spectral_data=array) ``` From 79051d72b7eb798991df069a8dca629f81d7531c Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Wed, 15 Sep 2021 09:33:22 -0500 Subject: [PATCH 18/19] update slider? --- plantcv/plantcv/visualize/show_spectra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/plantcv/visualize/show_spectra.py b/plantcv/plantcv/visualize/show_spectra.py index 914445ea3..becaca7f6 100644 --- a/plantcv/plantcv/visualize/show_spectra.py +++ b/plantcv/plantcv/visualize/show_spectra.py @@ -51,7 +51,7 @@ def __init__(self, spectral_data, figsize=(12, 8)): plt.subplots_adjust(left=0.25, bottom=0.25) # make a horizontal slider to control the radius - axradius = self.fig.add_axes([0.15, 0.035, 0.3, 0.035], facecolor='lightgoldenrodyellow') # [left, bottom, width, height] + axradius = self.plt.axes([0.15, 0.035, 0.3, 0.035], facecolor='lightgoldenrodyellow') # [left, bottom, width, height] self.radius_slider = Slider( ax=axradius, label="radius", From 5557f058510867a9cb4a89c2e29515571d23fa02 Mon Sep 17 00:00:00 2001 From: HaleySchuhl Date: Wed, 15 Sep 2021 09:35:15 -0500 Subject: [PATCH 19/19] undo --- plantcv/plantcv/visualize/show_spectra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plantcv/plantcv/visualize/show_spectra.py b/plantcv/plantcv/visualize/show_spectra.py index becaca7f6..914445ea3 100644 --- a/plantcv/plantcv/visualize/show_spectra.py +++ b/plantcv/plantcv/visualize/show_spectra.py @@ -51,7 +51,7 @@ def __init__(self, spectral_data, figsize=(12, 8)): plt.subplots_adjust(left=0.25, bottom=0.25) # make a horizontal slider to control the radius - axradius = self.plt.axes([0.15, 0.035, 0.3, 0.035], facecolor='lightgoldenrodyellow') # [left, bottom, width, height] + axradius = self.fig.add_axes([0.15, 0.035, 0.3, 0.035], facecolor='lightgoldenrodyellow') # [left, bottom, width, height] self.radius_slider = Slider( ax=axradius, label="radius",