matplotlib详细教学

Matplotlib初相识

认识matplotlib

Matplotlib是一个Python 2D绘图库,能够以多种硬拷贝格式和跨平台的交互式环境生成出版物质量的图形,用来绘制各种静态,动态,交互式的图表

一个最简单的绘图例子

matplotlib的图像都是画在对应的figure上,可以认为是一个绘图区域。而一个figure又可以包含一个或者多个axes,可以认为是子区域,这个子区域可以指定属于自己的坐标系。下面通过简单的实例进行展示:

import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
fig, ax = plt.subplots()
ax.plot([1,2,3,4],[1,4,2,3])

matplotlib详细教学

那么也可以用更为简单的方式来进行创建:

line = plt.plot([1,2,3,4],[1,4,2,3])

这是因为 如果未指定axes,那么会自动创建一个,因此可以简化。

figure的组成

通常,一个完成的matplotlib图像会包括四个层级(容器):

  • Figure:顶级层,用来容纳所有绘图元素
  • Axes:matplotlib宇宙的核心,容纳了大量元素用来构造一幅幅的子图,一个figure可以由1个或者多个子图构成
  • Axis:axes的下层,用来处理所有与坐标轴、网格相关的元素
  • Tick:axis的下层,用来处理所有和刻度相关的元素

matplotlib详细教学

; 两种绘图接口

matplotlib提供了两种最常用的绘图接口:

  • 创建figure和axes,然后在此之上调用绘图方法
  • 依赖pyplot自动创建figure和axes来绘图

就像是上小节所展示的那样两种创建图的方法。

通用绘图模板

Datawhale提供了一个通常的绘图模板,可以根据实际需要对该模板进行修改了补充:


x = np.linspace(0, 2, 100)
y = x**2

mpl.rc('lines', linewidth=4, linestyle='-.')

fig, ax = plt.subplots()

ax.plot(x, y, label='linear')

ax.set_xlabel('x label')
ax.set_ylabel('y label')
ax.set_title("Simple Plot")
ax.legend() ;

matplotlib详细教学

思考题

  • 请思考两种绘图模式的优缺点和各自适合的使用场景
  • 我觉得先创建figure和axes再进行绘图的方式更适用于你对图的规划比较清晰,或者你想要画多个子图,这样在同一个figure上作画会简洁方便;而pyplot模型更实用于你当前只需要画一个图,那么把所有元素都加到当前这个图上就可以了
  • 在第五节绘图模板中我们是以OO模式作为例子展示的,请思考并写一个pyplot绘图模式的简单模板
plt.plot(x,y,label='linear')
plt.xlabel("x label")
plt.ylabel("y label")
plt.title("simple plot")
plt.legend()

艺术画笔见乾坤

先准备待会儿要用到的库

import numpy as np
import pandas as pd
import re
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
from matplotlib.patches import Circle, Wedge
from matplotlib.collections import PatchCollection

概述

matplotlib的三层api

matplotlib的原理或者说基础逻辑是,用Artist对象在画布(canvas)上绘制(Render)图形。因此跟人作画类似,需要三个步骤:

  • 准备一个画图
  • 准备画笔、颜料
  • 作画

因此可以认为matplotlib有三层的API:

  • matplotlib.backend_bases.FigureCanvas 代表了绘图区,所有的图像都是在绘图区完成的
  • matplotlib.backend_bases.Renderer 代表了渲染器,可以近似理解为画笔,控制如何在 FigureCanvas 上画图。
  • matplotlib.artist.Artist 代表了具体的图表组件,即调用了Renderer的接口在Canvas上作图。

因此我们大部分是利用Artist类来进行绘图。

Artist的分类

Artist有两种类型: primitivescontainers

  • primitive是基本要素,包含一些我们要在绘图区作图用到的标准图形对象,例如曲线、文字、矩形等等。
  • container是容器,可以认为是用来放置基本要素的地方,包括图形figure,坐标系axes和坐标系axis

基本元素primitives

primitives主要有以下几种类型,我们按照顺序介绍。

2DLines

其中常见的参数主要有:

  • xdata:横坐标的取值,默认就是range(1,len(data)+1)
  • ydata:纵坐标取值
  • linewidth:线条的宽度
  • linestyle:线型
  • color:线条的颜色
  • marker:点的标注样式
  • markersize:标注的大小
如何设置参数属性

对于上面提到的各个参数有三种修改方法:

  • 在plot函数里面进行设置
x = range(0,5)
y = [2,5,7,9,11]
plt.plot(x,y,linewidth = 10)
  • 获取线对象,对线对象进行设置
x = range(0,5)
y = [2,5,7,8,10]
line, = plt.plot(x, y, '-')
line.set_antialiased(False);
  • 获取线属性,使用setp函数设置
x = range(0,5)
y = [2,5,7,8,10]
lines = plt.plot(x, y)
plt.setp(lines, color='r', linewidth=10);
如何绘制lines

那我们常见的功能是绘制直线line,以及绘制errorbar误差折线图,下面对这两种分别进行介绍。

绘制line

可以采用两种方法来绘制直线:

1、plot方法

x = range(0,5)
y1 = [2,5,7,8,10]
y2= [3,6,8,9,11]
fig,ax= plt.subplots()
ax.plot(x,y1)
ax.plot(x,y2)
print(ax.lines);

matplotlib详细教学

打印为:

