Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing lines between clicks on image with Matplotlib

I am trying to allow for a user to right click on an image once, and then again, and then the program will draw a line from the first click to the second.

However, what I have now, inserts lines into my image seemingly randomly. They pop up and they are nowhere near my clicks, and are of random lengths and angles.

I'm sort of a beginner to python and definitely to matplotlib, so any help would be appreciated. Below is my code, with the relevant area marked with a line of #s:

from pymouse import PyMouse
import matplotlib.pyplot as plt
import matplotlib.lines as lines
import numpy


im1 = plt.imread('xexample1.PNG')
im2 = plt.imread('xexample2.PNG')
im3 = plt.imread('xexample3.PNG')
data_images = [im1,im2,im3]


index = 0
ax = plt.gca()
fig = plt.gcf()
plt.imshow(data_images[index])


linepoints = numpy.array([])
print linepoints




#on click event- print x,y coords
def onclick(event):
   # if event.xdata != None and event.ydata != None:
    plot = numpy.asarray(data_images[index])

    if event.button == 1:            
        print("IMAGE: %d" %index, event.xdata, event.ydata,(plot[event.xdata][event.ydata])*255)
######################################################################
    if event.button == 3:
        global linepoints

        x = event.xdata
        y = event.ydata
        tup1 = [(x, y)]

        linepoints = numpy.append(linepoints, x)
        linepoints = numpy.append(linepoints, y)

        if numpy.size(linepoints) == 4:
           # print "full"
            #l1 = lines.Line2D([linepoints[0], linepoints[1]], [linepoints[2],linepoints[3]], transform=fig.transFigure, figure=plt)
            #fig.canvas.draw()
            plt.plot((linepoints[0], linepoints[1]), (linepoints[2], linepoints[3]), '-')

            print linepoints
            linepoints = numpy.array([])


        print linepoints
       # plt.show()
######################################################################
def toggle_images(event):
    global index


    if event.key == 'x':
        index += 1

        if index < len(data_images) and index >= 0:
            plt.imshow(data_images[index])
            plt.draw()

        else:
            #plt.close()
            print 'out of range'
            index -= 1


    if event.key == 'z':
        index -= 1

        if index < len(data_images) and index >= 0:
            plt.imshow(data_images[index])
            plt.draw()

        else:
            #plt.close()
            print 'out of range'
            index += 1

plt.imshow(data_images[index])
plt.connect('key_press_event',toggle_images)
cid = fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()
like image 484
Max Avatar asked Dec 03 '25 17:12

Max


1 Answers

I created a dressed-down version attached below, but in the end there was only a very minor mistake in your code:

plt.plot((linepoints[0], linepoints[1]), (linepoints[2], linepoints[3]), '-')

needed to be:

plt.plot((linepoints[0], linepoints[2]), (linepoints[1], linepoints[3]), '-')

I.e.; your 1st (index 0) and 3rd (index 2) values are the x values and 2nd (index 1) and fourth (index 3) are the y values, now you were actually plotting (x0,y0),(x1,y1) instead of (x0,x1),(y0,y1)

My minimal example:

import matplotlib.pyplot as plt
import numpy

plt.close('all')

fake_img = numpy.random.random((10,10))

plt.imshow(fake_img, interpolation='none')
ax  = plt.gca()
fig = plt.gcf()

linepoints = numpy.array([])

def onclick(event):
    if event.button == 3:
        global linepoints

        x = event.xdata
        y = event.ydata

        linepoints = numpy.append(linepoints, x)
        linepoints = numpy.append(linepoints, y)

        if numpy.size(linepoints) == 4:
            plt.plot((linepoints[0], linepoints[2]), (linepoints[1], linepoints[3]), '-')
            linepoints = numpy.array([])
            plt.show()

cid = fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()
like image 123
Bart Avatar answered Dec 07 '25 05:12

Bart