首页 > 编程语言 >Python 使用Matplotlib绘制可拖动的折线

Python 使用Matplotlib绘制可拖动的折线

时间:2023-04-15 17:12:48浏览次数:41  
标签:ax1 Python global Matplotlib 折线 file np yvals event

Python 使用Matplotlib绘制可拖动的折线

效果图: 

可以拖曲线上的点调整, 也可以拖旁边的sliderbar调整.

 

 

代码如下:

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

func = lambda x: np.zeros_like(x)

def load_cache_weight(cache_file):
    import yaml
    global yvals
    with open(cache_file,'r') as f:
        line = f.readline()
        d = dict(yaml.safe_load(line))
    keys = d.keys()
    for i, key in enumerate(keys):
        yvals[i] = d[key]

# user input config
N = 30
st = pd.to_datetime('20230414')
cache_file = None
cache_file = './tmp/saved_weight_2.json'
save_file  = './tmp/saved_weight_2.json'

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

#spline fit
yvals = func(x)
if cache_file is not None:
    load_cache_weight(cache_file)
spline = inter.InterpolatedUnivariateSpline (x, yvals)

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

#set up a plot
fig,axes = plt.subplots(1,1,figsize=(16,5),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)
    if cache_file is not None:
        load_cache_weight(cache_file)
    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 save_p(event):
    global yvals
    global datelst
    global save_file
    r = dict(zip(map(lambda x: x.strftime('%Y%m%d'),datelst),yvals))
    print(r)
    if save_file is not None:
        with open(save_file,'w') as f:
            import json
            json.dump(r,f)

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] = np.clip(event.ydata,-1,1)

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

############################

ed = st+pd.Timedelta(days=N-1)
datelst = pd.date_range(st,ed)

# ax1.plot ()

###########################

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, 32)
ax1.set_ylim(-1.05,1.05)
ax1.set_xlabel('dt')
ax1.set_ylabel('p')
ax1.grid(True)
ax1.yaxis.grid(True,which='minor',linestyle='--')
ax1.legend(loc=2,prop={'size':8})

sliders = []
for i in np.arange(N):

    axamp = plt.axes([0.84, 0.95-(i*0.03), 0.12, 0.02])
    # Slider
    date_i = datelst[i]
    mth = date_i.month
    day = date_i.day
    s = Slider(axamp, '{}/{}'.format(mth,day), -1, 1, 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.95-((N)*0.03), 0.06, 0.02])
bres = Button(axres, 'Reset')
bres.on_clicked(reset)

axres = plt.axes([0.84+0.08, 0.95-((N)*0.03), 0.06, 0.02])
bres2 = Button(axres, 'Save')
bres2.on_clicked(save_p)

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

 

标签:ax1,Python,global,Matplotlib,折线,file,np,yvals,event
From: https://www.cnblogs.com/JiangOil/p/17321432.html

相关文章

  • 自学Python爬虫笔记(day7)
    环境python3.9版本及以上,开发工具pycharm requests的进阶使用:案例一模拟用户登录-处理cookie:#登录->得到cookie#带着cookie去请求到暑假url->书架上的内容#必须把上面两个操作连起来#我们可以使用session进行请求->session你可以认为是一连串的请求,在这个过......
  • 使用 Python 的 socket 库来实现一个简单的 Socket 示例
    以下是一个简单的服务器端和客户端的例子:服务器端:pythonimportsocket#创建socket对象serversocket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#获取本地主机名host=socket.gethostname()#设置端口号port=9999#绑定端口号serversocket.bind((h......
  • python3正则-表达式
    1、介绍这里整理了表达式,即pattern参数的语法。其本质是一个str类型。2、开始和结尾(1)^^匹配字符串的开头(2)$$匹配字符串的末尾(3)整体匹配同时使用^和$3、匹配次数(1)贪婪匹配和非贪婪匹配模式贪婪匹配,在允许的范围内尽可能多的匹配表达式次数。比如*、+、{n,m}等......
  • python3正则-修饰符flags
    1、介绍在re模块的函数中,多数允许设置修饰符flags参数,其用于对匹配做优化和个性设置。2、修饰符修饰符实质上是int参数类型,可以直接指定int类型,也可以通过re调用变量名称指定。修饰符描述re.I使匹配对大小写不敏感re.L做本地化识别(locale-aware)匹配re.M多行......
  • python3正则-Match类
    1、介绍re.match、re.fullmatch和re.search这三个函数,如果存在匹配,其返回pattern初次匹配的结果,类型就为re.Match。2、类和初始化3、方法pattern="(ab)c"result=re.match(pattern=pattern,string="abcdef")print(result)(1)start获取pattern整体匹配的开始索引,返回类......
  • python3正则-编译和其他
    1、介绍将作为pattern参数的str类型,编译返回Pattern类型,方便后续调用,提高效率。re模块下存在多个函数,可以进行编译,返回类型是Pattern。Pattern类具有和re正则匹配函数类似的方法,当然在参数上略有不同,比如是将待匹配文本作为Pattern类的参数。2、compile函数pattern=re.comp......
  • python3时间
    1、介绍time模块是python的内部模块。2、函数#返回float类型,1670592065.0852547形式#print(time.time())#print(type(time.time()))#休眠,单位秒#time.sleep(5)#print(123)#返回int类型,1670592289035206400形式#print(time.time_ns())#print(type(time.time_......
  • python3正则-替换和切割函数
    1、介绍这里整理sub、subn和split三个函数的使用。2、sub函数sub(pattern,repl,string,count=0,flags=0)pattern,正则表达式repl,替换文本string,待处理字符串count,表示替换的最大次数。默认为0表示全部替换flags,标志,处理模式作用是在flags代表的模式下,匹配strings指......
  • python3正则-多匹配函数
    1、介绍这里介绍findall和finditer两个函数。2、findall函数findall(pattern,string,flags=0)pattern,正则表达式string,待处理字符串flags,标志,处理模式返回类型为list,如果不存在匹配,返回空列表[]。如果存在匹配,则返回全部匹配项,这里需要注意()的影响2.1无()importr......
  • Kali中切换到Python2.7 和 安装pip
    sudoupdate-alternatives--install/usr/bin/pythonpython/usr/bin/python21Kali是自带python2.7的,但是我的用正常的update-alternatives 没法切换,会报错,说找不到,可以替换的版本.使用上方命令就可以使用啦!!!OK啦!下面安装pip现在 /usr/bin下,创建一个文件夹,起......