<Axes.ArtistList of 2 lines>

可以看到创建了2个lines对象。

2、Line2D对象绘制

x = range(0,5)
y1 = [2,5,7,8,10]
y2= [3,6,8,9,11]
fig,ax= plt.subplots()
lines = [Line2D(x, y1), Line2D(x, y2,color='orange')]
for line in lines:
    ax.add_line(line)
ax.set_xlim(0,4)
ax.set_ylim(2, 11);

matplotlib详细教学
绘制errorbar误差折线图

是利用pyplot中的errorbar类来实现,其参数为:

  • x:横坐标
  • y:纵坐标
  • yerr:指定在y轴水平的误差
  • xerr:指定在x轴水平的误差
  • fmt:指定折线图中某个点的颜色、形状、线条风格等
  • ecolor:指定errorbar的颜色
  • elinewidth:指定errorbar的线条宽度

那么具体的绘制方法就是将plot更改为errorbar即可:

fig = plt.figure()
x = np.arange(10)
y = 2.5 * np.sin(x / 20 * np.pi)
yerr = np.linspace(0.05, 0.2, 10)
plt.errorbar(x,y+3,yerr=yerr,fmt='o-',ecolor='r',elinewidth=2);

matplotlib详细教学

patches

这个类是二维图形类,它最常见的可以用来绘制矩形、多边形、楔形。

矩形

Rectangle矩形类比较简单,主要是通过xy来控制锚点,然后控制矩形的高宽即可。

最常见的矩形图是hist直方图和bar条形图

hist-直方图

其函数为plt.hist(),那么参数为:

  • x:数据集,直方图将会对这个数据集进行统计
  • bins:统计的区间分布,我们可以指定区间进行统计,例如按照([0,10],[11,20])区间进行统计
  • range:tuplt,显示的区间
  • density:是否显示频数统计结果
  • histtype:可选{‘bar’, ‘barstacked’, ‘step’, ‘stepfilled’}之一,默认为bar,step使用的是梯状,stepfilled则会对梯状内部进行填充,效果与bar类似
  • align:可选{‘left’, ‘mid’, ‘right’}之一,默认为’mid’,控制柱状图的水平分布,left或者right,会有部分空白区域,推荐使用默认
  • log:y轴是否采用指数刻度
  • stacked:是否为堆积状图
x=np.random.randint(0,100,100)
bins=np.arange(0,101,10)
fig = plt.figure(figsize = (6,12))
plt.subplot(311)
plt.hist(x,bins,color='fuchsia',alpha=0.5, density = True, histtype="step",
        align = "left")
plt.xlabel('scores')
plt.ylabel('count')
plt.xlim(0,100);
plt.subplot(312)
plt.hist(x,bins,color='fuchsia',alpha=0.5, density = True, histtype="step",
        align = "mid")
plt.subplot(313)
plt.hist(x,bins,color='fuchsia',alpha=0.5, density = True, histtype="step",
        align = "right")

这里对比了一下参数align的区别:

matplotlib详细教学
bar-柱状图

同样,也是采用plt.bar()函数,其参数为:

  • left:x轴的位置序列,一般采用range函数产生一个序列,但是有时候可以是字符串
  • height:y轴的数值序列,也就是柱形图的高度,一般就是我们需要展示的数据
  • alpha:透明度,值越小越透明
  • width:柱形的宽度
  • color或者facecolor:柱形填充的颜色
  • edgecolor:柱形边缘颜色
  • label:标签
y = range(1,17)
plt.bar(np.arange(16), y, alpha=0.5, width=0.5, color='yellow', edgecolor='red', label='The First Bar', lw=2);

matplotlib详细教学
多边形

Polygon类是多边形类,其参数主要是绘制的多边形的顶点坐标。

那么这个类中最常用的是fill类,它是基于顶点坐标绘制一个填充的多边形,例如:

x = np.linspace(0, 5 * np.pi, 1000)
y1 = np.sin(x)
y2 = np.sin(2 * x)
plt.fill(x, y1, color = "g", alpha = 0.3);

matplotlib详细教学
楔型(饼状图)

一个楔型是以坐标xy为中心,半径r,从角度1扫到角度2。最常用是绘制饼状图plt.pie()

其参数为:

  • x:楔型的形状,一维数组,可以看成是扫过角度的大小
  • explode:如果不是None,那么就是一个len(x)的数组,用来指定每块的偏移
  • labels:指定每个块的标签,列表或者none
  • colors:指定每个块的颜色,列表或者none
  • startangle:饼状图开始绘制的角度
labels = ['Frogs', 'Hogs', 'Dogs', 'Logs']
sizes = [15, 30, 45, 10]
explode = (0, 0.1, 0, 0)
fig1, ax1 = plt.subplots()
ax1.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%', shadow=True, startangle=90)
ax1.axis('equal');

matplotlib详细教学

collections

这个类是用来绘制一组对象的集合,那么最常见的是用来绘制散点图,即scatter方法,根据xy绘制不同大小或者颜色标记的散点图。

其主要的参数如下:

  • x和y
  • s:散点的尺寸大小
  • c:颜色
  • marker:标记类型
x = [0,2,4,6,8,10]
y = [10]*len(x)
s = [20*2**n for n in range(len(x))]
plt.scatter(x,y,s=s) ;

matplotlib详细教学

image

这是绘制图像的类,最常用的imshow可以根据数组绘制成图像(数值是各个像素值)。

