Repository: danforthcenter/plantcv
Issue: Pseudocolor function plotting issues

**Describe the bug**
@dschneiderch noted that on his Windows system the `pcv.visualize.pseudocolor` function was plotting even when `pcv.params.debug = None`. He proposed the updating the debug logic block to the following:

```python
if params.debug is not None:
    if params.debug == 'print':
        plt.savefig(os.path.join(params.debug_outdir, str(params.device) + '_pseudocolored.png'), dpi=params.dpi)
        plt.close()
    elif params.debug == 'plot':
        plot_image(pseudo_img1)
        # Use non-blocking mode in case the function is run more than once
        plt.show(block=False)
```

Essentially this removes an extra piece of logic that did `plt.show()` even when debug was set to `None`.

I think there are some other issues to work out though, so I'm opening this as a new issue instead of applying the fix within another PR.

**To Reproduce**

**Issue 1**
We automatically set the `matplotlib` backend under conditions where we do not detect a display.:

```python
# If there is no display or a matplotlib backend already defined, use the non-GUI backend
if "DISPLAY" not in os.environ and "MPLBACKEND" not in os.environ:
    matplotlib.use("Agg")
```

On Linux and macOS, if `DISPLAY` is not a defined environment variable, or we are not in Jupyter (MPLBACKEND), then we set the backend to Agg so that plots can be created without trying to plot to a window/screen device. One part of @dschneiderch issue I think is that on Windows we are not accounting for display devices.

**Issue 2**
Related to the above issue, `pcv.visualize.pseudocolor`, with the current code, displays the image even when debug is `None`. In Jupyter for example:

```python
%matplotlib inline
from plantcv import plantcv as pcv
pcv.params.debug = None
img, imgpath, imgname = pcv.readimage(filename="image.png")
gray_img = pcv.rgb2gray_hsv(rgb_img=img, channel="v")
ps_img = pcv.visualize.pseudocolor(gray_img=gray_img)
# Plots the pseudocolor image here
ps_img.savefig("test.png")
# Saves the image correctly to a file
```

**Issue 3**
If the current code is modified to remove the extra `plt.show()` and the code is run multiple times in an environment with the `Agg` backend multiple scale bars are plotted, probably because the figure does not get closed before plotting again. 

**Expected behavior**
I'm not 100% sure what the overall solution is, we will need to try running some test code in Jupyter, on the command line, and with/without plotting interfaces to make sure we can get the behavior set to be consistent.

**Local environment (please complete the following information):**
 - OS: macOS, Windows
 - Environment: conda, Jupyter, command-line
 - PlantCV Version: 3.9.0+68.g409b26b


Changed files:
plantcv/plantcv/threshold/threshold_methods.py, plantcv/plantcv/__init__.py, plantcv/plantcv/visualize/pseudocolor.py, plantcv/plantcv/plot_image.py

diff --git a/plantcv/plantcv/__init__.py b/plantcv/plantcv/__init__.py
index 12b1d34d..0f629a0e 100644
--- a/plantcv/plantcv/__init__.py
+++ b/plantcv/plantcv/__init__.py
@@ -1,8 +1,5 @@
 import os
 import matplotlib
-# If there is no display or a matplotlib backend already defined, use the non-GUI backend
-if "DISPLAY" not in os.environ and "MPLBACKEND" not in os.environ:
-    matplotlib.use("Agg")
 
 observations = {}
 
diff --git a/plantcv/plantcv/plot_image.py b/plantcv/plantcv/plot_image.py
index f145b8d1..b13239c2 100755
--- a/plantcv/plantcv/plot_image.py
+++ b/plantcv/plantcv/plot_image.py
@@ -23,14 +23,17 @@ def plot_image(img, cmap=None):
         matplotlib.rcParams['figure.dpi'] = params.dpi
         # If the image is color then OpenCV stores it as BGR, we plot it as RGB
         if len(dimensions) == 3:
+            plt.figure()
             plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
             plt.show()
 
         elif cmap is None and len(dimensions) == 2:
+            plt.figure()
             plt.imshow(img, cmap="gray")
             plt.show()
 
         elif cmap is not None and len(dimensions) == 2:
+            plt.figure()
             plt.imshow(img, cmap=cmap)
             plt.show()
 
