Matplotlib 是 Python 生态中最基础、最强大的数据可视化库,被誉为 Python 可视化的“祖父”和“瑞士军刀”。它的核心价值在于提供了无与伦比的灵活性和控制力,允许你从零开始创建和定制几乎任何类型的静态、动画或交互式图表。
核心定位与特点
定位:Python 科学计算栈(NumPy, SciPy, Pandas)的基础绘图库。许多高级可视化库(如 Seaborn, pandas.plot)都构建在 Matplotlib 之上。
核心特点:
全面控制:你可以控制图表的每一个像素,从坐标轴刻度到图例样式,实现出版级精度的输出。
广泛的图表支持:支持折线图、散点图、柱状图、直方图、饼图、等高线图、3D图等数十种图表。
多输出格式:可将图表输出为 PNG, PDF, SVG, EPS 等多种图片或矢量格式。
跨平台交互:在 Jupyter Notebook、独立脚本、Web 应用服务器中均可使用。
一 画直线图
1.1 figure使用
import numpy as np import matplotlib.pyplot as plt # 从-3到中取50个数 x = np.linspace(-3, 3, 50) print(x) y1 = 2*x+1 y2 = x**2 plt.figure() plt.plot(x, y1) plt.figure(num=3, figsize=(8, 5)) # figsize的设置长和宽 plt.plot(x, y2) plt.plot(x, y1, color='red', linewidth=10.0, linestyle='--') # linewidth 设置线的宽度, linesyyle设置线的形状 # savefig 保存图片 plt.savefig("./image_dir/xianxing.png") plt.show()1.2 设置坐标轴
# 从-3到中取50个数 x = np.linspace(-3, 3, 50) y1 = 2 * x + 1 y2 = x ** 2 plt.figure(num=3, figsize=(8, 5)) # figsize的设置长和宽 plt.plot(x, y2) plt.plot(x, y1, color='red', linewidth=10.0, linestyle='--') plt.xlim((-1, 2)) # 设置x轴的范围 plt.ylim((-2, 3)) # 设置y轴的范围 plt.xlabel('I am x') # 设置x轴的名称 plt.ylabel('I am y') # 设置y轴额名称 new_ticks = np.linspace(-1, 2, 5) print(new_ticks) plt.xticks(new_ticks) # 设置x轴的范围的刻度值 # 设置y轴的范围的刻度值 plt.yticks([-2, -1, 0, 1, 2, 3], [r'$really\ bad$', r'$bad$', r'$normal$', r'$good$', r'$really\ good$']) plt.savefig('./image_dir/xlim.png') plt.show()# 从-3到中取50个数 x = np.linspace(-3, 3, 50) y1 = 2 * x + 1 y2 = x ** 2 plt.figure(num=3, figsize=(8, 5)) # figsize的设置长和宽 plt.plot(x, y2) plt.plot(x, y1, color='red', linewidth=10.0, linestyle='--') plt.xlim((-1, 2)) # 设置x轴的范围 plt.ylim((-2, 3)) # 设置y轴的范围 plt.xlabel('I am x') # 设置x轴的名称 plt.ylabel('I am y') # 设置y轴额名称 new_ticks = np.linspace(-1, 2, 5) print(new_ticks) plt.xticks(new_ticks) # 设置x轴的范围的刻度值 # 设置y轴的范围的刻度值 plt.yticks([-2, -1, 0, 1, 2, 3], [r'$really\ bad$', r'$bad$', r'$normal$', r'$good$', r'$really\ good$']) # gca = 'get current axis' ax = plt.gca() # 将轴的右边去掉 ax.spines['right'].set_color('none') # 将轴的上边去掉 ax.spines['top'].set_color('none') # 将下轴设置为x ax.xaxis.set_ticks_position('bottom') # 将左轴设置为y ax.yaxis.set_ticks_position('left') # 设置下轴的位置 set_position(outward, axes) ax.spines['bottom'].set_position(('data', 0)) # 设置左轴位置 ax.spines['left'].set_position(('data', '0')) plt.savefig('./image_dir/xlim2.png') plt.show()1.3 legend 图例
# 从-3到中取50个数 x = np.linspace(-3, 3, 50) y1 = 2 * x + 1 y2 = x ** 2 plt.figure(num=3, figsize=(8, 5)) # figsize的设置长和宽 plt.xlim((-1, 2)) # 设置x轴的范围 plt.ylim((-2, 3)) # 设置y轴的范围 plt.xlabel('I am x') # 设置x轴的名称 plt.ylabel('I am y') # 设置y轴额名称 new_ticks = np.linspace(-1, 2, 5) print(new_ticks) plt.xticks(new_ticks) # 设置x轴的范围的刻度值 # 设置y轴的范围的刻度值 plt.yticks([-2, -1, 0, 1, 2, 3], [r'$really\ bad$', r'$bad$', r'$normal$', r'$good$', r'$really\ good$']) # plt.plot是有返回值的 l1, = plt.plot(x, y2, label='up') l2, = plt.plot(x, y1, color='red', linewidth=10.0, linestyle='--', label='down') # handles, labels是设置名称, loc是设置位置 plt.legend(handles=[l1, l2], labels=['aaa', 'bbb'], loc='best') plt.savefig('./image_dir/xlim3.png') plt.show()1.4 annotation标注
# 从-3到中取50个数 x = np.linspace(-3, 3, 50) y1 = 2 * x + 1 # y2 = x ** 2 plt.figure(num=3, figsize=(8, 5)) # figsize的设置长和宽 # plt.plot(x, y2) plt.plot(x, y1, color='red', linewidth=1.0, linestyle='--') # gca = 'get current axis' ax = plt.gca() # 将轴的右边去掉 ax.spines['right'].set_color('none') # 将轴的上边去掉 ax.spines['top'].set_color('none') # 将下轴设置为x ax.xaxis.set_ticks_position('bottom') # 将左轴设置为y ax.yaxis.set_ticks_position('left') # 设置下轴的位置 set_position(outward, axes) ax.spines['bottom'].set_position(('data', 0)) # 设置左轴位置 ax.spines['left'].set_position(('data', '0')) x0 = 1 y0 = 2 * x0 + 1 plt.scatter(x0, y0, s=50, color='b') plt.plot([x0, x0], [y0, 0], 'k--', lw=2.5) # method1 xycoords依赖的数据集 plt.annotate(r'$2x+1=%s$' % y0, xy=(x0, y0), xycoords='data', xytext=(+30, -30), textcoords='offset points', fontsize=16, arrowprops=dict(arrowstyle='->', connectionstyle='arc3, rad=.2')) # method2 plt.text(-3.7, 3, r'$ this is the some test mu sigma_i alpha_t$', fontdict={'size':16, 'color':'r'}) plt.savefig('./image_dir/xlim4.png') plt.show()1.5 tick能见度
# 从-3到中取50个数 x = np.linspace(-3, 3, 50) y1 = 0.1*x # y2 = x ** 2 plt.figure(num=3, figsize=(8, 5)) # figsize的设置长和宽 # plt.plot(x, y2) plt.plot(x, y1, linewidth=10) plt.ylim(-2, 2) # gca = 'get current axis' ax = plt.gca() # 将轴的右边去掉 ax.spines['right'].set_color('none') # 将轴的上边去掉 ax.spines['top'].set_color('none') # 将下轴设置为x ax.xaxis.set_ticks_position('bottom') # 将左轴设置为y ax.yaxis.set_ticks_position('left') # 设置下轴的位置 set_position(outward, axes) ax.spines['bottom'].set_position(('data', 0)) # 设置左轴位置 ax.spines['left'].set_position(('data', '0')) for label in ax.get_xticklabels() + ax.get_yticklabels(): label.set_fontsize(12) label.set_bbox(dict(facecolor='blue', edgecolor='None', alpha=0.9)) plt.savefig('./image_dir/xlim5.png') plt.show()二 散点图
scatter函数原型:
其中散点的形状参数marker如下:
其中颜色参数c如下:
n = 1024 # 均值是0, 方差是1, 取1024个数 x = np.random.normal(0, 1, n) y = np.random.normal(0, 1, n) # 设置颜色值 T = np.arctan2(y, x) bar = plt.scatter(x, y, s=10, c=T, alpha=0.5, cmap='hot') # plt.xticks(()) # plt.yticks(()) plt.colorbar(bar) plt.savefig('./image_dir/scatter.png') plt.show()三 柱状图
n = 12 x = np.arange(n) print(x) # np.random.uniform(0.5, 1.0, n) 去、取0.5 到 1 之间12个数 y1 = (1-x/float(n)) * np.random.uniform(0.5, 1.0, n) y2 = (1 - x / float(n)) * np.random.uniform(0.5, 1.0, n) plt.bar(x, +y1, facecolor='#9999ff', edgecolor='white') plt.bar(x, -y2, facecolor='#ff9999', edgecolor='white') plt.xticks(()) plt.yticks(()) for x, y, y2 in zip(x, y1, y2): # 给每根柱子加上标识 plt.text(x, y+0.05, '%.2f'%y, ha='center', va='bottom') plt.text(x, -y2 - 0.05, f'{round(y2, 2)}', ha='center', va='top') plt.savefig('./image_dir/bar.png') plt.show()四:等高线图
def f(x, y): return (1-x/2+x**5+y**3)*np.exp(-x**2-y**2) n = 256 x = np.linspace(-3, 3, n) y = np.linspace(-3, 3, n) ''' meshgrid函数就是用两个坐标轴上的点在平面上画网格(当然这里传入的参数是两个的时候)。 当然我们可以指定多个参数,比如三个参数, 那么我们的就可以用三个一维的坐标轴上的点在三维平面上画网格。 ''' X, Y = np.meshgrid(x, y) # use plt.contourf to filling contours # X, Y and value for (X, Y)point plt.contourf(X, Y, f(X, Y), 8, alpha=0.75, cmap='hot') # plt.xticks(()) # plt.yticks(()) # use plt.contour to add contour lines 8表示分成10份, 0分成2份 C = plt.contour(X, Y, f(X, Y), 8, colors='black', linewidth=.5) # adding label plt.clabel(C, inline=True, fontsize=10) plt.savefig('./image_dir/contourf.png') plt.show()五 直方图
import matplotlib.pyplot as plt import numpy as np import matplotlib def hist1(): # 设置matplotlib正常显示中文和负号 matplotlib.rcParams['font.sans-serif'] = ['SimHei'] # 用黑体显示中文 matplotlib.rcParams['axes.unicode_minus'] = False # 正常显示负号 data = np.random.randn(10000) ''' data: 绘图数据 bins:直方图的长方形数目, 可选项, 默认为10 normed:是否将得到的直方图向量归一化, 可选项, 默认为0, 代表不归一化, 显示频数。 normed=1,表示归一化,显示频率 facecolor: 长方形的颜色 edgecolor: 长方形边框的颜色 alpha: 透明度 ''' plt.hist(data, bins=40, density=1, facecolor='blue', edgecolor='black', alpha=0.7) # 显示横轴标签 plt.xlabel("区间") # 显示纵轴标签 plt.ylabel("频数/频率") # 显示图标数 plt.title("频数/频率分布直方图") plt.show() if __name__ == '__main__': hist1()六 条形图
import matplotlib.pyplot as plt import matplotlib # 设置中文字体和负号正常显示 matplotlib.rcParams['font.sans-serif'] = ['SimHei'] matplotlib.rcParams['axes.unicode_minus'] = False label_list = ['2014', '2015', '2016', '2017'] # 横坐标刻度显示值 num_list1 = [20, 30, 15, 35] # 纵坐标值1 num_list2 = [15, 30, 40, 20] # 纵坐标值2 x = range(len(num_list1)) """ 绘制条形图 left:长条形中点横坐标 height:长条形高度 width:长条形宽度,默认值0.8 label:为后面设置legend准备 """ rects1 = plt.bar(left=x, height=num_list1, width=0.4, alpha=0.8, color='red', label="一部门") rects2 = plt.bar(left=[i + 0.4 for i in x], height=num_list2, width=0.4, color='green', label="二部门") plt.ylim(0, 50) # y轴取值范围 plt.ylabel("数量") """ 设置x轴刻度显示值 参数一:中点坐标 参数二:显示值 """ plt.xticks([index + 0.2 for index in x], label_list) plt.xlabel("年份") plt.title("某某公司") plt.legend() # 设置题注 # 编辑文本 for rect in rects1: height = rect.get_height() plt.text(rect.get_x() + rect.get_width() / 2, height+1, str(height), ha="center", va="bottom") for rect in rects2: height = rect.get_height() plt.text(rect.get_x() + rect.get_width() / 2, height+1, str(height), ha="center", va="bottom") plt.show()七 水平条形图
import matplotlib.pyplot as plt import matplotlib matplotlib.rcParams['font.sans-serif'] = ['SimHei'] matplotlib.rcParams['axes.unicode_minus'] = False price = [39.5, 39.9, 45.4, 38.9, 33.34] """ 绘制水平条形图方法barh 参数一:y轴 参数二:x轴 """ plt.barh(range(5), price, height=0.7, color='steelblue', alpha=0.8) # 从下往上画 plt.yticks(range(5), ['亚马逊', '当当网', '中国图书网', '京东', '天猫']) plt.xlim(30,47) plt.xlabel("价格") plt.title("不同平台图书价格") for x, y in enumerate(price): plt.text(y + 0.2, x - 0.1, '%s' % y) plt.show()八 堆叠条形图
import matplotlib.pyplot as plt import matplotlib matplotlib.rcParams['font.sans-serif'] = ['SimHei'] matplotlib.rcParams['axes.unicode_minus'] = False label_list = ['2014', '2015', '2016', '2017'] num_list1 = [20, 30, 15, 35] num_list2 = [15, 30, 40, 20] x = range(len(num_list1)) rects1 = plt.bar(left=x, height=num_list1, width=0.45, alpha=0.8, color='red', label="一部门") rects2 = plt.bar(left=x, height=num_list2, width=0.45, color='green', label="二部门", bottom=num_list1) plt.ylim(0, 80) plt.ylabel("数量") plt.xticks(x, label_list) plt.xlabel("年份") plt.title("某某公司") plt.legend() plt.show()九 饼图
import matplotlib.pyplot as plt import matplotlib matplotlib.rcParams['font.sans-serif'] = ['SimHei'] matplotlib.rcParams['axes.unicode_minus'] = False label_list = ["第一部分", "第二部分", "第三部分"] # 各部分标签 size = [55, 35, 10] # 各部分大小 color = ["red", "green", "blue"] # 各部分颜色 explode = [0.05, 0, 0] # 各部分突出值 """ 绘制饼图 explode:设置各部分突出 label:设置各部分标签 labeldistance:设置标签文本距圆心位置,1.1表示1.1倍半径 autopct:设置圆里面文本 shadow:设置是否有阴影 startangle:起始角度,默认从0开始逆时针转 pctdistance:设置圆内文本距圆心距离 返回值 l_text:圆内部文本,matplotlib.text.Text object p_text:圆外部文本 """ patches, l_text, p_text = plt.pie(size, explode=explode, colors=color, labels=label_list, labeldistance=1.1, autopct="%1.1f%%", shadow=False, startangle=90, pctdistance=0.6) plt.axis("equal") # 设置横轴和纵轴大小相等,这样饼才是圆的 plt.legend() plt.show()十 保存image图像:
a = np.random.rand(9).reshape(3, 3) plt.imshow(a, interpolation='nearest', cmap='bone', origin='upper') plt.colorbar() plt.xticks(()) plt.yticks(()) plt.savefig('./image_dir/imshow.png') plt.show()十一 画3d图
import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D def test1(): fig = plt.figure() ax = Axes3D(fig) x = np.arange(-4, 4, 0.25) print(x) y = np.arange(-4, 4, 0.25) x, y = np.meshgrid(x, y) # np.sqrt(x) : 计算数组各元素的平方根 R = np.sqrt(x ** 2 + y ** 2) # height value z = np.sin(R) ax.plot_surface(x, y, z, rstride=1, cstride=1, cmap='rainbow') # zdir 表示向那个轴投影 ax.contourf(x, y, z, zdir='z', offset=-2, cmap='rainbow') # 设置等高线的高度 ax.set_zlim(-2, 2) plt.show() if __name__ == '__main__': test1()十二 subplot多图合一
方法一
# method1: subplot2grid ################# ''' 第一个参数(3, 3) 是把图分成3行3列 第二个参数是位置 (0, 0)表示从0行0列开始 第三个参数 colspan=3 表示列占3列 , 第四个参数 rowspan=1 表示行占一行 ''' plt.figure() ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=3, rowspan=1) ax1.plot([1, 2], [1, 2]) ax1.set_title('al1_title') ax2 = plt.subplot2grid((3, 3), (1, 0), colspan=2,) ax3 = plt.subplot2grid((3, 3), (1, 2), rowspan=2) ax4 = plt.subplot2grid((3, 3), (2, 0)) ax5 = plt.subplot2grid((3, 3), (2, 1)) plt.savefig('./image_dir/grid1.png') plt.show()方法二
import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec plt.figure() gs = gridspec.GridSpec(3, 3) ax1 = plt.subplot(gs[0, :]) ax2 = plt.subplot(gs[1, :2]) ax3 = plt.subplot(gs[1:, 2]) ax4 = plt.subplot(gs[-1, 0]) ax5 = plt.subplot(gs[-1, -2]) plt.savefig('./image_dir/grid2.png') plt.show()方法三
# method4 plt.figure() plt.subplot(2, 2, 1) plt.plot([0, 1], [0, 1]) plt.subplot(222) plt.plot([0, 1], [0, 2]) plt.subplot(223) plt.plot([0, 1], [0, 3]) plt.subplot(224) plt.plot([0, 1], [0, 4]) plt.savefig('./image_dir/grid4.png') plt.tight_layout() plt.show()方法四
# method 3 : easy to define structure f, ((ax11, ax12), (ax21, ax22)) = plt.subplots(2, 2, sharex=True, sharey=True) ax11.scatter([1, 2], [1, 2]) plt.savefig('./image_dir/grid3.png') plt.tight_layout() plt.show()十三 画图中图
fig = plt.figure() x = np.arange(1, 9, 1) y = np.linspace(1, 10, 8) left, bottom, width, height = 0.1, 0.1, 0.8, 0.8 ax1 = fig.add_axes([left, bottom, width, height]) ax1.plot(x, y, 'r') ax1.set_xlabel('x') ax1.set_ylabel('y') ax1.set_title('title') left, bottom, width, height = 0.2, 0.6, 0.25, 0.25 ax2 = fig.add_axes([left, bottom, width, height]) ax2.plot(y, x, 'b') ax2.set_xlabel('x') ax2.set_ylabel('y') ax2.set_title('title inside 1') left, bottom, width, height = 0.6, 0.2, 0.25, 0.25 ax3 = fig.add_axes([left, bottom, width, height]) ax3.plot(y, x, 'g') ax3.set_xlabel('x') ax3.set_ylabel('y') ax3.set_title('title inside 2') plt.savefig('./image_dir/tu1.png') plt.tight_layout() plt.show()十四 次坐标轴
x = np.arange(0, 10, 0.1) y1 = 0.5*x**2 y2 = -1*x**2 fig, ax1 = plt.subplots() ax2 = ax1.twinx() ax1.plot(x, y1, 'g-') ax2.plot(x, y2, 'b--') ax1.set_xlabel('X data') ax1.set_ylabel('Y1', color='g') ax2.set_ylabel('Y2', color='b') plt.savefig('./image_dir/xy.png') plt.tight_layout() plt.show()十五 animation
import numpy as np from matplotlib import pyplot as plt from matplotlib import animation fig, ax = plt.subplots() x = np.arange(0, 2*np.pi, 0.01) print(len(x)) print(x) line, = ax.plot(x, np.sin(x)) def animate(i): line.set_ydata(np.sin(x+i/10)) return line, def init(): line.set_ydata(np.sin(x)) return line, # func 表示animation的动画, frames表示100个时间点, init_func 表示初始点, # inyterval 表示每隔多少时间点刷新 一次, blit是否是全部更新, 如果为FLASE则更新需要更新的点 ani = animation.FuncAnimation(fig=fig, func=animate, frames=100, init_func=init, interval=20, blit=False) plt.savefig('./image_dir/animation.png') plt.tight_layout() plt.show()