當光標懸停在matplotlib圖上時,是否可以綁定滾輪以放大/縮小?使用滾輪縮放Matplotlib plot
回答
這應該工作。當您滾動時,它將圖形重新居中在指針位置上。
import matplotlib.pyplot as plt
def zoom_factory(ax,base_scale = 2.):
def zoom_fun(event):
# get the current x and y limits
cur_xlim = ax.get_xlim()
cur_ylim = ax.get_ylim()
cur_xrange = (cur_xlim[1] - cur_xlim[0])*.5
cur_yrange = (cur_ylim[1] - cur_ylim[0])*.5
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
elif event.button == 'down':
# deal with zoom out
scale_factor = base_scale
else:
# deal with something that should never happen
scale_factor = 1
print event.button
# set new limits
ax.set_xlim([xdata - cur_xrange*scale_factor,
xdata + cur_xrange*scale_factor])
ax.set_ylim([ydata - cur_yrange*scale_factor,
ydata + cur_yrange*scale_factor])
plt.draw() # force re-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
假設你有一個軸對象ax
ax.plot(range(10))
scale = 1.5
f = zoom_factory(ax,base_scale = scale)
可選參數base_scale
允許您設置比例因子是你什麼都想要。
請確保您保留了f
的副本。回電使用弱引用,所以如果你不保留副本f
它可能會被垃圾收集。
寫這個答案後,我決定這其實非常有用,並把它放在一個gist
我也是獨立做的! 我希望我早點檢查過SO。我也想貢獻一下。 – RodericDay 2012-10-08 14:51:14
@RodericDay你可以抓住要點,讓它變得更好 – tacaswell 2012-10-08 15:08:44
我不是在提交真實代碼給其他人使用的階段,但是我會在下面的情況下推薦一個修正,以防用戶對相對座標感興趣 – RodericDay 2012-10-09 04:54:49
def zoom(self, event, factor):
curr_xlim = self.ax.get_xlim()
curr_ylim = self.ax.get_ylim()
new_width = (curr_xlim[1]-curr_ylim[0])*factor
new_height= (curr_xlim[1]-curr_ylim[0])*factor
relx = (curr_xlim[1]-event.xdata)/(curr_xlim[1]-curr_xlim[0])
rely = (curr_ylim[1]-event.ydata)/(curr_ylim[1]-curr_ylim[0])
self.ax.set_xlim([event.xdata-new_width*(1-relx),
event.xdata+new_width*(relx)])
self.ax.set_ylim([event.ydata-new_width*(1-rely),
event.ydata+new_width*(rely)])
self.draw()
的這種稍微改變代碼的目的是跟蹤相對光標的位置到新的縮放中心。這樣,如果您在中心以外的位置放大和縮小圖片,則可以保持在同一點上。
謝謝你們,這些例子非常有幫助。我不得不做一些改變來處理散點圖,並用左鍵拖動來添加平移。希望有人會覺得這很有用。
from matplotlib.pyplot import figure, show
import numpy
class ZoomPan:
def __init__(self):
self.press = None
self.cur_xlim = None
self.cur_ylim = None
self.x0 = None
self.y0 = None
self.x1 = None
self.y1 = None
self.xpress = None
self.ypress = None
def zoom_factory(self, ax, base_scale = 2.):
def zoom(event):
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 == 'down':
# deal with zoom in
scale_factor = 1/base_scale
elif event.button == 'up':
# deal with zoom out
scale_factor = base_scale
else:
# deal with something that should never happen
scale_factor = 1
print event.button
new_width = (cur_xlim[1] - cur_xlim[0]) * scale_factor
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])
ax.set_xlim([xdata - new_width * (1-relx), xdata + new_width * (relx)])
ax.set_ylim([ydata - new_height * (1-rely), ydata + new_height * (rely)])
ax.figure.canvas.draw()
fig = ax.get_figure() # get the figure of interest
fig.canvas.mpl_connect('scroll_event', zoom)
return zoom
def pan_factory(self, ax):
def onPress(event):
if event.inaxes != ax: return
self.cur_xlim = ax.get_xlim()
self.cur_ylim = ax.get_ylim()
self.press = self.x0, self.y0, event.xdata, event.ydata
self.x0, self.y0, self.xpress, self.ypress = self.press
def onRelease(event):
self.press = None
ax.figure.canvas.draw()
def onMotion(event):
if self.press is None: return
if event.inaxes != ax: return
dx = event.xdata - self.xpress
dy = event.ydata - self.ypress
self.cur_xlim -= dx
self.cur_ylim -= dy
ax.set_xlim(self.cur_xlim)
ax.set_ylim(self.cur_ylim)
ax.figure.canvas.draw()
fig = ax.get_figure() # get the figure of interest
# attach the call back
fig.canvas.mpl_connect('button_press_event',onPress)
fig.canvas.mpl_connect('button_release_event',onRelease)
fig.canvas.mpl_connect('motion_notify_event',onMotion)
#return the function
return onMotion
fig = figure()
ax = fig.add_subplot(111, xlim=(0,1), ylim=(0,1), autoscale_on=False)
ax.set_title('Click to zoom')
x,y,s,c = numpy.random.rand(4,200)
s *= 200
ax.scatter(x,y,s,c)
scale = 1.1
zp = ZoomPan()
figZoom = zp.zoom_factory(ax, base_scale = scale)
figPan = zp.pan_factory(ax)
show()
非常感謝。這很好。但是,對於比例尺不再是線性的地塊(例如日誌圖),這會發生故障。我爲此寫了一個新版本。我希望它能幫助別人。
基本上,我放大了標準化爲[0,1]的軸座標。所以,如果我用x放大兩倍,我現在想要在[.25,.75]範圍內。 我還添加了一個功能,如果您直接位於x軸的上方或下方,則只放大x;如果您直接位於y軸的左側或右側,則只在y中放大。如果你不需要這個,只需設置zoomx = True和zoomy = True並忽略if語句。
此引用的,誰想要了解matplotlib不同的座標系之間是如何將是非常有用的:http://matplotlib.org/users/transforms_tutorial.html
此函數是一個包含一個指向軸(self.ax)的對象內。
def zoom(self,event):
'''This function zooms the image upon scrolling the mouse wheel.
Scrolling it in the plot zooms the plot. Scrolling above or below the
plot scrolls the x axis. Scrolling to the left or the right of the plot
scrolls the y axis. Where it is ambiguous nothing happens.
NOTE: If expanding figure to subplots, you will need to add an extra
check to make sure you are not in any other plot. It is not clear how to
go about this.
Since we also want this to work in loglog plot, we work in axes
coordinates and use the proper scaling transform to convert to data
limits.'''
x = event.x
y = event.y
#convert pixels to axes
tranP2A = self.ax.transAxes.inverted().transform
#convert axes to data limits
tranA2D= self.ax.transLimits.inverted().transform
#convert the scale (for log plots)
tranSclA2D = self.ax.transScale.inverted().transform
if event.button == 'down':
# deal with zoom in
scale_factor = self.zoom_scale
elif event.button == 'up':
# deal with zoom out
scale_factor = 1/self.zoom_scale
else:
# deal with something that should never happen
scale_factor = 1
#get my axes position to know where I am with respect to them
xa,ya = tranP2A((x,y))
zoomx = False
zoomy = False
if(ya < 0):
if(xa >= 0 and xa <= 1):
zoomx = True
zoomy = False
elif(ya <= 1):
if(xa <0):
zoomx = False
zoomy = True
elif(xa <= 1):
zoomx = True
zoomy = True
else:
zoomx = False
zoomy = True
else:
if(xa >=0 and xa <= 1):
zoomx = True
zoomy = False
new_alimx = (0,1)
new_alimy = (0,1)
if(zoomx):
new_alimx = (np.array([1,1]) + np.array([-1,1])*scale_factor)*.5
if(zoomy):
new_alimy = (np.array([1,1]) + np.array([-1,1])*scale_factor)*.5
#now convert axes to data
new_xlim0,new_ylim0 = tranSclA2D(tranA2D((new_alimx[0],new_alimy[0])))
new_xlim1,new_ylim1 = tranSclA2D(tranA2D((new_alimx[1],new_alimy[1])))
#and set limits
self.ax.set_xlim([new_xlim0,new_xlim1])
self.ax.set_ylim([new_ylim0,new_ylim1])
self.redraw()
我真的很喜歡圖中的「x only」或「y only」模式。您可以綁定x和y鍵,以便縮放只發生在一個方向上。請注意,您可能還需要將焦點放回在畫布上,如果你點擊一個條目框或東西 -
canvas.mpl_connect('button_press_event', lambda event:canvas._tkcanvas.focus_set())
修改後的代碼的其餘部分是如下:
from matplotlib.pyplot import figure, show
import numpy
class ZoomPan:
def __init__(self):
self.press = None
self.cur_xlim = None
self.cur_ylim = None
self.x0 = None
self.y0 = None
self.x1 = None
self.y1 = None
self.xpress = None
self.ypress = None
self.xzoom = True
self.yzoom = True
self.cidBP = None
self.cidBR = None
self.cidBM = None
self.cidKeyP = None
self.cidKeyR = None
self.cidScroll = None
def zoom_factory(self, ax, base_scale = 2.):
def zoom(event):
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(xdata is None):
return()
if(ydata is None):
return()
if event.button == 'down':
# deal with zoom in
scale_factor = 1/base_scale
elif event.button == 'up':
# deal with zoom out
scale_factor = base_scale
else:
# deal with something that should never happen
scale_factor = 1
print(event.button)
new_width = (cur_xlim[1] - cur_xlim[0]) * scale_factor
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(self.xzoom):
ax.set_xlim([xdata - new_width * (1-relx), xdata + new_width * (relx)])
if(self.yzoom):
ax.set_ylim([ydata - new_height * (1-rely), ydata + new_height * (rely)])
ax.figure.canvas.draw()
ax.figure.canvas.flush_events()
def onKeyPress(event):
if event.key == 'x':
self.xzoom = True
self.yzoom = False
if event.key == 'y':
self.xzoom = False
self.yzoom = True
def onKeyRelease(event):
self.xzoom = True
self.yzoom = True
fig = ax.get_figure() # get the figure of interest
self.cidScroll = fig.canvas.mpl_connect('scroll_event', zoom)
self.cidKeyP = fig.canvas.mpl_connect('key_press_event',onKeyPress)
self.cidKeyR = fig.canvas.mpl_connect('key_release_event',onKeyRelease)
return zoom
def pan_factory(self, ax):
def onPress(event):
if event.inaxes != ax: return
self.cur_xlim = ax.get_xlim()
self.cur_ylim = ax.get_ylim()
self.press = self.x0, self.y0, event.xdata, event.ydata
self.x0, self.y0, self.xpress, self.ypress = self.press
def onRelease(event):
self.press = None
ax.figure.canvas.draw()
def onMotion(event):
if self.press is None: return
if event.inaxes != ax: return
dx = event.xdata - self.xpress
dy = event.ydata - self.ypress
self.cur_xlim -= dx
self.cur_ylim -= dy
ax.set_xlim(self.cur_xlim)
ax.set_ylim(self.cur_ylim)
ax.figure.canvas.draw()
ax.figure.canvas.flush_events()
fig = ax.get_figure() # get the figure of interest
self.cidBP = fig.canvas.mpl_connect('button_press_event',onPress)
self.cidBR = fig.canvas.mpl_connect('button_release_event',onRelease)
self.cidBM = fig.canvas.mpl_connect('motion_notify_event',onMotion)
# attach the call back
#return the function
return onMotion
這是對上述代碼進行細微修改的建議 - 它使得縮放居中更易於管理。
cur_xrange = (cur_xlim[1] - cur_xlim[0])*.5
cur_yrange = (cur_ylim[1] - cur_ylim[0])*.5
xmouse = event.xdata # get event x location
ymouse = event.ydata # get event y location
cur_xcentre = (cur_xlim[1] + cur_xlim[0])*.5
cur_ycentre = (cur_ylim[1] + cur_ylim[0])*.5
xdata = cur_xcentre+ 0.25*(xmouse-cur_xcentre)
ydata = cur_ycentre+ 0.25*(ymouse-cur_ycentre)
- 1. 縮放滾輪
- 2. 使用鼠標滾輪縮放圖像。
- 3. 使用滾輪放大/縮小
- 4. 在java中使用滾輪縮放
- 5. GMMap使用鼠標滾輪縮放。
- 6. 如何使用鼠標滾輪啓用縮放功能?
- 7. 在電子應用中使用Ctrl +滾輪縮放?
- 8. D3.js:使用鼠標滾輪縮放x軸和數據
- 9. Matplotlib subplot:imshow + plot
- 10. 2D plot with matplotlib
- 11. 1D plot matplotlib
- 12. 縮放地塊matplotlib
- 13. Matplotlib自動縮放
- 14. 縮放的輪廓
- 15. Python plot使用matplotlib的大矩陣
- 16. 使用鼠標滾輪放大
- 17. MatPlotLib Plot w/Python Tkinter
- 18. jQuery圖像縮放與鼠標滾輪或觸摸滾動
- 19. 使用自定義縮放欄時,如何讓Google地圖使用滾輪縮放?
- 20. Google地圖應該禁用滾輪縮放嗎?
- 21. 如何禁用Google街景上的鼠標滾輪縮放?
- 22. 禁用鼠標滾輪縮放與谷歌地圖v3在infowindow
- 23. 如何啓用鼠標滾輪縮放mapbox?
- 24. 如何禁用鼠標滾輪縮放Google註釋時間軸?
- 25. Core-Plot:2Y繪圖縮放問題
- 26. 使用pcolormesh和輪廓的Matplotlib動畫
- 27. Angular + UI排序列表:CTRL-鼠標滾輪縮放比正常鼠標滾輪縮小
- 28. 如何通過使用鼠標滾輪啓用縮放Microsoft圖表控件
- 29. 使用Google Maps API在地圖上啓用滾輪縮放功能
- 30. 使用Core Plot獨立(非均勻)縮放X和Y軸
您可以編寫一個回調函數做http://matplotlib.sourceforge.net/api/backend_bases_api.html?highlight=mpl_connect#matplotlib.backend_bases.FigureCanvasBase.mpl_connect – tacaswell 2012-07-18 22:39:55
任何的例子? – dimka 2012-07-18 22:42:35