使用imshow画图时首先需要传入一个数组,数组对应的是空间内的像素位置和像素点的值,interpolation参数可以设置不同的差值方法,可以理解为不同像素之间的处理手段:

methods = [None, 'none', 'nearest', 'bilinear', 'bicubic', 'spline16',
           'spline36', 'hanning', 'hamming', 'hermite', 'kaiser', 'quadric',
           'catrom', 'gaussian', 'bessel', 'mitchell', 'sinc', 'lanczos']

grid = np.random.rand(4, 4)

fig, axs = plt.subplots(nrows=3, ncols=6, figsize=(9, 6),
                        subplot_kw={'xticks': [], 'yticks': []})

for ax, interp_method in zip(axs.flat, methods):
    ax.imshow(grid, interpolation=interp_method, cmap='viridis')
    ax.set_title(str(interp_method))

plt.tight_layout()

matplotlib详细教学

对象容器-Object container

前面我们介绍的primitives基础元素,是包含在容器里面的,当然容器还会包含它自身的属性。

Figure容器

figure是最顶层的一个容器,它包含了图中的所有元素,而一个图表的背景可以认为就是在figure中添加的一个矩形。

当我们向图表中添加add_subplot或者add_axes时,这些元素会被添加到figure.axes列表中:

fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_axes([0.1, 0.1, 0.7, 0.3])
ax3 = fig.add_axes([0.2,0.1,0.3,0.4])
print(ax1)
print(fig.axes)

matplotlib详细教学

可以看到如果添加的子图位置重叠的可能存在的情况。而输出结果为:

AxesSubplot(0.125,0.53;0.775x0.35)
[<AxesSubplot:>, <Axes:>, <Axes:>]

figure.axes的列表中当前有三个元素,代表三个子图。

而我们可以通过figure.delaxes()来删除其中的图表,或者可以通过迭代访问列表中的元素获取子图表,再在其上做修改:

fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_axes([0.1, 0.1, 0.7, 0.3])
ax3 = fig.add_axes([0.2,0.1,0.3,0.4])
print(ax1)
print(fig.axes)
for ax in fig.axes:
    ax.grid(True)

matplotlib详细教学

Axes容器

Axes是matplotlib的核心。大量的用于绘图的 Artist存放在它内部,并且它有许多辅助方法来创建和添加 Artist给它自己,而且它也有许多赋值方法来访问和修改这些 Artist

和figure类似,axes包含一个patch属性,这个可以认为就是它的绘图区域:

fig = plt.figure()
ax = fig.add_subplot(111)
rect = ax.patch
rect.set_facecolor("blue")

matplotlib详细教学

Axes有许多方法用于绘图,如 .plot()&#x3001;.text()&#x3001;.hist()&#x3001;.imshow()等方法用于创建大多数常见的 primitive(如 Line2D&#xFF0C;Rectangle&#xFF0C;Text&#xFF0C;Image等等)。

可以在任意区域创建Axes,通过Figure.add_axes([left,bottom,width,height])来创建一个任意区域的Axes,其中left,bottom,width,height都是[0—1]之间的浮点数,他们代表了相对于Figure的坐标。

而我们往axes里面添加图表是通过add_line和add_patch来进行添加。

另外Axes还包含两个最重要的Artist container:

  • ax.xaxis:XAxis对象的实例,用于处理x轴tick以及label的绘制
  • ax.yaxis:YAxis对象的实例,用于处理y轴tick以及label的绘制

Axis容器

该容器用来处理跟坐标轴相关的属性,它包括坐标轴上的刻度线、刻度label、坐标网格、坐标轴标题等,而且可以独立对上下左右四个坐标轴进行处理。

可以通过下面的方法获取坐标轴的各个属性实例:

fig, ax = plt.subplots()
x = range(0,5)
y = [2,5,7,8,10]
plt.plot(x, y, '-')

axis = ax.xaxis
axis.get_ticklocs()
axis.get_ticklabels()
axis.get_ticklines()
axis.get_data_interval()
axis.get_view_interval()

也可以对获取的属性进行修改,例如:

fig = plt.figure()
rect = fig.patch
rect.set_facecolor('lightgoldenrodyellow')

ax1 = fig.add_axes([0.1, 0.3, 0.4, 0.4])
rect = ax1.patch
rect.set_facecolor('lightslategray')

for label in ax1.xaxis.get_ticklabels():

    label.set_color('blue')
    label.set_rotation(45)
    label.set_fontsize(14)

for line in ax1.yaxis.get_ticklines():

    line.set_markeredgecolor('green')
    line.set_markersize(25)
    line.set_markeredgewidth(2)

matplotlib详细教学

Tick容器

它是axis下方的一个容器对象,包含了tick、grid、line实例以及对应的label。我们可以访问它的属性来获取这些实例:

  • Tick.tick1line:Line2D实例
  • Tick.tick2line:Line2D实例
  • Tick.gridline:Line2D实例
  • Tick.label1:Text实例
  • Tick.label2:Text实例

y轴分为左右两个,因此tick1对应左侧的轴;tick2对应右侧的轴。

x轴分为上下两个,因此tick1对应下侧的轴;tick2对应上侧的轴。

例如我们做如下修改:

fig, ax = plt.subplots()
ax.plot(100*np.random.rand(20))
ax.yaxis.set_tick_params(which='major', labelcolor='blue',
                         labelleft=False, labelright=True);

