Python子包中的作用域类似于MATLAB';s stackedplot()

Python子包中的作用域类似于MATLAB';s stackedplot(),python,matlab,matplotlib,subplot,stacked,Python,Matlab,Matplotlib,Subplot,Stacked,Python中是否有与MATLAB的stackedplot()相同的绘图函数? MATLAB中的stackedplot()可以用相同的X轴绘制多个变量的线图,并垂直堆叠。此外,此图中还有一个范围,仅通过移动光标即可显示给定X的所有变量的值(请参见随附的图)。我已经能够在Python中生成堆叠的子图,没有任何问题,但是,无法添加这样的作用域,通过移动光标来显示所有变量的值。这个特性在Python中可用吗 这是一个使用MATLAB的stackedplot()绘制的图: 可用于在悬停、移动文本和垂直

Python中是否有与MATLAB的
stackedplot()相同的绘图函数
? MATLAB中的
stackedplot()
可以用相同的X轴绘制多个变量的线图,并垂直堆叠。此外,此图中还有一个范围,仅通过移动光标即可显示给定
X
的所有变量的值(请参见随附的图)。我已经能够在Python中生成堆叠的子图,没有任何问题,但是,无法添加这样的作用域,通过移动光标来显示所有变量的值。这个特性在Python中可用吗

这是一个使用MATLAB的
stackedplot()
绘制的图:

可用于在悬停、移动文本和垂直条时创建批注
sel.extras.append(…)
帮助自动隐藏不再需要的元素

导入matplotlib.pyplot作为plt
将matplotlib.transforms作为转换导入
导入MPLS游标
将numpy作为np导入
def共享范围(sel):
x=选择目标[0]
注释_text=f'x:{x:.2f}'
对于ax,以zip打印(轴,所有_打印):
y=np.interp(x,plot.get_-xdata(),plot.get_-ydata())
注释_text+=f'\n{plot.get_label()}:{y:.2f}'
vline=ax.axvline(x,color='k',ls=':')
附加选择(V行)
sel.annotation.set_text(注释_text)
trans=transforms.blended_transform_factory(轴[0]。transData,轴[0]。transAxes)
text1=轴[0]。text(x,1.01,f'{x:.2f}',ha='center',va='bottom',color='blue',clip_on=False,transform=trans)
附加选择(文本1)
图,轴=plt.子批次(图尺寸=(15,10),nrows=3,sharex=真)
y1=np.random.uniform(-1,1100).cumsum()
y2=np.random.uniform(-1,1100).cumsum()
y3=np.random.uniform(-1,1100).cumsum()
全部y=[y1,y2,y3]
所有标签=['Var1'、'Var2'、'Var3']
所有_图=[ax.plot(y,label=label)[0]
对于轴,y,zip中的标签(轴,所有y,所有标签)]
对于ax,在zip中添加标签(轴,所有标签):
ax.集合标签(标签)
cursor=mplcursors.cursor(所有绘图,悬停=True)
cursor.connect('add',共享\u范围)
plt.show()

以下是每个子批次都有单独注释的版本:

导入matplotlib.pyplot作为plt
将matplotlib.transforms作为转换导入
导入MPLS游标
将numpy作为np导入
def共享范围(sel):
sel.annotation.set_visible(False)#隐藏由游标创建的默认批注
x=选择目标[0]
对于ax,以zip打印(轴,所有_打印):
y=np.interp(x,plot.get_-xdata(),plot.get_-ydata())
vline=ax.axvline(x,color='k',ls=':')
附加选择(V行)
annot=ax.annotate(f'{y:.2f}',(x,y),xytext=(5,0),textcoords='offset points',
bbox=dict(facecolor='番茄色',edgecolor='黑色',boxstyle='圆形',alpha=0.5))
附加选择(注释)
trans=transforms.blended_transform_factory(轴[0]。transData,轴[0]。transAxes)
text1=轴[0]。text(x,1.01,f'{x:.2f}',ha='center',va='bottom',color='blue',clip_on=False,transform=trans)
附加选择(文本1)
图,轴=plt.子批次(图尺寸=(15,10),nrows=3,sharex=真)
y1=np.random.uniform(-1,1100).cumsum()
y2=np.random.uniform(-1,1100).cumsum()
y3=np.random.uniform(-1,1100).cumsum()
全部y=[y1,y2,y3]
所有标签=['Var1'、'Var2'、'Var3']
所有_图=[ax.plot(y,label=label)[0]
对于轴,y,zip中的标签(轴,所有y,所有标签)]
对于ax,在zip中添加标签(轴,所有标签):
ax.集合标签(标签)
cursor=mplcursors.cursor(所有绘图,悬停=True)
cursor.connect('add',共享\u范围)
plt.show()

