can Python Matplotlib “ginput” be independent from

2019-05-12 00:54发布

I am using ginput for a graphic selection of a few points along a time signal. Sometimes, when the signal is too dense it might be useful to zoom over an area before making the selection of points. My problem is that it seems that the zoom to rectangle option seems to be accounted for in ginput.

For instance, with this sample code:

from __future__ import print_function
from pylab import arange, plot, sin, ginput, show
import numpy as np

t = np.linspace(0,25,500)
plot(t, sin(t))
x = ginput(3)
print("clicked",x)
show()

If I zoom over a portion of the signal, the clicks made for the zoom area selection are accounted for in ginput... Is there a way to avoid this and make the zoom area selection independent from ginput ?

2条回答
霸刀☆藐视天下
2楼-- · 2019-05-12 01:11

I was having the same issue and my fix was to write a function to zoom with the mouse wheel so I could zoom without clicking. I got the function from this page:

Matplotlib plot zooming with scroll wheel

and modified the function so that it was not zoomed past the original x and y limits:

def zoom_factory(ax, max_xlim, max_ylim, base_scale = 2.):
    def zoom_fun(event):
        # get the current x and y limits
        cur_xlim = ax.get_xlim()
        cur_ylim = ax.get_ylim()
        xdata = event.xdata # get event x location
        ydata = event.ydata # get event y location
        if event.button == 'up':
            # deal with zoom in
            scale_factor = 1/base_scale
            x_scale = scale_factor / 2
        elif event.button == 'down':
            # deal with zoom out
            scale_factor = base_scale
            x_scale = scale_factor * 2
        else:
            # deal with something that should never happen
            scale_factor = 1
            print(event.button)
        # set new limits
        new_width = (cur_xlim[1] - cur_xlim[0]) * x_scale
        new_height = (cur_ylim[1] - cur_ylim[0]) * scale_factor

        relx = (cur_xlim[1] - xdata) / (cur_xlim[1] - cur_xlim[0])
        rely = (cur_ylim[1] - ydata) / (cur_ylim[1] - cur_ylim[0])

        if xdata - new_width * (1 - relx) > max_xlim[0]:
            x_min = xdata - new_width * (1 - relx)
        else:
            x_min = max_xlim[0]
        if xdata + new_width * (relx) < max_xlim[1]:
            x_max = xdata + new_width * (relx)
        else:
            x_max = max_xlim[1]
        if ydata - new_height * (1 - rely) > max_ylim[0]:
            y_min = ydata - new_height * (1 - rely)
        else:
            y_min = max_ylim[0]
        if ydata + new_height * (rely) < max_ylim[1]:
            y_max = ydata + new_height * (rely)
        else:
            y_max = max_ylim[1]
        ax.set_xlim([x_min, x_max])
        ax.set_ylim([y_min, y_max])
        ax.figure.canvas.draw()

    fig = ax.get_figure() # get the figure of interest
    # attach the call back
    fig.canvas.mpl_connect('scroll_event',zoom_fun)

    #return the function
    return zoom_fun

So for a given figure:

t = np.linspace(0,250,5000)
y = sin(t)    

fig = figure()
ax = fig.add_subplot(111)
plt.plot(t,y)

max_xlim = ax.get_xlim() # get current x_limits to set max zoom out
max_ylim = ax.get_ylim() # get current y_limits to set max zoom out
f = zoom_factory(ax, max_xlim, max_ylim, base_scale=1.1)
show()

x = ginput(3)
查看更多
\"骚年 ilove
3楼-- · 2019-05-12 01:25

As I did not get any answer and I could not find much on the topic, here is how I solved this problem: I added a pre-procedure allowing the user to zoom in over a chosen area. When the area is suitable for point picking, the user simply has to press "Enter" and go on with ginput.

from __future__ import print_function
from pylab import arange, plot, sin, ginput, show
import matplotlib as plt  
from pylab import *
import numpy as np

def closest_point(vec,val):
    ind = np.where(vec==min(vec,key=lambda x:abs(x-val)))
    return ind[0][0]

t = np.linspace(0,250,5000)
y = sin(t)

fig = plt.figure()
plt.suptitle('chosing points over a possibly dense signal...',fontsize=14)
zoom_ok = False
while not zoom_ok:
    plt.plot(t,y)
    plt.title('1 - click on the two corners of the area to enlarge',fontsize=12)
    zoom = ginput(2,timeout=-1)
    xzoom = np.zeros([0])
    for i in range(2):
        xzoom = np.concatenate((xzoom,[int(closest_point(t,zoom[i][0]))]))  
    temps_zoom = t[xzoom[0]:xzoom[1]]
    dep_zoom = y[xzoom[0]:xzoom[1]]
    plt.clf()
    plt.plot(temps_zoom,dep_zoom,'b')
    plt.title('2 - if zoom ok -> press Enter, otherwise -> mouse click',fontsize=12)
    zoom_ok = plt.waitforbuttonpress()
plt.title('3 - you may now select the points ',fontsize=16)
x = ginput(2,timeout=-1)
plt.show()  
查看更多
登录 后发表回答