diff --git a/plantcv/plantcv/threshold/threshold_methods.py b/plantcv/plantcv/threshold/threshold_methods.py
index e12be5bb..3e8f5ad9 100644
--- a/plantcv/plantcv/threshold/threshold_methods.py
+++ b/plantcv/plantcv/threshold/threshold_methods.py
@@ -245,10 +245,11 @@ def triangle(gray_img, max_value, object_type="light", xstep=1):
     # Additional figures created by this method, if debug is on
     if params.debug is not None:
         if params.debug == 'print':
-            plt.plot(hist)
-            plt.title('Threshold value = {t}'.format(t=autothreshval))
-            plt.axis([0, 256, 0, max(hist)])
-            plt.grid(True)
+            _, ax = plt.subplots()
+            ax.plot(hist)
+            ax.set(title='Threshold value = {t}'.format(t=autothreshval))
+            ax.axis([0, 256, 0, max(hist)])
+            ax.grid(True)
             fig_name_hist = os.path.join(params.debug_outdir,
                                          str(params.device) + '_triangle_thresh_hist_' + str(autothreshval) + ".png")
             # write the figure to current directory
@@ -257,9 +258,10 @@ def triangle(gray_img, max_value, object_type="light", xstep=1):
             plt.clf()
         elif params.debug == 'plot':
             print('Threshold value = {t}'.format(t=autothreshval))
-            plt.plot(hist)
-            plt.axis([0, 256, 0, max(hist)])
-            plt.grid(True)
+            _, ax = plt.subplots()
+            ax.plot(hist)
+            ax.axis([0, 256, 0, max(hist)])
+            ax.grid(True)
             plt.show()
 
     return bin_img
diff --git a/plantcv/plantcv/visualize/pseudocolor.py b/plantcv/plantcv/visualize/pseudocolor.py
index 3c4ceb40..87c42b49 100644
--- a/plantcv/plantcv/visualize/pseudocolor.py
+++ b/plantcv/plantcv/visualize/pseudocolor.py
@@ -112,8 +112,9 @@ def pseudocolor(gray_img, obj=None, mask=None, cmap=None, background="image", mi
             fatal_error(
                 "Background type {0} is not supported. Please use 'white', 'black', or 'image'.".format(background))
 
+        plt.figure()
         # Pseudocolor the image, plot the background first
-        pseudo_img1 = plt.imshow(bkg_img, cmap=bkg_cmap)
+        plt.imshow(bkg_img, cmap=bkg_cmap)
         # Overlay the masked grayscale image with the user input colormap
         plt.imshow(masked_img, cmap=cmap, vmin=min_value, vmax=max_value)
 
@@ -131,20 +132,10 @@ def pseudocolor(gray_img, obj=None, mask=None, cmap=None, background="image", mi
         # Store the current figure
         pseudo_img = plt.gcf()
 
-        # Print or plot if debug is turned on
-        if params.debug == 'print':
-            plt.savefig(os.path.join(params.debug_outdir, str(params.device) + '_pseudocolored.png'), dpi=params.dpi)
-            plt.close()
-        elif params.debug == 'plot':
-            plot_image(pseudo_img1)
-            # Use non-blocking mode in case the function is run more than once
-            plt.show(block=False)
-        elif params.debug is None:
-            plt.show(block=False)
-
     else:
+        plt.figure()
         # Pseudocolor the image
-        pseudo_img1 = plt.imshow(gray_img1, cmap=cmap, vmin=min_value, vmax=max_value)
+        plt.imshow(gray_img1, cmap=cmap, vmin=min_value, vmax=max_value)
 
         if colorbar:
             # Include the colorbar
@@ -160,16 +151,17 @@ def pseudocolor(gray_img, obj=None, mask=None, cmap=None, background="image", mi
 
         pseudo_img = plt.gcf()
 
-        # Print or plot if debug is turned on
+
+    # Print or plot if debug is turned on
+    if params.debug is not None:
         if params.debug == 'print':
-            plt.savefig(os.path.join(params.debug_outdir, str(params.device) + '_pseudocolored.png'), dpi=params.dpi)
-            pseudo_img.clear()
+            plt.savefig(os.path.join(params.debug_outdir, str(
+                params.device) + '_pseudocolored.png'), dpi=params.dpi)
             plt.close()
         elif params.debug == 'plot':
-            plot_image(pseudo_img1)
             # Use non-blocking mode in case the function is run more than once
             plt.show(block=False)
-        elif params.debug is None:
-            plt.show(block=False)
+    else:
+        plt.close()
 
     return pseudo_img