请注意,MATLAB图形是可以与之交互的UI元素,而不仅仅是一个普通的旧“图像”,可以说是从照相/摄像机中获得的。阿德里安说:“让情节互动可能相当困难。”。您可以在matplotlib中执行非常类似的操作。子图中的第一个图是时间在Y轴上的时间图。问题是,当鼠标悬停时,时间字符串注释不会显示在此绘图上。在我的系统(Windows、Pycharm、matplotlib 3.3.1)上,其他数字子绘图在显示注释方面没有任何问题。一切似乎都很正常,包括将鼠标悬停在时间绘图上并显示注释。我的是Windows、Spyder(3.3.3),和Matplotlib 3.3.0。时间字符串注释在早期版本的代码中工作得很好,其中所有注释都捆绑在一个盒子中。这对您有用吗?(在Jupyter笔记本电脑中,您需要包含
%Matplotlib notebook
而不是
%Matplotlib inline
,以获得交互式绘图)。非常感谢!这与我想要的非常接近。但是,绘图中的变量数量会根据需要而有所不同。是否有方法自动执行函数shared_scope()的内容基于绘图中变量的数量?此解决方案在我的代码中实现得很好,适用于所有数值变量。但是,如果其中一个变量的类型为“TimeStamp”,则此解决方案不起作用。看起来它在shared_scope()中的np.interp()处失败。您可以使用
matplotlib.dates.date2num
将时间戳转换为数字。谢谢!我使用matplotlib.dates.date2num修改了代码,以绘制“TimeStamp”变量。
import pandas as pd
import numpy as np
from datetime import datetime, date, time
import matplotlib.pyplot as plt
import matplotlib
import matplotlib.transforms as transforms
import mplcursors
from collections import Counter
import collections

def flatten(x):
    result = []
    for el in x:
        if isinstance(x, collections.Iterable) and not isinstance(el, str):
            result.extend(flatten(el))
        else:
            result.append(el)
    return result

def shared_scope(sel):
    sel.annotation.set_visible(False)  # hide the default annotation created by mplcursors
    x = sel.target[0]
    for ax in axes:
        for plot in plotStore:
            da = plot.get_ydata()
            if type(da[0]) is np.datetime64: #pd.Timestamp
                yData = matplotlib.dates.date2num(da) # to numerical values
                vals = np.interp(x, plot.get_xdata(), yData)
                dates = matplotlib.dates.num2date(vals) # to matplotlib dates
                y = datetime.strftime(dates,'%Y-%m-%d %H:%M:%S') # to strings
                annot = ax.annotate(f'{y:.30s}', (x, vals), xytext=(15, 10), textcoords='offset points',
                            bbox=dict(facecolor='tomato', edgecolor='black', boxstyle='round', alpha=0.5))
                sel.extras.append(annot)
            else:
                y = np.interp(x, plot.get_xdata(), plot.get_ydata())      
                annot = ax.annotate(f'{y:.2f}', (x, y), xytext=(15, 10), textcoords='offset points', arrowprops=dict(arrowstyle="->",connectionstyle="angle,angleA=0,angleB=90,rad=10"),
                            bbox=dict(facecolor='tomato', edgecolor='black', boxstyle='round', alpha=0.5))
                sel.extras.append(annot)
        vline = ax.axvline(x, color='k', ls=':')
        sel.extras.append(vline)
    trans = transforms.blended_transform_factory(axes[0].transData, axes[0].transAxes)
    text1 = axes[0].text(x, 1.01, f'{x:.2f}', ha='center', va='bottom', color='blue', clip_on=False, transform=trans)
    sel.extras.append(text1)
        
   
# Data to plot
data = pd.DataFrame(columns = ['timeOfSample','Var1','Var2'])
data.timeOfSample = ['2020-05-10 09:09:02','2020-05-10 09:09:39','2020-05-10 09:40:07','2020-05-10 09:40:45','2020-05-12 09:50:45']
data['timeOfSample'] = pd.to_datetime(data['timeOfSample'])
data.Var1 = [10,50,100,5,25]
data.Var2 = [20,55,70,60,50]
variables = ['timeOfSample',['Var1','Var2']] # variables to plot - Var1 and Var2 to share a plot

nPlot = len(variables)   
dataPts = np.arange(0, len(data[variables[0]]), 1) # x values for plots
plotStore = [0]*len(flatten(variables)) # to store all the plots for annotation purposes later

fig, axes = plt.subplots(nPlot,1,sharex=True)

k=0
for i in range(nPlot):
    if np.size(variables[i])==1:
        yData = data[variables[i]]   
        line, = axes[i].plot(dataPts,yData,label = variables[i]) 
        plotStore[k]=line
        k = k+1
    else:
        for j in range(np.size(variables[i])): 
            yData = data[variables[i][j]]        
            line, = axes[i].plot(dataPts,yData,label = variables[i][j])             
            plotStore[k]=line
            k = k+1  
    axes[i].set_ylabel(variables[i])


cursor = mplcursors.cursor(plotStore, hover=True)
cursor.connect('add', shared_scope)
plt.xlabel('Samples')
plt.show()