首先来看几个简单的图表, 下面4段不一样的matplotlib绘图代码最终的结果是同样的,绘制的图形以下图所示。html
a = np.linspace(-5, 5, 100) b = np.sin(a) c = np.cos(a) # -------------------------------------- # # ---------------First way-------------- # fig, ax = plt.subplots() ax.set_title('Sin-Cos') ax.set_xlabel('X') ax.set_ylabel('Y') ax.plot(a, b, c='r') ax.plot(a, c, c='g') ax.legend(['a', 'b']) fig.show() # -------------------------------------- # # ---------------Second way-------------- # fig = plt.figure() ax = fig.add_subplot(111) ax.set_title('Sin-Cos') ax.set_xlabel('X') ax.set_ylabel('Y') ax.plot(a, b, c='r') ax.plot(a, c, c='g') ax.legend(['a', 'b']) fig.show() # -------------------------------------- # # ---------------Third way-------------- # plt.figure() plt.title('Sin-Cos') plt.xlabel('X') plt.ylabel('Y') plt.plot(a, b, c='r') plt.plot(a, c, c='g') plt.legend(['a', 'b']) plt.show() # -------------------------------------- # # ---------------Fourth way------------- # plt.subplot(111) plt.title('Sin-Cos') plt.xlabel('X') plt.ylabel('Y') plt.plot(a, b, c='r') plt.plot(a, c, c='g') plt.legend(['a', 'b']) plt.show()
在以上的4种实现方式中,可能大多数都会使用后面两种,即直接使用plt.plot()进行绘制,我刚开始也同样,它看起来简单,用起来也很方便。但当你逐渐习惯使用默认的方式来进行绘图时,慢慢会出现各类的问题,尤为是当你须要对图表使用不少自定义的设置的时候。默认接口隐藏了绘图过程当中的不少细节,由于不了解其内部细节,因此在绘图过程当中,对一些图表的设置方法全靠记忆。api
好了,说了这么多,咱们先来了解matplotlib绘图过程当中几个主要的名称,以下图所示:dom
接着,介绍图形(Axes)中的主要部件,了解了每一个部件在图中的位置以及对应的功能以后才能按照本身的方式来对图表进行设置。函数
以上图中的全部部件,均可以经过axes来实现精确的控制,好比须要设置x轴主刻度标签, 便可使用axes.xaxis.set_ticklabels(['', '']),这种面向对象的控制方式,很容易理解和实现。字体
基于上面的介绍,咱们来绘制一些图形。spa
直接上代码:3d
# 导入FontProperties类,该类用于定义字体,包括字体,大小等 from matplotlib.font_manager import FontProperties # 定义标签字体,字体为Time New Roman # 也能够经过指定fname(字体文件的路径)来定义字体 label_font = FontProperties(family='Times New Roman', size=18, weight='bold', style='normal') # 定义标题字体 title_font = FontProperties(family='Times New Roman', size=20, weight='bold', style='normal') # 定义坐标轴刻度字体 ticks_font = FontProperties(family='Times New Roman', size=12, weight='bold', style='normal') # 定义legend字体 legend_font = FontProperties(family='Times New Roman', size=18, weight='bold', style='normal') year = np.arange(1985, 2017, 1) ndvi = np.random.rand(len(year)) # 建立fig和axes fig, ax = plt.subplots(figsize=(10, 5)) # 取消x方向的格网 # axis.xaxis.grid(False) # 取消y方向的格网 # axis.yaxis.grid(False) # 取消全部格网 ax.grid(False) # 定义标题,字体和颜色 # axis.yaxis.label.set_fontproperties(font) # axis.xaxis.label.set_fontproperties(font) ax.set_xlabel('Year', fontproperties=label_font, color='black') ax.set_ylabel('NDVI', fontproperties=label_font, color='black') # 定义坐标轴显示范围 ax.set_xlim(1985, 2017) ax.set_ylim(0, 1) # 取消图表的上边界和右边界 ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) # 将图表的左边界和下边界的颜色设为黑色(默认为黑色) # 颜色能够参考: # https://matplotlib.org/3.1.3/gallery/color/color_demo.html#sphx-glr-gallery-color-color-demo-py ax.spines['left'].set_color('black') ax.spines['bottom'].set_color('black') # 将图表的主刻度字体改成指定字体,并设定刻度不旋转,遍历全部主刻度 for tick in ax.xaxis.get_majorticklabels(): tick.set_fontproperties(ticks_font) tick.set_rotation(0) for tick in ax.yaxis.get_majorticklabels(): tick.set_fontproperties(ticks_font) tick.set_rotation(0) # 设置图表的主刻度线的位置,x轴在下边,y轴在左边 ax.yaxis.set_ticks_position('left') ax.xaxis.set_ticks_position('bottom') # 设置显示的x主刻度 ax.set_xticks(np.arange(1985, 2017, 3)) # 绘制时间序列 ax.plot(year, ndvi) # 设置第一条line(这里只有一条)的属性 ax.lines[0].set_linewidth(2) ax.lines[0].set_linestyle('-') ax.lines[0].set_color('black') ax.lines[0].set_marker('*') ax.lines[0].set_markeredgecolor('red') # 设置图例 ax.legend(['TS1', ], prop=legend_font, facecolor='white') #设置标题 ax.set_title('Time Series', fontproperties=title_font, color='black') plt.show()
绘制结果以下所示:code
绘制图表的代码虽然比较长,但结构比较清楚,结合前面的部件介绍,了解每一步的含义,相信很容易就能看懂。orm
代码以下:htm
# 定义坐标轴刻度字体 ticks_font = FontProperties(family='Times New Roman', size=14, weight='normal', style='normal') # 定义画板大小 fig_width = 5 # space = fig_width / 100 left, bottom, width, height = fig_width / 10, fig_width / 10, fig_width / 2, fig_width / 2 scatter_region = [left, bottom, width, height] topbar_region = [left, bottom + height + space, width, height/2] rightbar_region = [left + width + space, bottom, width/2, height] # 定义画板 plt.figure(figsize=(fig_width, fig_width)) # 定义Axes用于绘制散点图 # plt.axes([left, bottom, width, height]) ax_scatter = plt.axes(scatter_region) # 定义Axes用于绘制x的直方图 ax_topbar = plt.axes(topbar_region) # 定义Axes用于绘制y的直方图 ax_rightbar = plt.axes(rightbar_region) # ax_rightbar.invert_xaxis() # ax_topbar.xaxis.set_ticks([]) # ax_rightbar.xaxis.set_ticks_position('bottom') # ax_rightbar.yaxis.set_ticks([]) # 设置坐标轴属性, 这里使用set_tick_params(),能够同时设置坐标轴的多个属性,详情能够参考: # https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.axes.Axes.tick_params.html#matplotlib.axes.Axes.tick_params ax_rightbar.yaxis.set_tick_params(bottom=False, labelbottom=False) ax_rightbar.xaxis.set_tick_params(direction='out', color='black', left=True, labelleft=True) ax_topbar.yaxis.set_tick_params(direction='out', color='black', left=True, labelleft=True) ax_topbar.xaxis.set_tick_params(bottom=False, labelbottom=False) # ax_scatter.xaxis.set_tick_params(direction='out', color='black', labelsize=12) # ax_scatter.yaxis.set_tick_params(direction='out', color='black', labelsize=12) # 以上两行代码等同于下面一句代码 ax_scatter.tick_params(direction='out', color='black') # 设置坐标轴字体 for ax in [ax_topbar, ax_scatter, ax_rightbar]: for tick in ax.yaxis.get_majorticklabels(): tick.set_fontproperties(ticks_font) for tick in ax.xaxis.get_majorticklabels(): tick.set_fontproperties(ticks_font) # s参数用于设置散点大小,c用于设置cmap ax_scatter.scatter(x, y, s=np.abs(x / y) * 10, c=np.abs(x * y) * 0.02, alpha=0.6) ax_topbar.hist(x, bins=np.linspace(np.min(x), np.max(x), 16), color='#2C5784') ax_rightbar.hist(y, bins=np.linspace(np.min(y), np.max(y), 16), orientation='horizontal', color='#20866C') plt.show()
绘制结果以下图所示:
# 生成数据 x = np.linspace(-4, 4, 1000) y1 = np.sin(x) y2 = np.cos(x) y3 = np.exp(x) from matplotlib.font_manager import FontProperties label_font = FontProperties(family='Times New Roman', size=18, weight='bold', style='normal') title_font = FontProperties(family='Times New Roman', size=20, weight='bold', style='normal') ticks_font = FontProperties(family='Times New Roman', size=12, weight='bold', style='normal') legend_font = FontProperties(family='Times New Roman', size=18, weight='bold', style='normal') fig, ax = plt.subplots(figsize=(8, 10), dpi=100, ncols=1, nrows=2) # 绘制函数图像 ax[0].plot(x, y1, color='red') ax[0].plot(x, y2, color='orange') ax[1].plot(x, y3, color='blue') # ax1和ax共享x轴,当须要在同一个图表中显示比例不一样的图形时使用,好比exp(x)和sin(x) # ax1 = ax.twinx() # --------------------------------------- Fig 1 --------------------------------------- # # 设置标题,坐标轴标签 ax[0].set_title(r'$y=sin(x)$', fontproperties=title_font, color='black', pad=10) # ax[0].set_xlabel(r'$x$', fontproperties=label_font, color='black', ha='right') # ax[0].set_ylabel(r'$y$', fontproperties=label_font, color='black') # ax[0].xaxis.set_label_coords(5, 0) # ax[0].xaxis.set_label_coords(0, 1.5) # 不显示右坐标轴和上坐标轴 ax[0].spines['top'].set_visible(False) ax[0].spines['right'].set_visible(False) # 移动左坐标轴和底部坐标轴到图形中间位置 ax[0].spines['left'].set_position('center') ax[0].spines['bottom'].set_position('center') # 设置x轴刻度 # ax[0].xaxis.set_ticks_position('left') # 设置x轴刻度坐标 ax[0].set_xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi]) # 设置x轴刻度标签 ax[0].set_xticklabels([r'$-\pi$', r'$-\frac{\pi}{2}$', r'$0$', r'$\frac{\pi}{2}$', r'$\pi$']) # 设置y轴刻度 ax[0].set_yticks([-1, 0, 1]) # 设置y轴刻度的位置 ax[0].yaxis.set_ticks_position('left') # ax[0].lines[1].set_linestyle('--') # annotate函数的详细参数解释能够参考: # https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.axes.Axes.annotate.html """ annotate(text, xy, xytext, xycoords, textcoords, arrowprops ,*args, **kwargs) text(string): 须要标注的文本 xy(tuple -> (float, float)): 标注的点/位置 xytext(tuple -> (float, float)): 放置标注文本的位置 textcoords(string): 给定xytext的坐标系统,可选('offset points', 'offset pixel') xycoords(string): 给定xy的坐标系,默认'data',表示使用待标注对象的坐标系统 fontproperties(FontProperties): 须要标注的文本 arrowprops(dict): 设置标注文本和标注点之间的链接方式。arrowstyle="->" 表示使用箭头链接, connectionstyle="arc3,rad=.6" 表示链接类型为圆弧, 半径为0.6 """ ax[0].annotate(r'$Sin(\frac{2\pi}{3}) = \frac{\sqrt{3}}{2}$', xy=(np.pi * 2 / 3, np.sqrt(3)/2), xycoords='data', xytext=(10, 30), \ textcoords='offset points', arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.6"), fontproperties=ticks_font) # 这里坐标轴标签是使用注记来设置的 ax[0].annotate(r'$X$', xy=(4.4, 0), xycoords='data', color='black', fontproperties=label_font) ax[0].annotate(r'$Cos(\frac{2\pi}{3}) = -\frac{1}{2}$', xy=(np.pi * 2 / 3, -1/2), xycoords='data', xytext=(-100, -30), \ textcoords='offset points', arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"), fontproperties=ticks_font) ax[0].annotate(r'$Y$', xy=(-0.3, 1.05), xycoords='data', color='black', fontproperties=label_font) # 标记特定位置 ax[0].scatter([2*np.pi/3, ], [-1/2,], color='orange', s=40) ax[0].plot([2*np.pi/3, 2*np.pi/3], [0, -1/2], linestyle='--', color='orange') ax[0].scatter([2*np.pi/3, ], [np.sqrt(3)/2,], color='red', s=40) ax[0].plot([2*np.pi/3, 2*np.pi/3], [0, np.sqrt(3)/2], linestyle='--', color='red') # 设置图例 ax[0].legend([r'$Sin(x)$', r'$Cos(x)$',], loc='best', prop=legend_font, shadow=False, facecolor='white') # --------------------------------------- Fig 2 --------------------------------------- # ax[1].spines['top'].set_visible(False) ax[1].spines['right'].set_visible(False) # 统一设置刻度标签字体 for sub_ax in ax: for tick in sub_ax.xaxis.get_majorticklabels(): tick.set_fontproperties(ticks_font) for tick in sub_ax.yaxis.get_majorticklabels(): tick.set_fontproperties(ticks_font) ax[1].annotate(r'$X$', xy=(4.4, -0.7), xycoords='data', color='black', fontproperties=label_font) ax[1].annotate(r'$Y$', xy=(-4.4, 56), xycoords='data', color='black', fontproperties=label_font) # 填充图像和坐标轴之间的图形 # 若是要在x方向上的曲线之间填充,可使用fill_betweenx ax[1].fill_between(x, y3, 0, color='green') # 使用tighe_layout能够自动调整子图参数,以使子图适合图形区域。 fig.tight_layout() plt.show()
# Heatmap from mpl_toolkits.axes_grid1 import make_axes_locatable, axes_size from matplotlib.font_manager import FontProperties label_font = FontProperties(family='Times New Roman', size=18, weight='bold', style='normal') title_font = FontProperties(family='Times New Roman', size=20, weight='bold', style='normal') ticks_font = FontProperties(family='Times New Roman', size=12, weight='bold', style='normal') legend_font = FontProperties(family='Times New Roman', size=18, weight='bold', style='normal') vegetables = ["cucumber", "tomato", "lettuce", "asparagus", "potato", "wheat", "barley"] farmers = ["Farmer Joe", "Upland Bros.", "Smith Gardening", "Agrifun", "Organiculture", "BioGoods Ltd.", "Cornylee Corp."] harvest = np.array([[0.8, 2.4, 2.5, 3.9, 0.0, 4.0, 0.0], [2.4, 0.0, 4.0, 1.0, 2.7, 0.0, 0.0], [1.1, 2.4, 0.8, 4.3, 1.9, 4.4, 0.0], [0.6, 0.0, 0.3, 0.0, 3.1, 0.0, 0.0], [0.7, 1.7, 0.6, 2.6, 2.2, 6.2, 0.0], [1.3, 1.2, 0.0, 0.0, 0.0, 3.2, 5.1], [0.1, 2.0, 0.0, 1.4, 0.0, 1.9, 6.3]]) fig_size=8 fig, ax = plt.subplots(figsize=(fig_size, fig_size), dpi=100) # 使用matplotlib3.1.1绘制,会出现heatmap显示不全的问题 # 这里使用的是matplotlib3.1.0 im = ax.imshow(harvest, cmap=plt.cm.GnBu_r) ax.set_xticks(np.arange(len(farmers))) ax.set_yticks(np.arange(len(vegetables))) # ha -> horizontal align # va -> vertical align ax.set_xticklabels(farmers, ha='right', va='bottom', rotation_mode="anchor") ax.set_yticklabels(vegetables) for tick in ax.xaxis.get_majorticklabels(): tick.set_rotation(45) tick.set_fontproperties(ticks_font) for tick in ax.yaxis.get_majorticklabels(): tick.set_fontproperties(ticks_font) for i in range(len(vegetables)): for j in range(len(farmers)): text = ax.text(j, i, harvest[i, j], ha="center", va="center", color="w", fontproperties=ticks_font) # 参数的设置我暂时也不太理解,能够参考: # https://stackoverflow.com/questions/18195758/set-matplotlib-colorbar-size-to-match-graph # 建立颜色条,colorbar能够理解为子图,即sub fig cbar = fig.colorbar(im, orientation='vertical', fraction=0.046, pad=0.04) # colorbar.ax能够看作是一个fig中的axes,具备axes的全部属性和方法 # 设置颜色条的刻度标签 cbar.ax.set_yticklabels(np.arange(0, 7)) # 设置颜色条的刻度标签字体 ticklabs = cbar.ax.get_yticklabels() cbar.ax.set_yticklabels(ticklabs, fontproperties=ticks_font) # 设置颜色条坐标轴字体 # https://stackoverflow.com/questions/15908371/matplotlib-colorbars-and-its-text-labels cbar.ax.set_ylabel('Color Bar', fontproperties=title_font, rotation=270, labelpad=16) # 设置标题字体 ax.set_title("Harvest of local farmers (in tons/year)", fontproperties=title_font, pad=10) fig.tight_layout() plt.show()
绘制结果以下所示:
以上的几种图形基本上按照了如下步骤进行绘制:
本文主要介绍了matplotlib绘图对象中fig和axes的差别,能够这样理解,fig是画板,而axes是画板上的图形,一个fig中能够包含多个axes,而axes才是控制绘图的关键。
其次经过几种经常使用图形的绘制,介绍了matplotlib绘图过程当中大部分的经常使用操做。
以上全部图形的绘制均使用了同一种方式,即利用axes来进行绘图,主要有两个缘由,其一,这样写的代码可读性比较好,比较容易修改(至少我的认为是这样的)。其二,这种方式能够实现对图表的任意部件进行自定义的修改。
我虽然都使用了axes来绘图,而且也推荐使用这种方式来进行绘图。但并不意味着你也要使用这种方式,若是只是绘制一些示意图,对图形并无太多控制,其实plt.plot()可能更方便,这也是matplotlib默认的方式。
https://matplotlib.org/tutori...
https://matplotlib.org/1.5.1/...
https://zhuanlan.zhihu.com/p/...
https://matplotlib.org/3.1.3/...