matplotlib详细教学

将主轴设在右边且修改其颜色。

思考题

  • primitives 和 container的区别和联系是什么,分别用于控制可视化图表中的哪些要
  • 【答】:我认为container是一个容器,而primitives 是基本元素,可以理解为container是包容primitives的,例如figure,axes,axis等作为一个容器,它们可以包含很多primitives 的基础元素在其上面进行展示
  • 使用提供的drug数据集,对第一列yyyy和第二列state分组求和,画出下面折线图。PA加粗标黄,其他为灰色。
import pandas as pd
df = pd.read_csv("Drugs.csv")
df.head(5)
new_df = df.groupby(["YYYY","State"]).sum()
new_df

matplotlib详细教学
data = new_df.reset_index().pivot(index='YYYY', columns='State', values='DrugReports')
data

matplotlib详细教学
data = data.reset_index()
data

matplotlib详细教学

因此就可以开始绘图了:

fig,ax = plt.subplots(figsize = (12,12))

ax.grid(True, color='white')
rect = ax.patch
rect.set_facecolor('#efefef')

ax.plot(data["YYYY"], data["KY"],color='#afafaf')
ax.plot(data["YYYY"], data["OH"],color='#afafaf')
ax.plot(data["YYYY"], data["PA"],color='yellow',linewidth='8')
ax.plot(data["YYYY"], data["VA"],color='#afafaf')
ax.plot(data["YYYY"], data["WV"],color='#afafaf')

ax.set_title('Evolution of PA vs other states', color='yellow', loc='left')
ax.set_xlabel('Year')
ax.set_ylabel('DrugReports')

matplotlib详细教学
  • 分别用一组长方形柱和填充面积的方式模仿画出下图,函数 y = -1 * (x – 2) * (x – 8) +10 在区间[2,9]的积分面积
import numpy as np
x = np.linspace(0,10)
y = -1 * (x - 2) * (x - 8) + 10
fig,ax = plt.subplots(2,1,figsize = (8,12))
x_bar = np.linspace(2,9)
y_bar = -1 * (x_bar - 2) * (x_bar - 8) + 10
y_bar_button = y_bar * 0
ax[0].plot(x,y,color="red")
ax[1].plot(x,y,color="red")
ax[0].bar(x_bar, y_bar,width=0.1, color='lightgray')
ax[1].bar(x_bar, y_bar, width = 0.1, color='lightgray')
ax[0].set_ylim((0,20))
ax[1].set_ylim((0,20))
ax[1].fill_between(x_bar, y_bar, y_bar_button, color="lightgray")

matplotlib详细教学

布局格式定方圆

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

子图

使用plt.subplots()绘制均匀状态下的子图

该函数的返回分别是画布和子图构成的列表,传入的参数为行、列、第几个子图,figsize用来指定画布的大小,sharex和sharey用来表示是否共享横轴和纵轴刻度,tight_layout用来调整子图的相对大小使字符不重叠:

fig, axs = plt.subplots(2,5, figsize = (10,4), sharex = True, sharey = True)
fig.suptitle("样例1",size = 20)
for i in range(2):
    for j in range(5):
        axs[i][j].scatter(np.random.randn(10), np.random.randn(10))
        axs[i][j].set_title('第%d行,第%d列'%(i+1,j+1))
        axs[i][j].set_xlim(-5,5)
        axs[i][j].set_ylim(-5,5)
        if i==1: axs[i][j].set_xlabel('横坐标')
        if j==0: axs[i][j].set_ylabel('纵坐标')
fig.tight_layout()

matplotlib详细教学

前面是利用subplots(注意加了s)显式的创建多个对象,然后一一进行画图;我们还可以通过plt和subplot(注意没加s),每次在指定位置创建子图,创建后当前的绘制都会指向该子图:

plt.figure()

plt.subplot(2,2,1)
plt.plot([1,2], 'r')

plt.subplot(2,2,2)
plt.plot([1,2], 'b')

plt.subplot(224)
plt.plot([1,2], 'g');

matplotlib详细教学

除了常规的直角坐标系,还可以用projection方法创建极坐标系下的图表:

N = 300
r = 2 * np.random.rand(N)
theta = 2 * np.pi * np.random.rand(N)
area = 50 * r**2
colors = theta

plt.subplot(projection='polar')
plt.scatter(theta, r, c=colors, s=area, cmap='hsv', alpha=0.75);

matplotlib详细教学

练一练

请思考如何用极坐标系画出类似的玫瑰图

fig = plt.figure(figsize = (8,12))
ax = plt.subplot(projection = "polar")
x = np.arange(100,1000, 20)
y = np.linspace(0,np.pi*2, len(x))
ax.set_theta_direction(-1)
ax.set_theta_zero_location('N')
ax.bar(y, x, width = 0.15,color=np.random.random((len(r), 3)))
plt.tight_layout()

主要就是set_theta_direction和set_theta_zero_location两个函数调整图像。

matplotlib详细教学

使用GridSpec绘制非均匀子图

所谓非均匀包含两层含义,第一是指图的比例大小不同但没有跨行或跨列,第二是指图为跨列或跨行状态

利用 add_gridspec 可以指定相对宽度比例 width_ratios 和相对高度比例参数 height_ratios

