我之前曾问过“How to zoom subplots together?”这个问题,从那时起就一直在使用优秀的答案。
我现在只绘制两组时间序列数据,我需要继续如上所述进行缩放,但现在我还需要相对于另一个平移一个绘图(我正在进行眼球相关)。数据来自2个独立的仪器,具有不同的启动时间和不同的时钟设置。
在使用中,我使用“缩放到矩形”工具栏按钮进行缩放,然后使用“平移/缩放”按钮进行滚动。
我怎样才能最好地将X中的一个地块相对于另一个绘制?理想情况下,我也想拍摄并显示时差。我不需要在Y中垂直滚动。
我怀疑我可能需要停止使用简单的“sharex =”“sharey =”方法,但我不确定如何最好地继续。
提前感谢StackOverflow社区!
-BobC
答案 0 :(得分:7)
我攻击了上述解决方案,直到它确实想要我想要。
# File: ScrollTest.py
# coding: ASCII
"""
Interatively zoom plots together, but permit them to scroll independently.
"""
from matplotlib import pyplot
import sys
def _get_limits( ax ):
""" Return X and Y limits for the passed axis as [[xlow,xhigh],[ylow,yhigh]]
"""
return [list(ax.get_xlim()), list(ax.get_ylim())]
def _set_limits( ax, lims ):
""" Set X and Y limits for the passed axis
"""
ax.set_xlim(*(lims[0]))
ax.set_ylim(*(lims[1]))
return
def pre_zoom( fig ):
""" Initialize history used by the re_zoom() event handler.
Call this after plots are configured and before pyplot.show().
"""
global oxy
oxy = [_get_limits(ax) for ax in fig.axes]
# :TODO: Intercept the toolbar Home, Back and Forward buttons.
return
def re_zoom(event):
""" Pyplot event handler to zoom all plots together, but permit them to
scroll independently. Created to support eyeball correlation.
Use with 'motion_notify_event' and 'button_release_event'.
"""
global oxy
for ax in event.canvas.figure.axes:
navmode = ax.get_navigate_mode()
if navmode is not None:
break
scrolling = (event.button == 1) and (navmode == "PAN")
if scrolling: # Update history (independent of event type)
oxy = [_get_limits(ax) for ax in event.canvas.figure.axes]
return
if event.name != 'button_release_event': # Nothing to do!
return
# We have a non-scroll 'button_release_event': Were we zooming?
zooming = (navmode == "ZOOM") or ((event.button == 3) and (navmode == "PAN"))
if not zooming: # Nothing to do!
oxy = [_get_limits(ax) for ax in event.canvas.figure.axes] # To be safe
return
# We were zooming, but did anything change? Check for zoom activity.
changed = None
zoom = [[0.0,0.0],[0.0,0.0]] # Zoom from each end of axis (2 values per axis)
for i, ax in enumerate(event.canvas.figure.axes): # Get the axes
# Find the plot that changed
nxy = _get_limits(ax)
if (oxy[i] != nxy): # This plot has changed
changed = i
# Calculate zoom factors
for j in [0,1]: # Iterate over x and y for each axis
# Indexing: nxy[x/y axis][lo/hi limit]
# oxy[plot #][x/y axis][lo/hi limit]
width = oxy[i][j][1] - oxy[i][j][0]
# Determine new axis scale factors in a way that correctly
# handles simultaneous zoom + scroll: Zoom from each end.
zoom[j] = [(nxy[j][0] - oxy[i][j][0]) / width, # lo-end zoom
(oxy[i][j][1] - nxy[j][1]) / width] # hi-end zoom
break # No need to look at other axes
if changed is not None:
for i, ax in enumerate(event.canvas.figure.axes): # change the scale
if i == changed:
continue
for j in [0,1]:
width = oxy[i][j][1] - oxy[i][j][0]
nxy[j] = [oxy[i][j][0] + (width*zoom[j][0]),
oxy[i][j][1] - (width*zoom[j][1])]
_set_limits(ax, nxy)
event.canvas.draw() # re-draw the canvas (if required)
pre_zoom(event.canvas.figure) # Update history
return
# End re_zoom()
def main(argv):
""" Test/demo code for re_zoom() event handler.
"""
import numpy
x = numpy.linspace(0,100,1000) # Create test data
y = numpy.sin(x)*(1+x)
fig = pyplot.figure() # Create plot
ax1 = pyplot.subplot(211)
ax1.plot(x,y)
ax2 = pyplot.subplot(212)
ax2.plot(x,y)
pre_zoom( fig ) # Prepare plot event handler
pyplot.connect('motion_notify_event', re_zoom) # for right-click pan/zoom
pyplot.connect('button_release_event',re_zoom) # for rectangle-select zoom
pyplot.show() # Show plot and interact with user
# End main()
if __name__ == "__main__":
# Script is being executed from the command line (not imported)
main(sys.argv)
# End of file ScrollTest.py
答案 1 :(得分:6)
好的,这是我的捅。这有效,但可能有一个更简单的方法。此解决方案使用一些matplotlib event-handling在每次注意到鼠标运动时触发新的set_xlim()
。如果不需要动态同步缩放,则可以消除触发事件'motion_notify_event'
。
奖励:这适用于任意数量的子图。
from matplotlib import pyplot
import numpy
x = numpy.linspace(0,10,100)
y = numpy.sin(x)*(1+x)
fig = pyplot.figure()
ax1 = pyplot.subplot(121)
ax1.plot(x,y)
ax2 = pyplot.subplot(122)
ax2.plot(x,y)
ax1.old_xlim = ax1.get_xlim() # store old values so changes
ax2.old_xlim = ax2.get_xlim() # can be detected
def re_zoom(event):
zoom = 1.0
for ax in event.canvas.figure.axes: # get the change in scale
nx = ax.get_xlim()
ox = ax.old_xlim
if ox != nx: # of axes that have changed scale
zoom = (nx[1]-nx[0])/(ox[1]-ox[0])
for ax in event.canvas.figure.axes: # change the scale
nx = ax.get_xlim()
ox = ax.old_xlim
if ox == nx: # of axes that need an update
mid = (ox[0] + ox[1])/2.0
dif = zoom*(ox[1] - ox[0])/2.0
nx = (mid - dif, mid + dif)
ax.set_xlim(*nx)
ax.old_xlim = nx
if zoom != 1.0:
event.canvas.draw() # re-draw the canvas (if required)
pyplot.connect('motion_notify_event', re_zoom) # for right-click pan/zoom
pyplot.connect('button_release_event', re_zoom) # for rectangle-select zoom
pyplot.show()
答案 2 :(得分:-1)
根据Matplotlib/Pyplot: How to zoom subplots together?
的答案,有一个更简单的解决方案from matplotlib import pyplot as plt
fig, axes = plt.subplots(2, sharey = True, sharex = False)