【问题标题】:How to plot a lineplot with dots on specific points with specific colors and linetypes for each line using seaborn?如何使用seaborn在每条线的特定颜色和线型的特定点上绘制带有点的线图?
【发布时间】:2019-10-21 12:11:04
【问题描述】:

我有以下数据框

import pandas as pd



 data_tmp = pd.DataFrame({'x': [0,14,28,42,56, 0,14,28,42,56],
                         'y': [0, 0.003, 0.006, 0.008, 0.001, 0*2, 0.003*2, 0.006*2, 0.008*2, 0.001*2],
                         'cat': ['A','A','A','A','A','B','B','B','B','B'],
                         'color': ['#B5D8F0','#B5D8F0','#B5D8F0','#B5D8F0','#B5D8F0','#247AB2','#247AB2','#247AB2','#247AB2','#247AB2'],
                         'point': [14,14,14,14,14,28,28,28,28,28],
                         'linestyles':['-','-','-','-','-','--','--','--','--','--']})

我想根据cat 生成具有不同colorlinestyles 的线图。但我想根据cat 给出具体的colorlinestyles,因为它们在dataframe 中定义。最后我想用相同的颜色标记每一行上的points。

我只试过:

sns.lineplot(x="x", y="y", hue="cat", data=data_tmp)
sns.scatterplot(x="point",y="y",hue="cat", data=data_tmp[data_tmp.point==data_tmp.x])
plt.show()

有什么想法吗?

【问题讨论】:

    标签: python python-3.x matplotlib plot seaborn


    【解决方案1】:

    也许你想直接使用matplotlib,比如

    import pandas as pd
    import matplotlib.pyplot as plt
    
    
    df = pd.DataFrame({'x': [0,14,28,42,56, 0,14,28,42,56],
                       'y': [0, 0.003, 0.006, 0.008, 0.001, 0*2, 0.003*2, 0.006*2, 0.008*2, 0.001*2],
                       'cat': ['A','A','A','A','A','B','B','B','B','B'],})
    
    
    d = {"A" : {"color": '#B5D8F0', "markersize":  5, "linestyle": "-"},
         "B" : {"color": '#247AB2', "markersize": 10, "linestyle": "--"}}
    
    for n, grp in df.groupby("cat"):
        plt.plot(grp.x, grp.y, marker="o", label=n, **d[n])
    
    plt.legend()
    plt.show()
    

    【讨论】:

      【解决方案2】:

      这就是我可以做到的。您需要使用cat 列来控制不同的绘图参数(颜色、样式、标记大小),然后创建映射对象(这里是dicts)来告诉每个类别使用哪个参数值。颜色很简单。 linestyle 比较难,因为 Seaborn 只提供了dashes 作为可配置参数,需要在(segment, gap) 的高级 Matplotlib 格式中给出。函数matplotlib.lines._get_dash_pattern 将字符串值(例如--)转换为这种格式,但需要小心处理返回值。对于标记大小,不幸的是lineplot 不提供随类别更改标记大小的可能性(即使您可以更改标记样式),因此您需要在顶部使用scatterplot。最后一点是图例,您可能希望为第二个图禁用它,以避免重复它,但问题是第一个图例中没有标记。如果这让您感到困扰,您仍然可以手动编辑图例。总而言之,它可能看起来像这样:

      import pandas as pd
      import matplotlib as mpl
      import matplotlib.pyplot as plt
      import seaborn as sns
      
      # Converts a line style to a format acceptable by Seaborn
      def get_dash_pattern(style):
          _, dash = mpl.lines._get_dash_pattern(style)
          return dash if dash else (None, None)
      
      data_tmp = pd.DataFrame({
          'x': [0,14,28,42,56, 0,14,28,42,56],
          'y': [0, 0.003, 0.006, 0.008, 0.001, 0*2, 0.003*2, 0.006*2, 0.008*2, 0.001*2],
          'cat': ['A','A','A','A','A','B','B','B','B','B'],
          'color': ['#B5D8F0','#B5D8F0','#B5D8F0','#B5D8F0','#B5D8F0',
                    '#247AB2','#247AB2','#247AB2','#247AB2','#247AB2'],
          'point': [14,14,14,14,14,28,28,28,28,28],
          'linestyles':['-','-','-','-','-','--','--','--','--','--']})
      # Extract plot features as dicts
      feats = (data_tmp[['cat', 'color', 'linestyles', 'point']]
               .set_index('cat').drop_duplicates().to_dict())
      palette, dashes, sizes = feats['color'], feats['linestyles'], feats['point']
      # Convert line styles to dashes
      dashes = {k: get_dash_pattern(v) for k, v in dashes.items()}
      # Lines
      lines = sns.lineplot(x="x", y="y", hue="cat", style="cat", data=data_tmp,
                           palette=palette, dashes=dashes)
      # Points
      sns.scatterplot(x="x", y="y", hue="cat", size="cat", data=data_tmp,
                      palette=palette, sizes=sizes, legend=False)
      # Fix legend
      for t, l in zip(lines.legend().get_texts(), lines.legend().get_lines()):
          l.set_marker('o')
          l.set_markersize(sizes.get(l.get_label(), 0) / t.get_fontsize())
      plt.show()
      

      输出:

      【讨论】:

      • 也许我表述问题的方式具有误导性。关于这些点,我的意思是我想要 x 轴等于每行数据集中的 point 变量的点。但是您的回答仍然帮助我弄清楚了
      【解决方案3】:

      这是我在@jdehesa 帮助下的解决方案

      我还把图例放在了剧情之外,并对标签进行了一些润色

      def get_dash_pattern(style):
          _, dash = mpl.lines._get_dash_pattern(style)
          return dash if dash else (None, None)
      
      palette = dict(zip(data_tmp.cat, data_tmp.color))
      dashes = dict(zip(data_tmp.cat, data_tmp.linestyles))
      dashes = {k: get_dash_pattern(v) for k, v in dashes.items()}
      
      ax = sns.lineplot(x="x", y="y", hue="cat", data=data_tmp, palette=palette, style='cat',  dashes=dashes)
      ax = sns.scatterplot(x="point", y="y", hue="cat", data=data_tmp[data_tmp.point == data_tmp.x], palette=palette,
                           legend=False)
      
      ax.set_title('title')
      ax.set_ylabel('y label')
      ax.set_xlabel('x label')
      ax.legend(loc=(1.04, 0))
      plt.show()
      

      【讨论】:

        猜你喜欢
        • 2019-12-13
        • 2016-02-16
        • 1970-01-01
        • 2017-09-07
        • 2012-11-05
        • 2021-07-28
        • 1970-01-01
        • 2020-04-07
        • 1970-01-01
        相关资源
        最近更新 更多