-1

I have two imshow() problems that I suspect are closely related.

First, I can't figure out how to use set_data() to update an image I've created with imshow().

Second, I can't figure out why the colorbar I add to the imshow() plot after I'm done updating the plot doesn't match the colorbar I add to an imshow() plot of the same data that I create from scratch after I'm done taking data. The colorbar of the second plot appears to be correct.

Background.

I'm collecting measurement data in two nested loops, with each loop controlling one of the measurement conditions. I'm using pyplot.imshow() to plot my results, and I'm updating the imshow() plot every time I take data in the inner loop.

What I have works in terms of updating the imshow() plot but it seems to be getting increasingly slower as I add more loop iterations, so it's not scaling well. (The program I've included in with this post creates a plot that is eight rows high and six columns wide. A "real" plot might be 10x or 20x this size, in both dimensions.)

I think what I want to do is use the image's set_data() method but I can't figure out how. What I've tried either throws an error or doesn't appear to have any effect on the imshow() plot.

Once I'm done with the "take the data" loops, I add a colorbar to the imshow() plot I've been updating. However, the colorbar scale is obviously bogus.

In contrast, if I take create an entirely new imshow() plot, using the data I took in the loops, and then add a colorbar, the colorbar appears to be correct.

My hunch is the problem is with the vmin and vmax values associated with the imshow() plot I'm updating in the loops but I can't figure out how to fix it.

I've already looked at several related StackOverflow posts. For example:

These have helped, in that they've pointed me to set_data() and given me solutions to some other problems I had, but I still have the two problems I mentioned at the start.

Here's a simplified version of my code. Note that there are repeated zero values on the X and Y axes. This is on purpose.

I'm running Python 3.5.1, matplotlib 1.5.1, and numpy 1.10.4. (Yes, some of these are quite old. Corporate IT reasons.)

import numpy as np
import matplotlib.pyplot as plt
import random
import time
import warnings

warnings.filterwarnings("ignore", ".*GUI is implemented.*")  # Filter out bogus matplotlib warning.

# Create the simulated data for plotting

v_max = 120
v_step_size = 40
h_max = 50
h_step_size = 25
scale = 8

v_points = np.arange(-1*abs(v_max), 0, abs(v_step_size))
v_points = np.append(v_points, [-0.0])
reversed_v_points = -1 * v_points[::-1]  # Not just reverse order, but reversed sign
v_points = np.append(v_points, reversed_v_points)

h_points = np.arange(-1*abs(h_max), 0, abs(h_step_size))
h_points = np.append(h_points, [-0.0])
reversed_h_points = -1 * h_points[::-1]  # Not just reverse order, but reversed sign
h_points = np.append(h_points, reversed_h_points)

h = 0  # Initialize
v = 0  # Initialize

plt.ion()  # Turn on interactive mode.
fig, ax = plt.subplots()  # So I have access to the figure and the axes of the plot.

# Initialize the data_points
data_points = np.zeros((v_points.size, h_points.size))
im = ax.imshow(data_points, cmap='hot', interpolation='nearest')  # Specify the color map and interpolation
ax.set_title('Dummy title for initial plot')

# Set up the X-axis ticks and label them
ax.set_xticks(np.arange(len(h_points)))
ax.set_xticklabels(h_points)
ax.set_xlabel('Horizontal axis measurement values')

# Set up the Y-axis ticks and label them
ax.set_yticks(np.arange(len(v_points)))
ax.set_yticklabels(v_points)
ax.set_ylabel('Vertical axis measurement values')

plt.pause(0.0001)  # In interactive mode, need a small delay to get the plot to appear
plt.show()

for v, v_value in enumerate(v_points):
    for h, h_value in enumerate(h_points):

        # Measurement goes here.
        time.sleep(0.1)  # Simulate the measurement delay.
        measured_value = scale * random.uniform(0.0, 1.0)  # Create simulated data
        data_points[v][h] = measured_value  # Update data_points with the simulated data

        # Update the heat map with the latest point.
        #  - I *think* I want to use im.set_data() here, not ax.imshow(), but how?
        ax.imshow(data_points, cmap='hot', interpolation='nearest')  # Specify the color map and interpolation

        plt.pause(0.0001)  # In interactive mode, need a small delay to get the plot to appear
        plt.draw()

# Create a colorbar
#   - Except the colorbar here is wrong.  It goes from -0.10 to +0.10 instead
#     of matching the colorbar in the second imshow() plot, which goes from
#     0.0 to "scale".  Why?
cbar = ax.figure.colorbar(im, ax=ax)
cbar.ax.set_ylabel('Default heatmap colorbar label')
plt.pause(0.0001)  # In interactive mode, need a small delay to get the colorbar to appear
plt.show()

fig2, ax2 = plt.subplots()  # So I have access to the figure and the axes of the plot.
im = ax2.imshow(data_points, cmap='hot', interpolation='nearest')  # Specify the color map and interpolation
ax2.set_title('Dummy title for plot with pseudo-data')

# Set up the X-axis ticks and label them
ax2.set_xticks(np.arange(len(h_points)))
ax2.set_xticklabels(h_points)
ax2.set_xlabel('Horizontal axis measurement values')

# Set up the Y-axis ticks and label them
ax2.set_yticks(np.arange(len(v_points)))
ax2.set_yticklabels(v_points)
ax2.set_ylabel('Vertical axis measurement values')

# Create a colorbar
cbar = ax2.figure.colorbar(im, ax=ax2)
cbar.ax.set_ylabel('Default heatmap colorbar label')

plt.pause(0.0001)  # In interactive mode, need a small delay to get the plot to appear
plt.show()

dummy = input("In interactive mode, press the Enter key when you're done with the plots.")
BobInBaltimore
  • 425
  • 5
  • 13

1 Answers1

1

OK, I Googled some more. More importantly, I Googled smarter and figured out my own answer.

To update my plot inside my nested loops, I was using the command:

ax.imshow(data_points, cmap='hot', interpolation='nearest')  # Specify the color map and interpolation

What I tried using to update my plot more efficiently was:

im.set_data(data_points)

What I should have used was:

im.set_data(data_points)
im.autoscale()

This updates the pixel scaling, which fixed both my "plot doesn't update" problem and my "colorbar has the wrong scale" problem.

BobInBaltimore
  • 425
  • 5
  • 13