Home > Back-end >  Grab and plot 2D array's values crossed by a segment on matplotlib
Grab and plot 2D array's values crossed by a segment on matplotlib

Time:08-16

Goal: Plot the values of a 2D array's cells crossed by a segment.

How: With Matplotlib, plot the 2D array (with imshow), grab the coordinates of 2 points defining the segment (with plt.ginput()), and input them in line() from skimage.draw. Then, plot the cells' values below the image of the 2D array.

Problem: The script works until plotting the cell's values, then it freezes without giving an error. I do not know how to solve this issue.

Question: how could I obtain the kind of plot like displayed on the figure below ? Where is the error in my code ? What I would like to get

Here is my code with the bug. If you comment out the section as indicated, it will work but not as intended.

import time
from skimage.draw import line
import numpy as np
import matplotlib.pyplot as plt

# Create array used for the plot
rough = np.random.randn(100,100)

# Function to give instructions in the plot
def tellme(s):
    print(s)
    a0.set_title(s, fontsize=16)
    plt.draw()

# Create a figure with 2 subplots: the image, and the plot of the transect's values
f, (a0, a1) = plt.subplots(2, 1, gridspec_kw={'height_ratios': [3, 1]})
a0.imshow(rough, vmax = 10)

# Allow 1 click-and-drag to zoom. If you don't want to zoom, simply click once
tellme('Zoom in an area if you want')
plt.waitforbuttonpress() 

# Select two points that will be the extremities of the transect
tellme('Select two points that will be the extremities of a transect')
while True:
    pts = []
    while len(pts) < 2:
        pts = np.asarray(plt.ginput(2, timeout=-1))
        if len(pts) < 2:
            tellme('Too few points, starting over')
            time.sleep(1)  # Wait a second
    
    tellme('Happy? Key click for yes, mouse click for no')
    
    if plt.waitforbuttonpress():
        break


# Allow a buffer before retrieving the array's cells crossed by the transect
plt.waitforbuttonpress() 
tellme('Please wait')

# Plot the transect
CS = a0.plot(pts[:,0], pts[:,1], color='red')


#### Leave this section to get the code that does not work. If you want the 
#### code that works, comment it out.

while True:

    # Convert the transect's extremities coordinates to integers in order to use the line() function
    pts = np.array(pts, dtype = int)
    # Retrieve the coordinates of the transect's extremities
    rr, cc = line(pts[0,0], pts[0,1], pts[1,0], pts[1,1])
    # Plot in the 2nd subplot the values of the cells crossed by the transect
    
    a1.plot(rough[rr,cc])
    a1.set_title('Values cells segment')

# Buffer before closing the figure
plt.waitforbuttonpress() 

plt.close()

####



#### De-comment this section to get the working script.

#plt.close()
## Convert the transect's extremities coordinates to integers in order to use the line() function
#pts = np.array(pts, dtype = int)
## Retrieve the coordinates of the transect's extremities
#rr, cc = line(pts[0,0], pts[0,1], pts[1,0], pts[1,1])
## Plot in the 2nd subplot the values of the cells crossed by the transect
#plt.figure()
#plt.plot(rough[rr,cc])

####

CodePudding user response:

then it freezes without giving an error

this is because your code is in an endless loop (the second while True)

Here is a working version with some tweaks (keep line end points visible during dialog, constrained layout, final title to press key to quit):

import time
from skimage.draw import line
import numpy as np
import matplotlib.pyplot as plt

# Create array used for the plot
rough = np.random.randn(100,100)

# Function to give instructions in the plot
def tellme(s):
    print(s)
    a0.set_title(s, fontsize=16)
    plt.draw()

# Create a figure with 2 subplots: the image, and the plot of the transect's values
f, (a0, a1) = plt.subplots(2, 1, gridspec_kw={'height_ratios': [3, 1]}, layout='constrained')
a0.imshow(rough, vmax = 10)

# Allow 1 click-and-drag to zoom. If you don't want to zoom, simply click once
tellme('Zoom in an area if you want')
plt.waitforbuttonpress()

# Select two points that will be the extremities of the transect
tellme('Select two points that will be the extremities of a transect')
while True:
    pts = []
    if 'p' in locals():
       p.remove()
       plt.draw()
    while len(pts) < 2:
        pts = np.asarray(plt.ginput(2, timeout=-1))
        if len(pts) < 2:
            tellme('Too few points, starting over')
            time.sleep(1)  # Wait a second

    tellme('Happy? Key click for yes, mouse click for no')
    p, = a0.plot(pts[:,0], pts[:,1], 'r ')

    if plt.waitforbuttonpress():
        break

# Plot the transect
CS = a0.plot(pts[:,0], pts[:,1], color='red')

# Retrieve the coordinates of the transect's extremities
pts = pts.astype(int)
rr, cc = line(pts[0,0], pts[0,1], pts[1,0], pts[1,1])

# Plot in the 2nd subplot the values of the cells crossed by the transect
a1.plot(rough[rr,cc])
a1.set_title('Values cells segment')

# Buffer before closing the figure
tellme('Press any key to quit')
plt.waitforbuttonpress()

plt.close() 
  • Related