can Python Matplotlib “ginput” be independent from “zoom to rectangle”?

江枫思渺然 提交于 2020-01-13 13:08:42

问题


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 ?


回答1:


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)



回答2:


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()  


来源:https://stackoverflow.com/questions/29145821/can-python-matplotlib-ginput-be-independent-from-zoom-to-rectangle

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!