Matplotlib:颜色和线条样式由两个不同的变量和不同的图例组成

时间:2017-09-14 08:52:27

标签: python matplotlib legend

我有一个情节,每条线都用变量a的值着色,并且线条样式乘以变量b的值:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# some data
x = np.array([[1, 2, 0.1, 0.5], [2, 3, 0.1, 0.5], 
              [1, 4, 0.4, 0.8], [2, 1, 0.4, 0.8],
              [1, 1, 0.1, 0.8], [2, 3, 0.1, 0.8], 
              [1, 3, 0.4, 0.5], [2, 3, 0.4, 0.5]])
df = pd.DataFrame(x)
df.columns = ["x", "y", "a", "b"]
df.head()

# define color scheme and line style
colors = ["C1", "C2", "C3"]
linestyles = ['-', "--", ":"]


for a_idx, a in enumerate(np.unique(df["a"])):
    for b_idx, b in enumerate(np.unique(df["b"])):
        df2 = df[df["a"] == a]
        df2 = df2[df2["b"] == b]
        plt.plot(df2["x"], df2["y"], c = colors[a_idx], ls = linestyles[b_idx])
plt.legend(['a = 0.1, b = 0.5', 'a = 0.1, b = 0.8', 
            'a = 0.4, b = 0.5', 'a = 0.4, b = 0.8'])
plt.show()

enter image description here

现在我想要有颜色和线条样式的单独图例,所以一个标题为a的框和两个颜色为0.1,0.4的颜色的框和另一个标题为b的框和两个颜色为0.5和0.8的不同线条的线。

只有一个盒子也可以,但是有一些空格可以分开颜色和线条样式。

2 个答案:

答案 0 :(得分:4)

你可以做这样的事情

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt


# some data
x = np.array([[1, 2, 0.1, 0.5], [2, 3, 0.1, 0.5], 
              [1, 4, 0.4, 0.8], [2, 1, 0.4, 0.8],
              [1, 1, 0.1, 0.8], [2, 3, 0.1, 0.8], 
              [1, 3, 0.4, 0.5], [2, 3, 0.4, 0.5]])
df = pd.DataFrame(x)
df.columns = ["x", "y", "a", "b"]
df.head()

# define color scheme and line style
colors = ["C1", "C2", "C3"]
linestyles = ['-', "--", ":"]

fig, axes = plt.subplots()

for a_idx, a in enumerate(np.unique(df["a"])):
    for b_idx, b in enumerate(np.unique(df["b"])):
        df2 = df[df["a"] == a]
        df2 = df2[df2["b"] == b]
        axes.plot(df2["x"], df2["y"], c = colors[a_idx], ls = linestyles[b_idx])

#dummy lines with NO entries, just to create the black style legend
dummy_lines = []
for b_idx, b in enumerate(np.unique(df["b"])):
    dummy_lines.append(axes.plot([],[], c="black", ls = linestyles[b_idx])[0])
lines = axes.get_lines()
legend1 = plt.legend([lines[i] for i in [0,2]], ["a = 0.1", "a = 0.4"], loc=1)
legend2 = plt.legend([dummy_lines[i] for i in [0,1]], ["b = 0.5", "b = 0.8"], loc=4)
axes.add_artist(legend1)

plt.show()

基本思想是通过调用plt.legend()axes.add_artist()而不是仅调用plt.legend()来添加自己的图例。这允许您根据需要添加任意数量的图例。现在您只需选择与每个图表关联的行,并为每个图例中的每个条目设置标题。

要为不同的样式创建黑色图例,我们必须添加“虚拟”线,这些线不包含单个点(因此它们在图中本身不可见,但可以在图例中引用以更改颜色)。这是有效的,但似乎是一个古怪的黑客。对于小例子,这将没有任何问题,但对于大型项目,这不是最佳解决方案;所以,如果有人知道更好的解决方案,请告诉我!

这会创建此情节

答案 1 :(得分:2)

我使用ggplot(使用默认颜色)找到了一种更简单的方法。

import pandas as pd
import numpy as np
from ggplot import *

x = np.array([[1, 2, 0.1, 0.5], [2, 3, 0.1, 0.5], 
              [1, 4, 0.4, 0.8], [2, 1, 0.4, 0.8],
              [1, 1, 0.1, 0.8], [2, 3, 0.1, 0.8], 
              [1, 3, 0.4, 0.5], [2, 3, 0.4, 0.5]])
df = pd.DataFrame(x)
df.columns = ["x", "y", "a", "b"]

# convert a and b to categorical variables
df["a"] = df["a"].astype('category')
df["b"] = df["b"].astype('category')

ggplot(df, aes("x", "y", color = "a", linetype = "b")) + geom_line() + theme_bw()

诀窍是将a和b转换为分类变量。然后ggplot会自动添加两个图例。

enter image description here