gpt4 book ai didi

python - 在 matplotlib 交互式绘图中拖动点

转载 作者:行者123 更新时间:2023-12-03 02:13:40 24 4
gpt4 key购买 nike

我使用matplotlib创建了一个交互式绘图并遵循this回答。该图使用 slider ,以便允许用户控制点的垂直(y 轴)位置,并在它们发生变化时将样条线拟合到它们。完成此操作的代码如下:

import matplotlib.animation as animation
from matplotlib.widgets import Slider
import matplotlib as mpl
from matplotlib import pyplot as plt
import scipy.interpolate as inter
import numpy as np



func = lambda x: 0.1*x**2

#get a list of points to fit a spline to as well
N = 10
xmin = 0
xmax = 10
x = np.linspace(xmin,xmax,N)

#spline fit
yvals = func(x)
spline = inter.InterpolatedUnivariateSpline (x, yvals)

#figure.subplot.right
mpl.rcParams['figure.subplot.right'] = 0.8

#set up a plot
fig,axes = plt.subplots(1,1,figsize=(9.0,8.0),sharex=True)
ax1 = axes


interval = 100 # ms, time between animation frames
loop_len = 5.0 # seconds per loop
scale = interval / 1000 / loop_len

def update(val):
# update curve
for i in np.arange(N):
yvals[i] = sliders[i].val
l.set_ydata(yvals)
spline = inter.InterpolatedUnivariateSpline (x, yvals)
m.set_ydata(spline(X))
# redraw canvas while idle
fig.canvas.draw_idle()

X = np.arange(0,xmax+1,0.1)
ax1.plot (X, func(X), 'k--', label='original')
l, = ax1.plot (x,yvals,color='k',linestyle='none',marker='o',markersize=8)
m, = ax1.plot (X, spline(X), 'r-', label='spline')



ax1.set_yscale('linear')
ax1.set_xlim(0, xmax)
ax1.set_ylim(0,xmax)
ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax1.grid(True)
ax1.yaxis.grid(True,which='minor',linestyle='--')
ax1.legend(loc=2,prop={'size':22})

sliders = []

for i in np.arange(N):

axamp = plt.axes([0.84, 0.8-(i*0.05), 0.12, 0.02])
# Slider
s = Slider(axamp, 'p{0}'.format(i), 0, 10, valinit=yvals[i])
sliders.append(s)


for i in np.arange(N):
#samp.on_changed(update_slider)
sliders[i].on_changed(update)


plt.show()

我认为如果可以直接单击这些点并垂直向上或向下拖动它们,用户界面会更好。 matplotlib 交互式代码的哪些功能最有帮助?我看过各种widgets examples ,但还没有找到任何对我来说很容易看到对此直接有用的东西。最接近的似乎是 rectangle selector ,但我不确定如何调整它以获得我需要的东西。

编辑:

