继上一篇在 Java 中缩放拖动图片后,在python matplotlib中也来实现一个自由缩放拖动的例子:
python matplotlib 中缩放,较为简单,只需要通过设置要显示的 x y坐标的显示范围即可。基于此,实现一个鼠标监听回调,在回调中计算滚轮缩放或者鼠标拖动之后的坐标范围,即可。
效果:
上代码:
- import matplotlib.pyplot as plt
- import matplotlib as mpl
-
- from matplotlib.text import Text, Annotation
- from matplotlib.patches import Polygon, Rectangle, Circle, Arrow, ConnectionPatch,Ellipse,FancyBboxPatch
- from matplotlib.widgets import Button, Slider, Widget
-
- # https://www.python100.com/html/85915.html
- # patches 是matplotlib里面的一个库,里面有基本图形绘制, Polygon:多边形 Rectangle:矩形 Circle:圆 Arrow:箭头 ConnecctionPatch:链接线 Ellipse:椭圆
-
- fig = plt.figure()
- ax = fig.add_subplot(111)
-
- rect = Rectangle((0.1,0.1),1,1,color='yellow')
- ax.add_patch(rect)
-
- rect2 = Circle((1.5,1.5),0.2,color='red')
- ax.add_patch(rect2)
-
- arrow = ConnectionPatch((1,3),(1.8,1.8), "data", "data", clip_on=True,
- arrowstyle="-|>", shrinkA=5, shrinkB=5, mutation_scale=20, fc="w")
- arrow.set_annotation_clip(False)
- ax.add_patch(arrow)
-
- fancybox = FancyBboxPatch((2,2),width=1,height=1, boxstyle=mpl.patches.BoxStyle("Round", pad=0.2),color='green')
- ax.add_patch(fancybox)
-
- ax.text(2, 0.2, 'Hello World')
-
- startx=0
- starty=0
- mPress=False
- def call_move(event):
- # print(event.name)
- global mPress
- global startx
- global starty
- # print(mPress)
- if event.name=='button_press_event':
- axtemp=event.inaxes
- if axtemp and event.button==1:
- print(event)
- mPress=True
- startx=event.xdata
- starty=event.ydata
- elif event.name=='button_release_event':
- axtemp=event.inaxes
- if axtemp and event.button==1:
- mPress=False
- elif event.name=='motion_notify_event':
- axtemp=event.inaxes
- if axtemp and event.button==1 and mPress:
- x_min, x_max = axtemp.get_xlim()
- y_min, y_max = axtemp.get_ylim()
- w=x_max-x_min
- h=y_max-y_min
- # print(event)
- # 移动
- mx=event.xdata-startx
- my=event.ydata-starty
- # 注意这里, -mx, 因为下一次 motion事件的坐标,已经是在本次做了移动之后的坐标系了,所以要体现出来
- # startx=event.xdata-mx startx=event.xdata-(event.xdata-startx)=startx, 没必要再赋值了
- # starty=event.ydata-my
- # print(mx,my,x_min,y_min,w,h)
- axtemp.set(xlim=(x_min-mx, x_min-mx+w))
- axtemp.set(ylim=(y_min-my, y_min-my+h))
- fig.canvas.draw_idle() # 绘图动作实时反映在图像上
- return
-
-
- def call_scroll(event):
- print(event.name)
- axtemp=event.inaxes
- print('event:',event)
- print(event.xdata,event.ydata)
- # 计算放大缩小后, xlim 和ylim
- if axtemp:
- x_min, x_max = axtemp.get_xlim()
- y_min, y_max = axtemp.get_ylim()
- w = x_max - x_min
- h = y_max - y_min
- curx=event.xdata
- cury=event.ydata
- curXposition=(curx - x_min) / w
- curYposition=(cury - y_min) / h
- if event.button == 'down':
- print('befor:',w,h)
- w = w*1.1
- h = h*1.1
- print('down',w,h)
- elif event.button == 'up':
- print('befor:',w,h)
- w = w/1.1
- h = h/1.1
- print('up',w,h)
- print(curXposition,curYposition)
- newx=curx - w*curXposition
- newy=cury - h*curYposition
- axtemp.set(xlim=(newx, newx+w))
- axtemp.set(ylim=(newy, newy+h))
- fig.canvas.draw_idle() # 绘图动作实时反映在图像上
- fig.canvas.mpl_connect('scroll_event', call_scroll)
- fig.canvas.mpl_connect('button_press_event', call_move)
- fig.canvas.mpl_connect('button_release_event', call_move)
- # fig.canvas.mpl_connect('draw_event', call_move)
- fig.canvas.mpl_connect('motion_notify_event', call_move)
-
- # 我们可以最后来设置 x y 轴的初始大小范围
- ax.set_xlim(0,10)
- ax.set_ylim(0,10)
-
- plt.show()
-
-
注意:上面demo监听的是 鼠标左键拖动, event.button==1 这个会导致和原版的工具栏 放大镜 工具冲突,所以也可以 把 event.button == 3 用鼠标右键来判断 (1 是左键,2是中间滚轮按下去键,3是右键。)