5 图例
matplotlib中的图例是帮助观察者理解图像数据的重要工具。图列通常包含在图像中,用于解释不同的颜色、形状、标签和其它元素。
1)主要参数
当不设置图例的参数时,默认的图例是这样的。
x = np.linspace(0,1,50)
y1 = np.sin(x*2*np.pi)
y2 = np.cos(x*2*np.pi)
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
ax.plot(x,y1,label="sin")
ax.plot(x,y2,label="cos")
ax.legend()
图例就是左下角的那部分。图例的主要参数,其实也就是上例ax.lengend()函数的主要参数:
- 图例位置相关:loc(位置字符串)
- 边框相关:facecolor(背景色),edgecolor(边框颜色),shadow(是否设置阴影),framemon(是否有边框和背景)
- 图例的列数:默认是1行多列的格式,ncol(列的个数)。
2)配置示例
通过示例来演示常用设置。
2.1 图例位置
x = np.linspace(0,1,50)
y1 = np.sin(x*2*np.pi)
y2 = np.cos(x*2*np.pi)
fig, ax = plt.subplots(3,3)
fig.set_size_inches(10,10)
locations = [
["lower left", "lower center", "lower right"],
["center left", "center", "center right"],
["upper left", "upper center", "upper right"]
]
for i in range(3):
for j in range(3):
ax[i,j].plot(x, y1, label="sin")
ax[i,j].plot(x, y2, label="cos")
ax[i][j].legend(loc=locations[i][j])
上面的示例显示了不同位置的图列。
2.2 图例边框
边框可以设置边框的背景色,边框颜色和是否有阴影。
x = 2 * np.pi * np.linspace(0,1,50)
y1 = np.sin(x)
y2 = np.cos(x)
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
ax.plot(x, y1, label="sin",c="red")
ax.plot(x, y2, label="cos",c="black")
ax.legend(facecolor="yellow", edgecolor="green",shadow=True)
上例中,背景色yellow,边框green,阴影设置为True。
设置无边框比较简单,frameon=False即可。
x = 2 * np.pi * np.linspace(0,1,50)
y1 = np.sin(x)
y2 = np.cos(x)
fig = plt.figure()
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
ax.plot(x, y1, label="sin")
ax.plot(x, y2, label="cos")
ax.legend(frameon=False)
2.3 图例分列
图例默认是一列多行的格式,比如上面的各个示例,图例都是一次竖着排列下来的。可以通过ncols属性,让图例横着排列。
x = 2 * np.pi * np.linspace(0,1,50)
y1 = np.sin(x)
y2 = np.cos(x)
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8, 0.8])
ax.plot(x, y1, label="sin")
ax.plot(x, y2, label="cos")
ax.legend(frameon=False, loc="upper center", ncol=2)
上面的示例,图例(legend)设置为两列,位与上方中间位置。
2.4 多个图例
一般的图形只有一个图例,比如上面的都是这样的,sin和cos都在一个图例中。如果图例太多,或者多个图例之间关系不大,也可以创建多个图列。
from matplotlib.legend import Legend
x = 4 * np.pi * np.linspace(0,1,50)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.sin(x+np.pi/4)
y4 = np.cos(x+np.pi/4)
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
legends = []
legends += ax.plot(x, y1, label="sin(x)")
legends += ax.plot(x, y2, label="cos(x)")
legends += ax.plot(x, y3, label="sin(x+$\pi/4)$")
legends += ax.plot(x, y4, label="cos(x+$\pi/4)$")
ax.legend(legends[:2],["sin(x)","cos(x)"], loc="upper right")
leg = Legend(ax, legends[2:], ["sin(x+$\pi/4)$","cos(x+$\pi/4$)"],loc="lower left")
ax.add_artist(leg)
上面的示例中4条曲线,分成了2个图例来说明。一个图列在右上角,一个图例在左下角。
2.5 图例中不同大小的点
最后,介绍一种更复杂的图例显示方式。首先生成几种主要编程语言的热度,生成图例的时候,给3个主要节点500,5000和10000设置点的大小比例与图中的各个散点数据保持一致。
x=["Python", "C/C++", "Java", "Go", "Shell", "Ruby", "Lua"]
y=np.array([10000, 25000, 20000,1500,3000,4000,1000])
fig = plt.figure(figsize=[8,6])
plt.scatter(x,y,c=np.log10(y), s=y/32)
for hot in [500,5000,10000]:
plt.scatter([],[], c='b', s=hot/32, alpha=0.3, label=str(hot)+"(hot)")
plt.legend(scatterpoints=1, labelspacing=1.5,title="hot legend", frameon=False)
3) 总结
图例可以设置成各式各样,本篇介绍的图例设置方式并不是仅仅为了美观,更重要的是利用这些设置方式帮助用户能够达到以下目的:
- 帮助观察者快速了解图形数据:图例提供了关于图像数据的简洁,易于理解的解释,使得观察者能够快速了解图像的主题和内容。
- 帮助观察者更好地理解图像细节:在一些复杂地图像中,观察者可能需要花费很多时间才能理解其中的细节。图例可以提供关于图像细节的额外信息,使得观察者能够更好地理解图像。
- 帮助观察者发现图像中地异常或者重要信息:图例可以用于指出图像中地异常或者重要信息,帮助观察者更好的理解和分析图像。
6 文本标注
matplotlib文本和标注可以为数据和图形之间提供额外的信息,帮助观察者更好地理解数据和图形的含义。
文本用于图形中添加注释或者提供更详细的信息,以帮助观察者理解图形的含义。标注则是一种更加细粒度的文本信息,可以被用来为特定的数据点或区域提供更详细的信息。本节通过示例一次介绍文本和标注的常用使用方式。
1 文本
文本在图形中主要用在标题,坐标轴,图形中一些说明的地方。
1.1 颜色和字体
x = np.linspace(0, 10, 50)
y = np.power(x,2)
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
ax.set_title("Caption", fontdict={"fontsize":25, "color":"green"})
ax.set_xlabel("x axis", fontdict={"fontsize":20, "color":"blue"})
ax.set_ylabel("y axis", fontdict={"fontsize":20, "color":"yellow"})
ax.text(2,60,"f(x) = x * x", fontdict={"fontsize":15, "color":"black"})
ax.plot(x,y,label="f(x) = x * x")
ax.legend()
需要掌握的部分就是fontdict这个参数,这个字典还有其它参数可以控制字体,这里只演示了两个常用的参数:
- fontsize:设置字体大小
- color:设置字体颜色
1.2 latex公式
上面的示例中,f(x) = x * x可以latex的方式来显示。
latex让能够显示各种复杂的数学公式,让文本看起来和数学书中一样。
x = np.linspace(0, 10, 50)
y = np.power(x,2)
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
ax.set_title("Caption", fontdict={"fontsize":25, "color":"green"})
ax.set_xlabel("x", fontdict={"fontsize":20, "color":"blue"})
ax.set_ylabel("$x^2$", fontdict={"fontsize":20, "color":"red"})
ax.text(2,60,"$f(x) = x^2$", fontdict={"fontsize":15, "color":"black"})
ax.plot(x,y,label="$f(x) = x^2$")
ax.legend()
上面将Y轴的文本和图形中间的数学公式改成了latex格式。
2)标注
图形添加标注时,一般包含2个部分,一个指向数据的箭头,一段说明文字。
设置标志的核心参数是:
- xy:这是待标注的数据点的坐标。
- xytext:标注文本的坐标,一般是文本的左上角的点。
- bbox:文本框的样式字典
- arrowprops:箭头的样式字典
下面的示例中,通过设置上面4个参数来演示几种常用的标注:
x = np.linspace(1,10,10)
y = np.array([88,80,25,66,40,70,66,10,90,5])
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
ax.plot(x, y)
ax.annotate(
"the first value",
xy=(1,88),
xytext=(0.3,70),
arrowprops={"arrowstyle": "->", "connectionstyle": "arc3,rad=-0.5"},
)
ax.annotate(
"point 1",
xy=(3,25),
xytext=(1.8,10),
bbox={"boxstyle":"round","fc":"none","ec":"g"},
arrowprops={"arrowstyle":"->"}
)
ax.annotate(
"max",
xy=(9,90),
xytext=(6,85),
bbox={"boxstyle":"round","alpha":0.1},
arrowprops={"arrowstyle":"wedge,tail_width=0.8","alpha":0.1}
)
ax.annotate(
"point 2",
xy=(4,66),
xytext=(3,85),
bbox={"boxstyle":"round","fc":"lightblue","ec":"r"},
arrowprops={"arrowstyle":"fancy"},
)
- first value:设置箭头的弯曲度
- point 1:设置了边框
- point 2:设置了边框和背景色,同时设置了另一种箭头样式。
- max:设置了边框和另一种箭头的透明度。
3)总结
在使用matplotlib进行数据分析可视化时,合理使用文本和标注可以大大提供图形的可读性和易懂性,帮助观察者更好地理解数据和图形的含义。
7 绘图配置
matplotlib提供了大量配置参数,这些参数可以但不限于让我们从整体上调整通过matplotlib绘制的图形样式,这里的参数还有很多是功能性的,和其它工具结合时需要用的配置。
print(len(plt.rcParams))
结果:305.
本节仅介绍几个常用参数,目的是了解参数的使用方法和产生的效果。
1)坐标轴
首先是坐标轴相关的配置,通过下面的代码可以看看有多个关于坐标轴的配置:
import matplotlib.pyplot as plt
count = 0
for key,val in plt.rcParams.items():
if key.startswith("axes"):
print(key, " = ", val)
count += 1
print(f"axes 相关设置有:{count} 个")
axes.autolimit_mode = data
axes.axisbelow = line
axes.edgecolor = black
axes.facecolor = white
axes.formatter.limits = [-5, 6]
axes.formatter.min_exponent = 0
axes.formatter.offset_threshold = 4
axes.formatter.use_locale = False
axes.formatter.use_mathtext = False
axes.formatter.useoffset = True
axes.grid = False
axes.grid.axis = both
axes.grid.which = major
axes.labelcolor = black
axes.labelpad = 4.0
axes.labelsize = medium
axes.labelweight = normal
axes.linewidth = 0.8
axes.prop_cycle = cycler('color', ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf'])
axes.spines.bottom = True
axes.spines.left = True
axes.spines.right = True
axes.spines.top = True
axes.titlecolor = auto
axes.titlelocation = center
axes.titlepad = 6.0
axes.titlesize = large
axes.titleweight = normal
axes.titley = None
axes.unicode_minus = True
axes.xmargin = 0.05
axes.ymargin = 0.05
axes3d.grid = True
axes 相关设置有:33 个
一个有33个关于坐标轴的配置。
x = np.linspace(0,1,50) * 4 * np.pi
y1 = np.sin(x)
y2 = np.cos(x)
plt.rcParams.update(plt.rcParamsDefault)
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
ax.plot(x,y1, label="sin(x)")
ax.plot(x,y2, label="cos(x)")
ax.legend()
修改了背景色,边框和网格:
x = np.linspace(0,1,50) * 4 * np.pi
y1 = np.sin(x)
y2 = np.cos(x)
plt.rcParams.update(plt.rcParamsOrig)
plt.rc("axes",facecolor="yellow",edgecolor="red",grid=True)
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
ax.plot(x,y1, label="sin(x)")
ax.plot(x,y2, label="cos(x)")
ax.legend()
2) 网格
关于网格,除了通过坐标轴来设置,它还有自己的一些专用的设置选项:
count = 0
for key, val in plt.rcParams.items():
if key.startswith("grid"):
print(key, " = ", val)
count += 1
print(f"grid 相关设置有:{count}个")
运行结果:
grid.alpha = 1.0
grid.color = #b0b0b0
grid.linestyle = -
grid.linewidth = 0.8
grid 相关设置有:4个
总共有4个相关的设置,设置看看效果。
代码和上面类似,如下:
x = np.linspace(0,1,50) * 4 * np.pi
y1 = np.sin(x)
y2 = np.cos(x)
plt.rcParams.update(plt.rcParamsOrig)
plt.rc("axes",grid=True)
plt.rc("grid", linestyle="-.",linewidth=1.5, color="blue")
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
ax.plot(x,y1, label="sin(x)")
ax.plot(x,y2, label="cos(x)")
ax.legend()
运行结果:
3) 刻度的相关参数:
xcount = 0
ycount = 0
for key, val in plt.rcParams.items():
if key.startswith("xtick"):
print(key, " = ", val)
xcount += 1
if key.startswith("ytick"):
print(key, " = ", val)
ycount += 1
print(f"xtick 相关设置有:{xcount}个")
print(f"ytick 相关设置有:{ycount}个")
运行结果:
xtick.alignment = center
xtick.bottom = True
xtick.color = black
xtick.direction = out
xtick.labelbottom = True
xtick.labelsize = medium
xtick.labeltop = False
xtick.major.bottom = True
xtick.major.pad = 3.5
xtick.major.size = 3.5
xtick.major.top = True
xtick.major.width = 0.8
xtick.minor.bottom = True
xtick.minor.pad = 3.4
xtick.minor.size = 2.0
xtick.minor.top = True
xtick.minor.visible = False
xtick.minor.width = 0.6
xtick.top = False
ytick.alignment = center_baseline
ytick.color = black
ytick.direction = out
ytick.labelleft = True
ytick.labelright = False
ytick.labelsize = medium
ytick.left = True
ytick.major.left = True
ytick.major.pad = 3.5
ytick.major.right = True
ytick.major.size = 3.5
ytick.major.width = 0.8
ytick.minor.left = True
ytick.minor.pad = 3.4
ytick.minor.right = True
ytick.minor.size = 2.0
ytick.minor.visible = False
ytick.minor.width = 0.6
ytick.right = False
xtick 相关设置有:19个
ytick 相关设置有:19个
X轴刻度和Y轴刻度的相关设置各有19个。
设置方法和效果如下:
x = np.linspace(0,1,50) * 4 * np.pi
y1 = np.sin(x)
y2 = np.cos(x)
plt.rcParams.update(plt.rcParamsDefault)
plt.rc("xtick", color="red", direction="in")
plt.rc("ytick", color="blue")
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
ax.plot(x,y1, label="sin(x)")
ax.plot(x,y2, label="cos(x)")
ax.legend()
运行结果:
上面的示例分布设置X轴和Y轴的眼色,以及X轴的direction, direction="in"表示刻度的小短线在图形的内部。Y轴没有设置这个属性,它的刻度线在图形外的。
4)颜色列表
绘制图形的时候,一个图形中有多条曲线时,每条曲线默认就会使用不同的颜色。这是因为配置有一个默认的颜色列表,绘制多个图形时,会依次使用其中的颜色。
print(plt.rcParams["axes.prop_cycle"])
运行结果:
cycler('color', ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf'])
修改这个默认的颜色列表,看看变化效果:
x = np.linspace(0,1,50) * 4 * np.pi
y1 = np.sin(x)
y2 = np.cos(x)
from matplotlib import cycler
colors= cycler(
"color", ["#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf"]
)
plt.rcParams.update(plt.rcParamsDefault)
plt.rc("axes", prop_cycle=colors)
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
ax.plot(x, y1, label="sin(x)")
ax.plot(x, y2, label="cos(x)")
ax.legend()
改变颜色列表之后,两条曲线的颜色都变了。
绘制曲线或者其它图形时,其实是有参数可以指定颜色的,为什么还需要这个颜色列表的配置?这是因为,如果我们能够确定报告的风格,那么就可以在一开始就根据报告的风格设置好这个颜色列表。
然后绘制各种图形时就不需要指定颜色,极大简化后续的代码,也提供了代码的可维护性。
5) 总结
在配置rcParams时,可以根据需要修改各种选项,以达到更好的显示效果。
8 样式表
现在matplotlib已经内置了很多样式表,通过使用不同的样式表,可以整体改变绘制图形的风格,不用再调整一个个显示参数。
1)样式表的使用
1.1 所有内置样式表
首先查看内置的样式表:
import matplotlib.pyplot as plt
plt.style.available
['Solarize_Light2',
'_classic_test_patch',
'bmh',
'classic',
'dark_background',
'fast',
'fivethirtyeight',
'ggplot',
'grayscale',
'seaborn',
'seaborn-bright',
'seaborn-colorblind',
'seaborn-dark',
'seaborn-dark-palette',
'seaborn-darkgrid',
'seaborn-deep',
'seaborn-muted',
'seaborn-notebook',
'seaborn-paper',
'seaborn-pastel',
'seaborn-poster',
'seaborn-talk',
'seaborn-ticks',
'seaborn-white',
'seaborn-whitegrid',
'tableau-colorblind10']
1.2 使用样式表的方式
使用样式表的方式有两种:一个是全局全局样式表设置,比如:
plt.style.use("ggplot")
随后的代码中,所有绘制的图形都是ggplot风格。
另一种局部样式表设置,比如:
with plt.style.context("classic"):
# draw figure
pass
这种方式,样式表只在with范围内效率。
2) 不同样式表的效率
下面演示几种风格差异比较大的样式表。首选,装载一个绘制图形的函数。
def draw():
x = np.linspace(1,10,10)
y = np.random.randint(10,100,10)
fig = plt.figure(figsize=[6,4])
fig.add_subplot(211)
plt.plot(x,y)
fig.add_subplot(212)
plt.hist(y)
draw()
2.1 classic风格
with plt.style.context("classic"):
draw()
2.2 solarize_Light2风格
with plt.style.context("Solarize_Light2"):
draw()
2.3 bmh风格
with plt.style.context("bmh"):
draw()
2.4 dark_background风格
with plt.style.context("dark_background"):
draw()
2.5 fast风格
with plt.style.context("fast"):
draw()
2.6 ggplot风格
with plt.style.context("ggplot"):
draw()
2.7 seaborn风格
matplotlib支持多种seaborn风格。这是使用默认的seaborn风格。
with plt.style.context("seaborn"):
draw()
3) 总结
内置的样式表方便易用,提供了许多预定义的样式,可以快速帮助我们创建美观的图表。使用内置的样式表还有个好处是可以保持图表的统一风格,使得图表具有更高的刻度性和可维护性。matplotlib提供的丰富样式表,可以满足不同类型的绘图需求,并且还可以通过自定义样式表来实现更加个性的绘图效果。