fig = plt.figure(figsize=(10, 4))
spec = fig.add_gridspec(nrows=2, ncols=5, width_ratios=[1,2,3,4,5], height_ratios=[1,3])
fig.suptitle('样例2', size=20)
for i in range(2):
    for j in range(5):
        ax = fig.add_subplot(spec[i, j])
        ax.scatter(np.random.randn(10), np.random.randn(10))
        ax.set_title('第%d行,第%d列'%(i+1,j+1))
        if i==1: ax.set_xlabel('横坐标')
        if j==0: ax.set_ylabel('纵坐标')
fig.tight_layout()

matplotlib详细教学

上述创建子图时用到了spec[i,j]的方法,说明它是一个可索引的列表,那么同样也可以对其采用切片:

fig = plt.figure(figsize=(10, 4))
spec = fig.add_gridspec(nrows=2, ncols=6, width_ratios=[2,2.5,3,1,1.5,2], height_ratios=[1,2])
fig.suptitle('样例3', size=20)

ax = fig.add_subplot(spec[0, :3])
ax.scatter(np.random.randn(10), np.random.randn(10))

ax = fig.add_subplot(spec[0, 3:5])
ax.scatter(np.random.randn(10), np.random.randn(10))

ax = fig.add_subplot(spec[:, 5])
ax.scatter(np.random.randn(10), np.random.randn(10))

ax = fig.add_subplot(spec[1, 0])
ax.scatter(np.random.randn(10), np.random.randn(10))

ax = fig.add_subplot(spec[1, 1:5])
ax.scatter(np.random.randn(10), np.random.randn(10))
fig.tight_layout()

matplotlib详细教学

子图上的方法

补充一些子图上的常用方法。

常用来画直线的方法为 axhline, axvline, axline (水平、垂直、任意方向)

fig, ax = plt.subplots(figsize=(4,3))
ax.axhline(0.5,0.1,0.8, color = 'red')

ax.axvline(0.5,0.2,0.8, color = "blue")
ax.axline([0.3,0.3],[0.7,0.7], color = "green");

matplotlib详细教学

利用grid可以添加灰色网格:

fig, ax = plt.subplots(figsize=(4,3))
ax.grid(True)

matplotlib详细教学

使用set_xscale或者set_yscale可以设置坐标轴的刻度:

fig, axs = plt.subplots(1, 2, figsize=(10, 4))
for j in range(2):
    axs[j].plot(list('abcd'), [10**i for i in range(4)])
    if j==0:
        axs[j].set_yscale('log')
    else:
        pass
fig.tight_layout()

matplotlib详细教学

思考题

  • 墨尔本1981年至1990年的每月温度情况
data = pd.read_csv("layout_ex1.csv")
data["Time"] = pd.to_datetime(data["Time"])
data["year_num"] = data["Time"].apply(lambda x: x.year)
fig, ax = plt.subplots(2, 5, figsize = (20,4))
fig.suptitle('墨尔本1981年至1990年月温度曲线',size=20,y=1.1)
for i in range(2):
    for j in range(5):
        tem = data[data["year_num"] == j+1981+i*5]["Temperature"]
        x = np.arange(0,12)
        ax[i][j].plot(x,tem,marker = "o",color='b')
        ax[i][j].set_title(str(j+1981 + i*5 ) + "年")
        if( j == 0):
            ax[i][j].set_ylabel("气温")
plt.tight_layout()

matplotlib详细教学
  • np.random.randn(2, 150) 生成一组二维数据,使用两种非均匀子图的分割方法,做出该数据对应的散点图和边际分布图
data = np.random.randn(2,150)
fig = plt.figure(figsize = (12,12))
spec = fig.add_gridspec(nrows = 2, ncols = 2,width_ratios = [3,1],height_ratios=[1,3])
ax = fig.add_subplot(spec[0,0])
ax.hist(data[0,:],color = "blue",width = 0.4)
ax.axis("off")
ax2 = fig.add_subplot(spec[1,1])
ax2.hist(data[1,:], orientation='horizontal',color = "blue",rwidth = 0.8)

ax2.axis("off")
ax3 = fig.add_subplot(spec[1,0])
ax3.scatter(data[0,:],data[1,:],color = "blue")
ax3.grid(True)
ax3.set_ylabel("my_data_y")
ax3.set_xlabel("my_data_x")
plt.tight_layout()

matplotlib详细教学

文字图例尽眉目

import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.dates as mdates
import datetime

Figure和Axes上的文本

文本API示例

下面这些命令是通过pyplot API和ooAPI分别创建文本的方式:

matplotlib详细教学

fig = plt.figure()
ax = fig.add_subplot()

ax.set_xlabel('xlabel')
ax.set_ylabel('ylabel')

ax.axis([0, 10, 0, 10])
ax.text(3, 8, 'boxed italics text in data coords', style='italic',
        bbox={'facecolor': 'red', 'alpha': 0.5, 'pad': 10})

fig.text(0.4,0.8,'This is text for figure')
ax.plot([2], [1], 'o')

ax.annotate('annotate', xy=(2, 1), xytext=(3, 4),
            arrowprops=dict(facecolor='black', shrink=0.05));

matplotlib详细教学

text-子图上的文本

其调用方法为axes.text()。那么其参数为:

  • x,y:文本出现的位置
  • s:文本的内容
  • fontdict:可选参数,用来调整文本的属性

