【问题标题】:Cycling through 2 lists循环浏览 2 个列表
【发布时间】:2020-01-02 21:47:06
【问题描述】:

我想根据其中一个列表是否完成一个循环来循环浏览 2 个不同的列表。具体来说,我想更改绘图中数据点的符号和颜色。

这是我目前正在做的:

import pandas as pd
import itertools
import seaborn as sns
import matplotlib.pyplot as plt

%matplotlib inline
markers = itertools.cycle(['.', '1', '+', 'x'])
colors = itertools.cycle(['r', 'g'])

classes = ["class 1"] * 5 + ["class 2"] * 5 + ["class 3"] * 7
vals = [1,1.2,1.3,1.4,1.5] + [2,2.2,2.3,2.4,2.5] + [3,3.1,3.2,3.3,3.4,3.5,3.6]
vals2 = [x**2 for x in vals]
p_df = pd.DataFrame({"class": classes, "vals": vals, "vals2": vals2})

fig, ax = plt.subplots(figsize=(8,6))
for label, df in p_df.groupby('class'):
    df.plot.scatter(x='vals', y='vals2', ax=ax, label=label, color=next(colors), marker=next(markers))
plt.legend()

但这不是我想要的,因为我在遍历标记的同时还遍历颜色。我想先完成颜色的迭代,然后移动到下一个标记。所以顺序是这样的

第一个情节,“。”标记,'r' 颜色

第二个情节,'.'标记,'g' 颜色

第三个绘图,'1' 标记,'r' 颜色

第 4 个图,'1' 标记,'g' 颜色

...等等

我想到的一种方法是跟踪已经完成的绘图数量,然后在标记上调用 next。但这似乎不是一个用更多 for 循环进行绘图的更复杂绘图的好方法。

有什么建议吗?

【问题讨论】:

标签: python matplotlib


【解决方案1】:

这是一个常见的问题,所以matplotlib 现在包括cycler,用于编写这种东西。然后你可以像这样替换你的itertools.cycles

import pandas as pd
from cycler import cycler
import seaborn as sns
import matplotlib.pyplot as plt

markers = cycler(marker='.1+x')
colors = cycler(color='rg')

style = iter(markers * colors)

classes = ["class 1"] * 5 + ["class 2"] * 5 + ["class 3"] * 7
vals = [1,1.2,1.3,1.4,1.5] + [2,2.2,2.3,2.4,2.5] + [3,3.1,3.2,3.3,3.4,3.5,3.6]
vals2 = [x**2 for x in vals]
p_df = pd.DataFrame({"class": classes, "vals": vals, "vals2": vals2})

fig, ax = plt.subplots(figsize=(8,6))
for label, df in p_df.groupby('class'):
    df.plot.scatter(x='vals', y='vals2', ax=ax, label=label, **next(style))
plt.legend()

要查看循环是如何组成的,您可以这样做

for i in (markers * colors):
    print(i)

打印出来的

{'marker': '.', 'color': 'r'}
{'marker': '.', 'color': 'g'}
{'marker': '1', 'color': 'r'}
{'marker': '1', 'color': 'g'}
{'marker': '+', 'color': 'r'}
{'marker': '+', 'color': 'g'}
{'marker': 'x', 'color': 'r'}
{'marker': 'x', 'color': 'g'}

【讨论】:

    【解决方案2】:

    使用itertools.product():

    # Replace the itertools.cycle(...) lines with:
    linetype = itertools.product('.1+x', 'rg')
    
    ...
    
    for label, df in p_df.groupby('class'):
        (marker, color) = next(linetype)
        df.plot.scatter(x='vals', y='vals2', ax=ax, label=label, color=color, marker=marker)
    

    正如评论中所指出的(抱歉,由于已被删除,无法归因),如果您需要重复使用组合,您可以随时将其包装在itertools.cycle()

    linetype = itertools.cycle(itertools.product('.1+x', 'rg'))
    

    【讨论】:

    • 感谢您提出包装。
    【解决方案3】:

    Matplotlib 的 cycler 允许自动循环遍历属性。但这仅适用于plot(不适用于scatter)。但是,无论如何,使用plot 可以更有效地生成单个彩色散点图。

    import pandas as pd
    import matplotlib.pyplot as plt
    
    
    markers = plt.cycler(marker=['.', '1', '+', 'x'])
    colors = plt.cycler(color=['r', 'g'])
    
    classes = ["class 1"] * 5 + ["class 2"] * 5 + ["class 3"] * 7
    vals = [1,1.2,1.3,1.4,1.5] + [2,2.2,2.3,2.4,2.5] + [3,3.1,3.2,3.3,3.4,3.5,3.6]
    vals2 = [x**2 for x in vals]
    p_df = pd.DataFrame({"class": classes, "vals": vals, "vals2": vals2})
    
    fig, ax = plt.subplots(figsize=(8,6))
    ax.set_prop_cycle(markers*colors)
    for label, df in p_df.groupby('class'):
        ax.plot("vals", "vals2", linestyle="", data=df)
    plt.legend()
    plt.show()
    

    【讨论】:

      猜你喜欢
      • 2020-10-14
      • 2016-08-08
      • 1970-01-01
      • 2018-12-08
      • 1970-01-01
      • 1970-01-01
      • 2016-05-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多