本文对 Matplotlib
的用法进行不完全总结 1’ 2。
更新: 2023 / 1 / 4
Python | Matplotlib | 不完全总结
ImageMagick
参考这里 3
导库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.animation as animation
from mpl_toolkits.mplot3d import Axes3D
画布
创建多子图
subplot
创建图片对象及坐标轴,自定义图片大小
# setup the figure and axes
fig = plt.figure(figsize=(8, 3))
ax1 = fig.add_subplot(121, projection='3d')
ax2 = fig.add_subplot(122, projection='3d')
plt.show()
其中,
def add_subplot(self, *args, **kwargs):
"""
Add an `~.axes.Axes` to the figure as part of a subplot arrangement.
Call signatures::
add_subplot(nrows, ncols, index, **kwargs)
add_subplot(pos, **kwargs)
add_subplot(ax)
add_subplot()
Parameters
----------
...
projection : {None, 'aitoff', 'hammer', 'lambert', 'mollweide', \
'polar', 'rectilinear', str}, optional
The projection type of the subplot (`~.axes.Axes`). *str* is the
name of a custom projection, see `~matplotlib.projections`. The
default None results in a 'rectilinear' projection.
可以调用 subplot
在同一个画布上绘制多个图像。
动图
将使用 matplotlib.animation
中的 FuncAnimation
。
FuncAnimation
通过重复调用函数(在画布上绘制)来制作动画,动态就是 N
张图一张一张按照一定频率刷新。
语法如下,
def __init__(self, fig, func, frames=None, init_func=None, fargs=None,
save_count=None, *, cache_frame_data=True, **kwargs):
Animation
是一个幻象:在每一个frame
中,绘制的对象都使用func
函数来更新。所有的frame
都在最后被保存为一个文件(要么是gif
,要么是mp4
)。frames
是指定N
张图。fargs
是传递给func
函数的参数元组
主题
标题
pyplot.title
语法如下 6
matplotlib.pyplot.title(label, fontdict=None, loc='center', pad=None, **kwargs)[source]
变量 | 说明 |
---|---|
Parameters | label : str Text to use for the title |
fontdict : dict A dictionary controlling the appearance of the title text, the default fontdict is: {'fontsize': rcParams['axes.titlesize'], 'fontweight' : rcParams['axes.titleweight'], 'verticalalignment': 'baseline', 'horizontalalignment': loc} Copy to clipboard | |
loc : {'center', 'left', 'right'}, str, optional Which title to set, defaults to 'center' | |
pad : float The offset of the title from the top of the axes, in points. Default is None to use rcParams['axes.titlepad']. | |
Returns | text : Text The matplotlib text instance representing the title |
Other Parameters | **kwargs : Text properties Other keyword arguments are text properties, see Text for a list of valid text properties. |
示例
参考这里 7
文字
坐标轴
pyplot.xlabel
语法如下 8
matplotlib.pyplot.xlabel(xlabel, fontdict=None, labelpad=None, *, loc=None, **kwargs)[source]
示例
plt.plot([1, 2, 1, 2])
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
plt.savefig('1.png')
效果如下所示,
网格
pyplot.grid
语法如下 9
matplotlib.pyplot.grid(visible=None, which='major', axis='both', **kwargs)[source]
示例
plt.plot([1,2,1,2])
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
plt.grid(which='major', axis='both', color='green', linewidth=2)
plt.savefig('2.png')
效果如下所示:
图例
pyplot.legend
语法如下 10:
class matplotlib.legend.Legend(parent, handles, labels, *, loc=None, numpoints=None, markerscale=None, markerfirst=True, scatterpoints=None, scatteryoffsets=None, prop=None, fontsize=None, labelcolor=None, borderpad=None, labelspacing=None, handlelength=None, handleheight=None, handletextpad=None, borderaxespad=None, columnspacing=None, ncols=1, mode=None, fancybox=None, shadow=None, title=None, title_fontsize=None, framealpha=None, edgecolor=None, facecolor=None, bbox_to_anchor=None, bbox_transform=None, frameon=None, handler_map=None, title_fontproperties=None, alignment='center', ncol=1)
示例
x = [1,2,3,4,5]
y = [50,40,70,80,20]
y2 = [80,20,20,50,60]
y3 = [70,20,60,40,60]
y4 = [80,20,20,50,60]
plt.plot(x,y,'g',label='Enfield', linewidth=5)
plt.plot(x,y2,'c',label='Honda',linewidth=5)
plt.plot(x,y3,'k',label='Yahama',linewidth=5)
plt.plot(x,y4,'y',label='KTM',linewidth=5)
plt.title('bike details in line plot')
plt.ylabel('Distance in kms')
plt.xlabel('Days')
plt.legend(loc='upper right', shadow=True, title='legend title', labelcolor='r', ncol=2, fontsize='x-small')
效果如下所示:
2D
柱状图
参考这里 13
准备数据,数据集参考此处的网址 14,将其数据集保存为 3d.csv
。
选取出 year=2018
时 value
按倒序排列的 df
的前 10
行,
df = pd.read_csv('3d.csv', usecols=['name', 'group', 'year', 'value'])
current_year = 2018
df = df[df['year'].eq(current_year)].sort_values(by='value', ascending=True).tail(10)
df = df[::-1]
# name group year value
# 6045 Tokyo Asia 2018 38194.2
# 1324 Delhi India 2018 27890.0
# 5547 Shanghai Asia 2018 25778.6
# 689 Beijing Asia 2018 22674.2
# 3748 Mumbai India 2018 22120.0
# 5445 Sao Paulo Latin America 2018 21697.8
# 3574 Mexico City Latin America 2018 21520.4
# 4679 Osaka Asia 2018 20409.0
# 1195 Cairo Middle East 2018 19849.6
# 1336 Dhaka Asia 2018 19632.6
print(df['name'].shape, df['name'].unique())
# (10,) ['Tokyo' 'Delhi' 'Shanghai' 'Beijing' 'Mumbai' 'Sao Paulo' 'Mexico City'
# 'Osaka' 'Cairo' 'Dhaka']
上面经筛选后所得的 df
中 name
为唯一值的有 10
个,分别为 ['Tokyo' 'Delhi' 'Shanghai' 'Beijing' 'Mumbai' 'Sao Paulo' 'Mexico City' 'Osaka' 'Cairo' 'Dhaka']
。
基本:水平 / 垂直柱形
- 横向
使用 ax.barh(x, y)
来绘制水平柱状图,
fig, ax = plt.subplots(figsize=(15, 8))
ax.barh(df['name'], df['value'])
plt.show()
效果图如下所示,
- 竖向
使用 ax.bar(x, y)
来绘制垂直柱状图,
fig, ax = plt.subplots(figsize=(15, 8))
ax.bar(df['name'], df['value'])
plt.show()
效果图如下所示,
主题:颜色、文字、网格线
- 颜色
使用ax.barh(color=[])
来定义bar
的颜色,语法如下:
def barh(self, x=None, y=None, **kwargs):
"""
Make a horizontal bar plot.
A horizontal bar plot is a plot that presents quantitative data with
rectangular bars with lengths proportional to the values that they
represent. A bar plot shows comparisons among discrete categories. One
axis of the plot shows the specific categories being compared, and the
other axis represents a measured value.
"""
return self(kind="barh", x=x, y=y, **kwargs)
在示例中,
fig, ax = plt.subplots(figsize=(15, 8))
colors = dict(zip(
['India','Europe','Asia','Latin America','Middle East','North America','Africa'],
['#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff', '#f7bb5f', '#eafb50']
))
group_lk = df.set_index('name')['group'].to_dict()
ax.barh(df['name'], df['value'], color=[colors[group_lk[x]] for x in df['name']])
plt.show()
效果图如下所示,
- 文字
使用 ax.text
来添加文字,语法如下:
def text(self, x, y, s, fontdict=None, **kwargs):
"""
Add text to the Axes.
Add the text *s* to the Axes at location *x*, *y* in data coordinates.
Parameters
----------
x, y : float
The position to place the text. By default, this is in data
coordinates. The coordinate system can be changed using the
*transform* parameter.
s : str
The text.
fontdict : dict, default: None
A dictionary to override the default text properties. If fontdict
is None, the defaults are determined by `.rcParams`.
在示例中,
fig, ax = plt.subplots(figsize=(15, 8))
colors = dict(zip(
['India','Europe','Asia','Latin America','Middle East','North America','Africa'],
['#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff', '#f7bb5f', '#eafb50']
))
group_lk = df.set_index('name')['group'].to_dict()
ax.barh(df['name'], df['value'], color=[colors[group_lk[x]] for x in df['name']])
for i, (value, name) in enumerate(zip(df['value'], df['name'])):
dx = df['value'].max() / 200
ax.text(value-dx, i, name, ha='right', size=10) # Tokyo: name
ax.text(value-dx, i-.25, group_lk[name], ha='right', size=10) # Asia: group name
ax.text(value+dx, i, value, ha='left', size=10) # 38194.2: value
ax.text(1, 0.4, f'Year: {current_year}', transform=ax.transAxes, size=30, ha='right')
plt.show()
效果图如下所示,
- 复合效果
fig, ax = plt.subplots(figsize=(15, 8))
colors = dict(zip(
['India','Europe','Asia','Latin America','Middle East','North America','Africa'],
['#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff', '#f7bb5f', '#eafb50']
))
group_lk = df.set_index('name')['group'].to_dict()
def draw_barchart(df, year):
df = df[df['year'].eq(year)].sort_values(by='value', ascending=True).tail(10)
df = df[::-1]
ax.clear()
ax.barh(df['name'], df['value'], color=[colors[group_lk[x]] for x in df['name']])
dx = df['value'].max() / 200
for i, (value, name) in enumerate(zip(df['value'], df['name'])):
ax.text(value - dx, i, name, size=14, weight=600, ha='right', va='bottom')
ax.text(value - dx, i - .25, group_lk[name], size=10, color='#444444', ha='right', va='baseline')
ax.text(value + dx, i, f'{value:,.0f}', size=14, ha='left', va='center')
# ... polished styles
ax.text(0, 1.1, 'The most populous cities in the world in 2018',
transform=ax.transAxes, size=24, weight=600, ha='left')
ax.text(0, 1.06, 'Population (thousands)', transform=ax.transAxes, size=12, color='#777777')
ax.xaxis.set_major_formatter(ticker.StrMethodFormatter('{x:,.0f}'))
ax.xaxis.set_ticks_position('top')
ax.tick_params(axis='x', colors='#777777', labelsize=12)
ax.set_yticks([])
# ax.margins(0, 0.01)
ax.grid(which='major', axis='x', linestyle='-.')
ax.set_axisbelow(True)
ax.text(1, 0.4, year, transform=ax.transAxes, color='#777777', size=46, ha='right', weight=800)
ax.text(1.1, 0, 'by @XS', transform=ax.transAxes, ha='right',
color='#777777', bbox=dict(facecolor='white', alpha=0.8, edgecolor='white'))
plt.box(False)
draw_barchart(df, 2018)
plt.show()
效果图如下所示,
动图
为了设置动画,我们将使用 matplotlib.animation
中的 FuncAnimation
。 FuncAnimation
通过重复调用函数(在画布上绘制)来制作动画。
在我们的例子中,该函数将是 draw_barchart
。我们还使用 frame
,这个参数接受你想要运行的函数的值 —— 我们将从 1968
年运行到 2018
年。
-
animation
使用 animation
来添加回调函数,
df = pd.read_csv('3d.csv', usecols=['name', 'group', 'year', 'value'])
def draw_barchart(year, df):
colors = dict(zip(
['India', 'Europe', 'Asia', 'Latin America', 'Middle East', 'North America', 'Africa'],
['#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff', '#f7bb5f', '#eafb50']
))
group_lk = df.set_index('name')['group'].to_dict()
df = df[df['year'].eq(year)].sort_values(by='value', ascending=True).tail(10)
df = df[::-1]
ax.clear()
ax.barh(df['name'], df['value'], color=[colors[group_lk[x]] for x in df['name']], edgecolor='black')
dx = df['value'].max() / 200
ax.set_xlim([0, 40000])
for i, (value, name) in enumerate(zip(df['value'], df['name'])):
ax.text(value - dx, i, name, size=14, weight=600, ha='right', va='bottom')
ax.text(value - dx, i - .25, group_lk[name], size=10, color='#444444', ha='right', va='baseline')
ax.text(value + dx, i, f'{value:,.0f}', size=14, ha='left', va='center')
ax.text(0, 1.1, f'The most populous cities in the world in {year}',
transform=ax.transAxes, size=24, weight=600, ha='left')
ax.text(0, 1.06, 'Population (thousands)', transform=ax.transAxes, size=12, color='#777777')
ax.xaxis.set_major_formatter(ticker.StrMethodFormatter('{x:,.0f}'))
ax.xaxis.set_ticks_position('top')
ax.tick_params(axis='x', colors='#777777', labelsize=12)
# ax.set_yticks([])
ax.margins(0, 0.01)
ax.grid(which='major', axis='x', linestyle='-.')
ax.set_axisbelow(True)
ax.text(1, 0.4, year, transform=ax.transAxes, color='#777777', size=46, ha='right', weight=800)
ax.text(1.1, 0, 'by @XS', transform=ax.transAxes, ha='right',
color='#777777', bbox=dict(facecolor='white', alpha=0.8, edgecolor='white'))
plt.box(False)
fig, ax = plt.subplots(figsize=(15, 8))
animator = animation.FuncAnimation(fig, draw_barchart, frames=range(1968, 2019), fargs=(df,), repeat_delay=100)
animator.save(filename='1.gif', writer='imagemagick', fps=5)
效果图如下所示,
线图
准备数据,如下所示:
# fake data
x = np.linspace(0, 10)
# [ 0. 0.20408163 0.40816327 0.6122449 0.81632653 1.02040816
# 1.2244898 1.42857143 1.63265306 1.83673469 2.04081633 2.24489796
# 2.44897959 2.65306122 2.85714286 3.06122449 3.26530612 3.46938776
# 3.67346939 3.87755102 4.08163265 4.28571429 4.48979592 4.69387755
# 4.89795918 5.10204082 5.30612245 5.51020408 5.71428571 5.91836735
# 6.12244898 6.32653061 6.53061224 6.73469388 6.93877551 7.14285714
# 7.34693878 7.55102041 7.75510204 7.95918367 8.16326531 8.36734694
# 8.57142857 8.7755102 8.97959184 9.18367347 9.3877551 9.59183673
# 9.79591837 10. ]
y = np.sin(x)
# [ 0. 0.20266794 0.39692415 0.57470604 0.72863478 0.85232157
# 0.94063279 0.98990308 0.99808748 0.96484631 0.89155923 0.78126802
# 0.63855032 0.46932961 0.2806294 0.08028167 -0.12339814 -0.32195632
# -0.50715171 -0.67129779 -0.80758169 -0.91034694 -0.97532829 -0.99982867
# -0.9828312 -0.92504137 -0.82885774 -0.6982724 -0.53870529 -0.35677924
# -0.16004509 0.04333173 0.24491007 0.43632343 0.6096272 0.75762842
# 0.8741843 0.9544572 0.99511539 0.99447137 0.95255185 0.8710967
# 0.75348673 0.60460332 0.43062587 0.23877532 0.0370144 -0.16628279
# -0.36267843 -0.54402111]
x
为横坐标,y
为纵坐标。
基本
使用 ax.plot(x, y)
来绘制线图,
fig, ax = plt.subplots()
line, = ax.plot(x, y)
plt.show()
效果图如下所示,
动图
x = np.linspace(0, 10)
y = np.sin(x)
fig, ax = plt.subplots()
line, = ax.plot(x, y)
def update(num, x, y, line):
line.set_data(x[:num], y[:num])
return line,
ani = animation.FuncAnimation(fig, update, len(x), interval=100,
fargs=[x, y, line], blit=True)
ani.save('1.gif', writer='imagemagick', fps=60)
- 前两个参数只是
fig
(图形对象)和update
(更新每一帧中绘制对象的函数)。 - 传递给构造函数的第三个参数是
len(x)
,它指示数据点的总数(回想一下x
和y
是列表)。这正是传递给update
的num
参数!在每一帧中,一个从1
到len(x)
的值被赋予更新函数以生成不同的图。这些情节构成了Animation
的 “幻觉”。 - 参数
interval
是以毫秒为单位的帧之间的延迟,在这种情况下设置为100 ms
。 - 参数
fargs
是一个包含传递给更新函数的其他参数(除了num
)的元组,它是x
、y
和line
的顺序相同的元组。 - 最后一个参数
blit
设置为True
以优化结果。
FuncAnimation
的构造函数中还有很多其他的参数,你可以查看 FuncAnimation
的文档了解更多。
最后调用 FuncAnimation
对象的 save
方法保存动画。在这里,我们使用 gif
生成器 imagemagick
将 ani
保存到 gif
文件。在这里,我们将帧率 fps
设置为 60
。
效果图如下,
还有另外一个例子,效果如下所示,源码参考这里 15
折线图
参考这里 13
准备数据,如下所示:
x_1 = [1, 2, 3, 4]
y_1 = [10, 50, 20, 100]
x_2 = [1, 2, 3, 4]
y_21 = [45, 50, 20, 100]
y_22 = [26, 10, 76, 25]
y_23 = [11, 66, 55, 88]
y_24 = [69, 50, 35, 100]
基本
使用 ax.plot(x, y)
来绘制线图,
matplotlib.rcParams['font.sans-serif'] = ['SimHei'] # 用黑体显示中文
# "r" 表示红色,ms用来设置*的大小
plt.plot(x_1, y_1, "r", marker='*', ms=10, label="a")
plt.xticks(ticks=x_1, labels=['a', 'b', 'c', 'd'])
plt.xticks(rotation=45)
plt.xlabel("X")
plt.yticks(ticks=[i*40 for i in range(3)])
plt.ylabel("Y")
plt.title("title")
plt.legend(loc="upper left")
for i, j in zip(x_1, y_1):
plt.text(i, j+1, str(j), ha='center', va='bottom', fontsize=10, rotation=45)
plt.show()
效果图如下所示,
对于多个折线图,
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
x_2 = [1, 2, 3, 4]
y_21 = [45, 50, 20, 100]
y_22 = [26, 10, 76, 25]
y_23 = [11, 66, 55, 88]
y_24 = [69, 50, 35, 100]
plt.plot(x_2, y_21, marker='*', ms=10, label="a")
plt.plot(x_2, y_22, marker='*', ms=10, label="b")
plt.plot(x_2, y_23, marker='*', ms=10, label="c")
plt.plot(x_2, y_24, marker='*', ms=10, label="d")
plt.xticks(rotation=45)
plt.xlabel("X")
plt.ylabel("Y")
plt.title("title")
plt.legend(loc="upper left")
for y in [y_21, y_22, y_23, y_24]:
for i, j in zip(x_2, y):
plt.text(i, j+1, str(j), ha='center', va='bottom', fontsize=20, rotation=0)
plt.show()
效果图如下所示,
3D
柱状图
参考这里 17
准备数据,如下所示:
# fake data
_x = np.arange(4)
_y = np.arange(5)
_xx, _yy = np.meshgrid(_x, _y)
x, y = _xx.ravel(), _yy.ravel()
top = x + y
bottom = np.zeros_like(top)
width = depth = 1
基本
使用 ax.bar3d()
画出相应柱状图,
ax1.bar3d(x, y, bottom, width, depth, top, shade=True)
ax1.set_title('Shaded')
plt.savefig('3D-bar-example.png')
plt.show()
效果图如下所示,
示例
1.
import io
data = '''
raw Stage1 Stage2 Stage3 Stage4
asdfghdfs 1249.0 661.0 661.0 654.0 647.0
bgdfghdfs 1237.0 654.0 654.0 648.0 642.0
dfdfghdfs 1236.0 653.0 653.0 647.0 641.0
qwdfghdfs 1240.0 652.0 652.0 647.0 641.0
hjdfghdfs 1236.0 652.0 652.0 647.0 641.0
kldfghdfs 1234.0 651.0 651.0 645.0 640.0
sddfghdfs 1236.0 648.0 648.0 643.0 637.0
rfdfghdfs 1228.0 646.0 646.0 640.0 633.0
'''
df = pd.read_csv(io.StringIO(data), delim_whitespace=True)
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
X = np.arange(len(df))
color_list = ['#acc2d9', '#a8ff04', '#70b23f', '#952e8f', '#388004', '#efb435',
'#0c06f7', '#2242c7', '#05ffa6', '#0cb577']
fig = plt.figure(figsize=(12, 8))
ax = Axes3D(fig)
ly, lx = len(X), len(df.columns)
xpos = np.arange(0, lx, 1) # Set up a mesh of positions
ypos = np.arange(0, ly, 1)
xpos, ypos = np.meshgrid(xpos, ypos)
xpos = xpos.flatten() # Convert positions to 1D array
ypos = ypos.flatten()
zpos = np.zeros(lx * ly)
dx = 0.5 * np.ones_like(zpos)
dy = dx.copy()
dz = np.array(df).flatten()
cs = color_list[:lx] * ly
ax.bar3d(xpos, ypos, zpos, dx, dy, dz, alpha=0.8, color=cs)
ax.set_yticks(np.arange(len(df.index)) + 1.5)
ax.set_yticklabels(df.index)
ax.set_xticks(np.arange(len(df.columns)))
ax.set_xticklabels(df.columns)
ax.tick_params(axis='both', which='major', labelsize=10)
plt.gcf().autofmt_xdate()
ax.set_xlabel('Test case', labelpad=20)
ax.set_ylabel('Sample category', labelpad=15)
ax.set_zlabel("Number of Samples", labelpad=10)
plt.subplots_adjust(left=0.18, right=0.79, top=0.99, bottom=0.08)
for tick in ax.xaxis.get_major_ticks():
tick.label1.set_horizontalalignment('left')
plt.show()
效果如下所示:
线图
参考这里 18
动图
# Fixing random state for reproducibility
np.random.seed(19680801)
def random_walk(num_steps, max_step=0.05):
"""Return a 3D random walk as (num_steps, 3) array."""
start_pos = np.random.random(3)
steps = np.random.uniform(-max_step, max_step, size=(num_steps, 3))
walk = start_pos + np.cumsum(steps, axis=0)
return walk
def update_lines(num, walks, lines):
for line, walk in zip(lines, walks):
# NOTE: there is no .set_data() for 3 dim data...
line.set_data(walk[:num, :2].T)
line.set_3d_properties(walk[:num, 2])
return lines
# Data: 40 random walks as (num_steps, 3) arrays
num_steps = 30
walks = [random_walk(num_steps) for index in range(40)]
# Attaching 3D axis to the figure
fig = plt.figure()
ax = fig.add_subplot(projection="3d")
# Create lines initially without data
lines = [ax.plot([], [], [])[0] for _ in walks]
# Setting the axes properties
ax.set(xlim3d=(0, 1), xlabel='X')
ax.set(ylim3d=(0, 1), ylabel='Y')
ax.set(zlim3d=(0, 1), zlabel='Z')
# Creating the Animation object
ani = animation.FuncAnimation(
fig, update_lines, num_steps, fargs=(walks, lines), interval=100)
plt.show()
效果图如下,
折线图
参考这里 19
准备数据,如下所示:
x_1 = np.array([100, 0])
# [100 0
y_1 = np.array([100, 100])
# [100 100]
z_1 = np.array([10, 60])
# [10 60]
基本
使用 ax.plot3D()
画出相应柱状图,
fig = plt.figure()
ax = plt.axes(projection='3d')
# defining coordinates for the 2 points.
x_1 = np.array([100, 0])
y_1 = np.array([100, 100])
z_1 = np.array([10, 60])
# plotting
ax.plot3D(x_1, y_1, z_1)
for x, y, z in zip(x_1, y_1, z_1):
ax.text(x-5, y-5, z+10, s=(x, y, z))
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.savefig(f"3D-linear-example.png")
plt.show()
效果图如下所示,
参考链接
#todo
[]: Three-Dimensional Plotting in Matplotlib