重点解释下fontdict和**kwargs参数,这两种方式都可以用于调整呈现的文本样式,最终效果是一样的,不仅text方法,其他文本方法如set_xlabel,set_title等同样适用这两种方式修改样式。通过一个例子演示这两种方法是如何使用的。

fig = plt.figure(figsize = (10,3))
axes = fig.subplots(1,2)
axes[0].text(0.3,0.8, "modift by **kwargs", style="italic",
            bbox = {"facecolor":"red", "alpha":0.5, "pad": 10})
font = {"bbox": {"facecolor":"red", "alpha":0.5, "pad": 10},
       "style":"italic"}
axes[1].text(0.3,0.8, "modify by fontdict", fontdict = font)

matplotlib详细教学

那么这些样式常用的参数如下:

matplotlib详细教学

matplotlib详细教学

xlabel和ylabel

其调用方法为axes.set_xlabel和axes.set_ylabel

其参数为:

  • xlabel:标签内容
  • fontdict和之前一样
  • **kwargs也和之前一样
  • labelpad:标签和坐标轴之间的距离
  • loc:标签位置,可选为”left”,”center”,”right”

在**kwargs中有另外的参数可以调整标签的位置等信息,下面来观察他们的区别:

fig = plt.figure(figsize=(10,3))
axes = fig.subplots(1,2)
axes[0].set_xlabel('xlabel',labelpad=20,loc='left')

axes[1].set_xlabel('xlabel', position=(0.2, _), horizontalalignment='left');

matplotlib详细教学

title和suptitle-子图和画布的标题

title调用方法为axes.set_title(),其参数为:

  • label:标签内容
  • fontdict,loc,**kwargs和之前一样
  • pad:标题偏离图表顶部的位置
  • y:title所在子图垂向的位置,默认在子图的顶部

suptitle的调用为figure.suptitle()。

下面查看pad和y的影响:

fig = plt.figure(figsize=(10,3))
fig.suptitle('This is figure title',y=1.2)
axes = fig.subplots(1,2)
axes[0].set_title('This is title,pad = 15',pad=15)
axes[1].set_title('This is title,pad = 6',pad=6);
fig = plt.figure(figsize=(10,3))
fig.suptitle('This is figure title2',y=1)
axes = fig.subplots(1,2)
axes[0].set_title('This is title,y = 1',y = 1)
axes[1].set_title('This is title,y = 1.2',y = 1.2);

matplotlib详细教学

matplotlib详细教学

可以看到两者其实就是控制标题与图的距离而已。

annotate-子图的注解

调用方式为axes.annotate(),其参数为:

  • text:注解的内容
  • xy:注解箭头指向的位置
  • xytext:注解文字的坐标
  • xycoords:用来定义xy参数的坐标系
  • textcoords:用来定义xytext参数的坐标系
  • arrowprops:用来定义指向箭头的样式

其参数特别多样化,这里只是举个例子:

fig = plt.figure()
ax = fig.add_subplot()
ax.annotate("annotate1",
            xy=(0.2, 0.2), xycoords='data',
            xytext=(0.8, 0.8), textcoords='data',
            arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=0.2")
            );

matplotlib详细教学

字体的属性设置

字体设置一般有全局字体设置和自定义局部字体设置两种方法。

为了方便在图中加入合适的字体,可以尝试了解中文字体的英文名称,此链接中就有常用的中文字体的英文名


plt.rcParams['font.sans-serif'] = ['SimSun']
plt.rcParams['axes.unicode_minus'] = False

x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
plt.plot(x, label='小示例图标签')

plt.xlabel('x 轴名称参数', fontproperties='Microsoft YaHei', fontsize=16)
plt.ylabel('y 轴名称参数', fontproperties='Microsoft YaHei', fontsize=14)
plt.title('坐标系的标题',  fontproperties='Microsoft YaHei', fontsize=20)
plt.legend(loc='lower right', prop={"family": 'Microsoft YaHei'}, fontsize=10) ;

matplotlib详细教学

tick上的文本

设置tick(刻度)和ticklabel(刻度标签)也是可视化中经常需要操作的步骤,matplotlib既提供了自动生成刻度和刻度标签的模式(默认状态),同时也提供了许多灵活设置的方式。

简单模式

直接使用axis.set_ticks设置标签位置,使用axis.set_ticklabels设置标签格式:

x1 = np.linspace(0.0, 5.0, 100)
y1 = np.cos(2 * np.pi * x1) * np.exp(-x1)
fig, axs = plt.subplots(2, 1, figsize=(5, 3), tight_layout=True)
axs[0].plot(x1, y1)
axs[1].plot(x1, y1)
axs[1].xaxis.set_ticks(np.arange(0., 10.1, 2.));

matplotlib详细教学

可以自动设置相对来说会好一点(上图)

fig, axs = plt.subplots(2, 1, figsize=(5, 3), tight_layout=True)
axs[0].plot(x1, y1)
axs[1].plot(x1, y1)
ticks = np.arange(0., 8.1, 2.)
tickla = [f'{tick:1.2f}' for tick in ticks]
axs[1].xaxis.set_ticks(ticks)
axs[1].xaxis.set_ticklabels(tickla);

matplotlib详细教学

我们通常设置tick都是要与数值的范围匹配, 然后再设置ticklabel为我们想要的类型,如下:


