Pandas matplotlib:基于另一列值更改数据点之间的宽度

Pandas matplotlib:基于另一列值更改数据点之间的宽度,pandas,dataframe,matplotlib,data-visualization,Pandas,Dataframe,Matplotlib,Data Visualization,尽我所能把它放在一张照片里: 我想增加两个数据点之间这类行的宽度,这两个数据点具有更高的z值。当它们超过某个阈值时,把它们涂成红色会很好 matplotlib可以吗 或者使用在pd.DataFrame()上工作的替代库 在使用较大的数据集以这种方式绘制时,是否需要记住某些限制 模型示例: import pandas as pd import numpy as np from datetime import datetime, timedelta date_today = datetime.

尽我所能把它放在一张照片里:

我想增加两个数据点之间这类行的
宽度
,这两个数据点具有更高的
z
值。当它们超过某个阈值时,把它们涂成红色会很好

  • matplotlib可以吗
  • 或者使用在
    pd.DataFrame()
    上工作的替代库
  • 在使用较大的数据集以这种方式绘制时,是否需要记住某些限制

  • 模型示例:

    import pandas as pd
    import numpy as np
    from datetime import datetime, timedelta
    
    date_today = datetime.now()
    days = pd.date_range(date_today, date_today + timedelta(minutes=1), freq='s')
    
    np.random.seed(seed=1111)
    y = np.random.randint(10, high=13, size=len(days))
    z = np.random.randint(1, high=10, size=len(days))
    df = pd.DataFrame({'ts': days, 'y': y, 'z': z})
    df = df.set_index('ts')
    print(df)
    
    df.y.plot()
    

    我将这样做:基本上,我是在数据框中添加条件行(
    df'[linewidth]',df['linecolors']
    ),该数据框包含用于绘制线段的打印选项,并基于一个

    这将产生:


    请注意,我通过
    df['threshold\u bool']
    添加了分散点和文本,为了突出显示代码如何决定某个段是高于阈值还是低于阈值,请参见代码中的注释。

    这里是另一种方法,基于使用类似于此的
    线集合

    将熊猫作为pd导入
    将numpy作为np导入
    从datetime导入datetime,timedelta
    将matplotlib.pyplot作为plt导入
    从matplotlib.collections导入LineCollection
    从matplotlib.dates导入日期格式化程序、date2num、第二个定位器
    date_today=datetime.now()
    days=pd.date\u范围(date\u today,date\u today+timedelta(分钟=1),freq='s')
    np.random.seed(seed=1111)
    y=np.random.randint(10,高=13,大小=len(天))
    z=np.random.randint(1,高=10,大小=len(天))
    df=pd.DataFrame({'ts':天,'y':y,'z':z})
    df=df.set_索引('ts'))
    #制作每一条线段
    points=np.array([date2num(df.index),y]).T.reforme(-1,1,2)
    分段=np。连接([点[:-1],点[1:],轴=1)
    #创建线条集合,如果z>5,则将默认线条颜色设置为红色
    #否则为蓝色,如果z>=上一个值,则线宽为2,否则为1
    lc=线路收集(
    部分,
    颜色=np.其中(z>5,'红色','蓝色'),
    线宽=np,其中(z[1::]>=z[:-1],2,1),
    )
    #将其添加到绘图轴和自动缩放轴以考虑线
    图,ax=plt.子批次()
    ax.添加_集合(lc)
    ax.自动缩放()
    #很好地格式化x轴
    ax.xaxis.set\u major\u定位器(第二定位器(范围(0,60,10)))
    ax.xaxis.set\u major\u格式化程序(日期格式化程序(“%H:%M:%S”))
    plt.show()
    
    这给出了下面的图

    不要发布图片。发布代码和数据亲爱的@PaulH,是的,这是真的,我可以写一些简单的代码,比如
    .plot([…],color='red',linewidth=10)
    。遗憾的是,这些接口看起来不合适,因为我正在寻找一种逐点的方法来将额外列中的信息集成到行中。对我来说,这张图片很容易指向目标图片。我是说人们应该能够复制粘贴一些代码来生成您的数据和您已经尝试过的内容。您可以在seaborn中执行此操作,但我不打算为you@PaulH好了-添加了示例模型来生成数据集。看起来很不错。你为什么选择通过
    z>0.25
    选择
    color
    ,而使用
    np选择
    linewidth
    。其中(z[1:]>=z[:-1],5,1)
    ?@Asmus这只是一个基于我如何解释问题的示例(我可能错了,因此OP应该纠正我)。我认为问题很清楚,如果z值高于上一个值,那么线宽应该更粗。我不清楚“门槛”是相同的标准还是不同的标准。啊,我明白了。不管怎样,我喜欢你的解决方案,投赞成票吧!:)@tomjn谢谢你的回答-看起来很激动人心。关于您的评论:您的假设是正确的,即基于
    z
    (没有任何阈值)该行应该更大。如果
    z>threshold
    ,则
    threshold
    标准仅用于以不同颜色绘制线段。因此,这里的一切都是正确的:)终于找到了应用您的方法的时间。它像预期的那样工作-谢谢!也许值得一提的是,如果您已经来自一个
    pd.DataFrame
    ,您可以像
    y=df['y'].to_numpy()
    。剩下的就直截了当了。
    import pandas as pd
    import numpy as np
    from datetime import datetime, timedelta
    import matplotlib.pyplot as plt
    from pandas.plotting import register_matplotlib_converters
    register_matplotlib_converters()
    
    date_today = datetime.now()
    days = pd.date_range(date_today, date_today + timedelta(minutes=1), freq='s')
    
    # np.random.seed(seed=1111)
    # y = np.random.randint(10, high=13, size=len(days))
    # z = np.random.randint(1, high=10, size=len(days))
    
    ## note that I'm using a cosine function here instead, 
    #  in order to make it easier to see that the code is working
    y = np.cos(np.linspace(0,4*np.pi,len(days)))
    z = y
    
    df = pd.DataFrame({'ts': days, 'y': y, 'z': z})
    df = df.set_index('ts')
    
    ## create new columns to hold the linewidths and associated colors, depending on a threshold value
    threshold = -.25
    thick_linewidth = 5
    thin_linewidth = 1
    thick_color = "r"
    thin_color = "b"
    
    df['threshold_bool']  =  np.where(df['z']>= threshold, 1, 0) ### only for debug, you don't really need this
    df['linewidth'] =  np.where(df['z']>= threshold, thick_linewidth, thin_linewidth)
    df['linecolors'] =  np.where(df['z']>= threshold, thick_color, thin_color)
    
    def plot_widths(xs, ys, widths, colors, ax=None, xlim=None, ylim=None,
                    **kwargs):
        if not (len(xs) == len(ys) == len(widths)):
            raise ValueError('xs, ys, and widths must have identical lengths')
        fig = None
        if ax is None:
            fig, ax = plt.subplots(1)
    
        segmentx, segmenty = [xs[0]], [ys[0]]
        current_width = widths[0]
        color = colors[0]
        
        ## to debug the visualisation use:
        ax.scatter(xs.values,ys.values,edgecolors="k",facecolors="w",marker='o',s=12**2,zorder=19)
        for (x,y,z) in zip(xs.values,ys.values,df['threshold_bool'].values):
            ax.text(x,y,z,ha="center",va="center",zorder=20)
        #####
        
        for ii, (x, y, width) in enumerate(zip(xs, ys, widths)):
            segmentx.append(x)
            segmenty.append(y)
            if (width != current_width) or (ii == (len(xs) - 1)):
                
                    
                ax.plot(segmentx, segmenty, linewidth=current_width, color=color,
                        **kwargs)
                segmentx, segmenty = [x], [y]
                
                current_width = width
                if width == thick_linewidth:
                    color = thick_color
                else:
                    color = thin_color
                    
        if xlim is None:
            xlim = [min(xs), max(xs)]
        if ylim is None:
            ylim = [min(ys), max(ys)]
        ax.set_xlim(xlim)
        ax.set_ylim(ylim)
    
        return ax if fig is None else fig
    
    fig,ax = plt.subplots()
    plot_widths(df.index, df.y, df.linewidth, df.linecolors, ax=ax, )
    ax.axhline(threshold,linestyle="dashed",color="r")
    plt.show()