This答案可能可以根据我的需要进行调整。这与我真正需要的之间的区别在于,该示例沿现有线选择一个点(基于鼠标单击和拖动)并突出显示它。我需要单击并选择小范围内的现有点(如果没有,则拖动不应执行任何操作)。然后,代码应该在拖动时更改该点,并在拖动操作期间重新调整样条线。我也许可以用上面的示例来做到这一点,因为它让我更好地理解如何使用 mpl_connect 来执行不同的操作(并给出了一些示例操作。

最终代码应该只允许垂直拖动点,但我认为该约束很容易构建(即仅使用鼠标单击/释放的 y 坐标)。

编辑2:

The Poly Editor示例似乎非常接近我需要的,我可以以此为基础进行开发。

最佳答案

好的,严重依赖 Poly Editor例如,我构建了一个示例,可以使用 slider 更改点值或单击并拖动点。

代码如下,带有注释的诊断打印:

import matplotlib.animation as animation
from matplotlib.widgets import Slider, Button
import matplotlib as mpl
from matplotlib import pyplot as plt
import scipy.interpolate as inter
import numpy as np



func = lambda x: 0.1*x**2

#get a list of points to fit a spline to as well
N = 10
xmin = 0
xmax = 10
x = np.linspace(xmin,xmax,N)

#spline fit
yvals = func(x)
spline = inter.InterpolatedUnivariateSpline (x, yvals)

#figure.subplot.right
mpl.rcParams['figure.subplot.right'] = 0.8

#set up a plot
fig,axes = plt.subplots(1,1,figsize=(9.0,8.0),sharex=True)
ax1 = axes


pind = None #active point
epsilon = 5 #max pixel distance

def update(val):
global yvals
global spline
# update curve
for i in np.arange(N):
yvals[i] = sliders[i].val
l.set_ydata(yvals)
spline = inter.InterpolatedUnivariateSpline (x, yvals)
m.set_ydata(spline(X))
# redraw canvas while idle
fig.canvas.draw_idle()

def reset(event):
global yvals
global spline
#reset the values
yvals = func(x)
for i in np.arange(N):
sliders[i].reset()
spline = inter.InterpolatedUnivariateSpline (x, yvals)
l.set_ydata(yvals)
m.set_ydata(spline(X))
# redraw canvas while idle
fig.canvas.draw_idle()

def button_press_callback(event):
'whenever a mouse button is pressed'
global pind
if event.inaxes is None:
return
if event.button != 1:
return
#print(pind)
pind = get_ind_under_point(event)

def button_release_callback(event):
'whenever a mouse button is released'
global pind
if event.button != 1:
return
pind = None

def get_ind_under_point(event):
'get the index of the vertex under point if within epsilon tolerance'

# display coords
#print('display x is: {0}; display y is: {1}'.format(event.x,event.y))
t = ax1.transData.inverted()
tinv = ax1.transData
xy = t.transform([event.x,event.y])
#print('data x is: {0}; data y is: {1}'.format(xy[0],xy[1]))
xr = np.reshape(x,(np.shape(x)[0],1))
yr = np.reshape(yvals,(np.shape(yvals)[0],1))
xy_vals = np.append(xr,yr,1)
xyt = tinv.transform(xy_vals)
xt, yt = xyt[:, 0], xyt[:, 1]
d = np.hypot(xt - event.x, yt - event.y)
indseq, = np.nonzero(d == d.min())
ind = indseq[0]

#print(d[ind])
if d[ind] >= epsilon:
ind = None

#print(ind)
return ind

def motion_notify_callback(event):
'on mouse movement'
global yvals
if pind is None:
return
if event.inaxes is None:
return
if event.button != 1:
return

#update yvals
#print('motion x: {0}; y: {1}'.format(event.xdata,event.ydata))
yvals[pind] = event.ydata

# update curve via sliders and draw
sliders[pind].set_val(yvals[pind])
fig.canvas.draw_idle()

X = np.arange(0,xmax+1,0.1)
ax1.plot (X, func(X), 'k--', label='original')
l, = ax1.plot (x,yvals,color='k',linestyle='none',marker='o',markersize=8)
m, = ax1.plot (X, spline(X), 'r-', label='spline')



ax1.set_yscale('linear')
ax1.set_xlim(0, xmax)
ax1.set_ylim(0,xmax)
ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax1.grid(True)
ax1.yaxis.grid(True,which='minor',linestyle='--')
ax1.legend(loc=2,prop={'size':22})

sliders = []

for i in np.arange(N):

axamp = plt.axes([0.84, 0.8-(i*0.05), 0.12, 0.02])
# Slider
s = Slider(axamp, 'p{0}'.format(i), 0, 10, valinit=yvals[i])
sliders.append(s)


for i in np.arange(N):
#samp.on_changed(update_slider)
sliders[i].on_changed(update)

axres = plt.axes([0.84, 0.8-((N)*0.05), 0.12, 0.02])
bres = Button(axres, 'Reset')
bres.on_clicked(reset)

fig.canvas.mpl_connect('button_press_event', button_press_callback)
fig.canvas.mpl_connect('button_release_event', button_release_callback)
fig.canvas.mpl_connect('motion_notify_event', motion_notify_callback)

plt.show()

我没有将代码封装到对象中,如Poly Editor示例确实如此,但这应该是一个很容易完成的升级。

enter image description here

关于python - 在 matplotlib 交互式绘图中拖动点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50439506/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com