fig, axs = plt.subplots(2, 1, figsize=(6, 4), tight_layout=True)
x1 = np.linspace(0.0, 6.0, 100)
y1 = np.cos(2 * np.pi * x1) * np.exp(-x1)
axs[0].plot(x1, y1)
axs[0].set_xticks([0,1,2,3,4,5,6])

axs[1].plot(x1, y1)
axs[1].set_xticks([0,1,2,3,4,5,6])
axs[1].set_xticklabels(['zero','one', 'two', 'three', 'four', 'five','six'],
                   rotation=30, fontsize='small')
axs[1].xaxis.set_ticks_position('top')

print(axs[1].xaxis.get_ticklines());

matplotlib详细教学

上方的例子就是位置在bottom,下方就是在top,both就是上下都有,none就是都没有。

Tick Lacators and Formatters

除了上述的简单模式以外,还可以通过Axis.set_major_locatorAxis.set_minor_locator方法用来设置标签的位置,Axis.set_major_formatterAxis.set_minor_formatter方法用来设置标签的格式。这种方式的好处是不用显式地列举出刻度值列表。

set_major_formatter和set_minor_formatter这两个formatter格式命令可以接收字符串格式(matplotlib.ticker.StrMethodFormatter)或函数参数(matplotlib.ticker.FuncFormatter)来设置刻度值的格式 。

这部分的内容比较推荐用到的时候再去查。

Tick Formatters

接受字符串:

fig, axs = plt.subplots(2, 2, figsize=(12, 5), tight_layout=True)
for n, ax in enumerate(axs.flat):
    ax.plot(x1*10., y1)

formatter = matplotlib.ticker.FormatStrFormatter('%1.1f')
axs[0, 1].xaxis.set_major_formatter(formatter)

formatter = matplotlib.ticker.FormatStrFormatter('-%1.1f')
axs[1, 0].xaxis.set_major_formatter(formatter)

formatter = matplotlib.ticker.FormatStrFormatter('%1.5f')
axs[1, 1].xaxis.set_major_formatter(formatter);

matplotlib详细教学

接受函数:

def formatoddticks(x, pos):
    if x % 2:
        return f'{x:1.2f}'
    else:
        return ''

fig, ax = plt.subplots(figsize=(5, 3), tight_layout=True)
ax.plot(x1, y1)
ax.xaxis.set_major_formatter(formatoddticks);

matplotlib详细教学
Tick Locators

这个实现更复杂的操作:

fig, axs = plt.subplots(2, 2, figsize=(8, 5), tight_layout=True)
for n, ax in enumerate(axs.flat):
    ax.plot(x1*10., y1)

locator = matplotlib.ticker.AutoLocator()
axs[0, 0].xaxis.set_major_locator(locator)

locator = matplotlib.ticker.MaxNLocator(nbins=3)
axs[0, 1].xaxis.set_major_locator(locator)

locator = matplotlib.ticker.MultipleLocator(5)
axs[1, 0].xaxis.set_major_locator(locator)

locator = matplotlib.ticker.FixedLocator([0,7,14,21,28])
axs[1, 1].xaxis.set_major_locator(locator);

matplotlib详细教学

locator = mdates.DayLocator(bymonthday=[1,15,25])
formatter = mdates.DateFormatter('%b %d')

fig, ax = plt.subplots(figsize=(5, 3), tight_layout=True)
ax.xaxis.set_major_locator(locator)
ax.xaxis.set_major_formatter(formatter)
base = datetime.datetime(2017, 1, 1, 0, 0, 1)
time = [base + datetime.timedelta(days=x) for x in range(len(x1))]
ax.plot(time, y1)
ax.tick_params(axis='x', rotation=70);

matplotlib详细教学

legend图例

在学习legend之前需要先学习几个术语:

  • legend entry(图例条目):每个图例都有一个或者多个条目组成,一个条目包含一个key和对应的label,例如图中三条曲线需要标注,那么就是3个条目
  • legend key(图例键):每个legend label左边的标记,指明是哪条曲线
  • legend label(图例标签):描述文本
  • legend handle(图例句柄):用于在图例中生成适当图例条目的原始对象

以下图为例,右侧的方框中的共有两个legend entry;两个legend key,分别是一个蓝色和一个黄色的legend key;两个legend label,一个名为’Line up’和一个名为’Line Down’的legend label

matplotlib详细教学

图例的绘制同样有OO模式和pyplot模式两种方式,写法都是一样的,使用legend()即可调用。

fig, ax = plt.subplots()
line_up, = ax.plot([1, 2, 3], label='Line 2')
line_down, = ax.plot([3, 2, 1], label='Line 1')
ax.legend(handles = [line_up, line_down], labels = ['Line Up', 'Line Down']);

matplotlib详细教学
fig, ax = plt.subplots()
line_up, = ax.plot([1, 2, 3], label='Line 2')
line_down, = ax.plot([3, 2, 1], label='Line 1')
ax.legend()

matplotlib详细教学

而设置图例的位置,可以通过设置loc参数的值来设置,其有10个位置可以选择,每个都有字符串的形式和对应的数字形式:

Location StringLocation Codebest0upper right1upper left2lower left3lower right4right5center left6center right7lower center8upper center9center10

fig,axes = plt.subplots(2,5,figsize=(15,5))
for i in range(2):
    for j in range(5):
        axes[i][j].plot([0.5],[0.5])
        axes[i][j].legend(labels='a',loc=i*5+j)
fig.tight_layout()

matplotlib详细教学

还可以设置图例的边框和背景:

fig = plt.figure(figsize=(10,3))
axes = fig.subplots(1,3)
for i, ax in enumerate(axes):
    ax.plot([1,2,3],label=f'ax {i}')
axes[0].legend(frameon=False)
axes[1].legend(edgecolor='blue')
axes[2].legend(facecolor='gray');

matplotlib详细教学

也可以为图例加上标题:

fig,ax =plt.subplots()
ax.plot([1,2,3],label='label')
ax.legend(title='legend title');

matplotlib详细教学

思考题

尝试使用两种方式模仿画出下面的图表(重点是柱状图上的标签),本文学习的text方法和matplotlib自带的柱状图标签方法bar_label

第一种

label = ["Jim","Slim","Harry","Dick","Tom"]
y = [4,7,6,8,10]
error = np.random.rand(len(y)).round(2)
fig,ax = plt.subplots()
ax.set_title("How fast do you want to go today?")
ax.set_xlim(0,15)
for i in range(0, len(y)):
    ax.text(y[i] + error[i]+1, label[i], '±' + str(error[i]), fontsize=10,horizontalalignment='center',color='blue')
ax.set_xlabel('performance')
ax.barh(label, y, color = 'blue',xerr = error)

label = ["Jim","Slim","Harry","Dick","Tom"]
y = [4,7,6,8,10]
error = np.random.rand(len(y)).round(2)
fig,ax = plt.subplots()
ax.set_title("How fast do you want to go today?")
ax.set_xlim(0,15)
ax.set_xlabel('performance')
b = ax.barh(label, y, color = 'blue',xerr = error)
plt.bar_label(b, ["±"+str(i) for i in error])

matplotlib详细教学

样式色彩秀芳华

第五回详细介绍matplotlib中样式和颜色的使用

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

matplotlib的绘图样式(style)

设置样式最简单就是在绘制每一个元素时在参数中设定对应的样式,不过也可以用方法来批量修改全局的样式。

matplotlib预先定义样式

只需要在python脚步最开始时输入想使用的style的名称就可以调用,那么我们可以查看有哪些方式方便使用:

print(plt.style.available)
['Solarize_Light2', '_classic_test_patch', '_mpl-gallery', '_mpl-gallery-nogrid', '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']

那么使用方法例如:

plt.style.use('ggplot')
plt.plot([1,2,3,4],[2,3,4,5]);

matplotlib详细教学

用户自定义stylesheet

在任意路径下创建一个后缀名为mplstyle的样式清单,编辑文件添加以下样式内容:

axes.titlesize : 24
axes.labelsize : 20
lines.linewidth : 3
lines.markersize : 10
xtick.labelsize : 16
ytick.labelsize : 16

引用自定义stylesheet后观察图表变化:

plt.style.use('style1.mplstyle')
plt.plot([1,2,3,4],[2,3,4,5]);

matplotlib详细教学

值得特别注意的是,matplotlib支持混合样式的引用,只需在引用时输入一个样式列表,若是几个样式中涉及到同一个参数,右边的样式表会覆盖左边的值:

plt.style.use(['dark_background', 'style1.mplstyle'])
plt.plot([1,2,3,4],[2,3,4,5]);

matplotlib详细教学

设置rcparams

还可以通过修改默认rc设置的方式改变样式,所有rc设置都保存在一个叫做 matplotlib.rcParams的变量中。修改过后再绘图,可以看到绘图样式发生了变化。

plt.style.use('default')
mpl.rcParams['lines.linewidth'] = 2
mpl.rcParams['lines.linestyle'] = '--'
plt.plot([1,2,3,4],[2,3,4,5]);

matplotlib详细教学

另外matplotlib也还提供了一种更便捷的修改样式方式,可以一次性修改多个样式。

mpl.rc('lines', linewidth=4, linestyle='-.')

matplotlib的色彩设置color

在matplotlib中,设置颜色有以下几种方式

RGB或者RGBA

plt.plot([1,2,3],[4,5,6],color=(0.1, 0.2, 0.5))
plt.plot([4,5,6],[1,2,3],color=(0.1, 0.2, 0.5, 0.5));

颜色用[0,1]之间的浮点数表示,四个分量按顺序分别为(red, green, blue, alpha),其中alpha透明度可省略。

matplotlib详细教学

HEX RGB或者RGBA


plt.plot([1,2,3],[4,5,6],color='#0f0f0f')
plt.plot([4,5,6],[1,2,3],color='#0f0f0f80');

matplotlib详细教学

灰度色阶


plt.plot([1,2,3],[4,5,6],color='0.5');

matplotlib详细教学

单字符基本颜色

八个基本颜色可以用单个字符来表示,分别是’b’, ‘g’, ‘r’, ‘c’, ‘m’, ‘y’, ‘k’, ‘w’,对应的是blue, green, red, cyan, magenta, yellow, black, and white的英文缩写,设置color=’m’即可。

颜色名称

matplotlib提供了颜色对照表,可供查询颜色对应的名称

matplotlib详细教学

; 用colormap设置一组颜色

具体可以阅读这篇文章

x = np.random.randn(50)
y = np.random.randn(50)
plt.scatter(x,y,c=x,cmap='RdYlBu');

matplotlib详细教学

Original: https://blog.csdn.net/StarandTiAmo/article/details/128058482
Author: FavoriteStar
Title: matplotlib详细教学

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/766692/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球