Python—Matplotlib基础学习

简介

使用指南

导入
import matplotlib.pyplot as plt
import numpy as np     #matplotlib常与numpy库搭配使用

在这里举个简单的例子:

 用坐标轴创建图形最简单的方法是使用pyplot.subplots。我们可以用 Axes.plot绘制坐标轴上的一些数据:

fig,ax = plt.subplots()       #创建一个包含单个坐标轴的图形。
ax.plot([1,2,3,4],[1,4,2,3])  #在坐标轴上绘制一些数据

Figure的组成



Pyplot教程

pyplot简介

matplotlib.pyplot是使matplotlib像MATLAB一样工作的函数的集合。每个pyplot功能都会对图形进行一些更改:例如,创建图形,在图形中创建绘图区域,在绘图区域中绘制一些线条,用标签装饰绘图等。

使用pyplot生成可视化的效果非常快:

plt.plot([1,2,3,4])
plt.ylabel('num')
plt.show()

关于上面这个示例中,x轴范围0-3,y轴范围1-4,原因是如果你向Plot传递单个列表或数组,那么matplotlib假定它是y轴的序列,并自动为你生成从0开始的x值


plot的样式

对于每对x,y参数,都有一个可选的第三个参数,它是表示图的颜色和线型的格式字符串。格式字符串的字母和符号来自MATLAB,您将颜色字符串与线型字符串连接在一起。默认格式字符串是“ b-”,这是一条蓝色实线。

例如,要用红色圆圈绘制以上内容:

plt.plot([1,2,3,4],[1,4,9,16],'ro') #'r':red,'o':点
plt.axis([0,6,0,20])                #确定坐标轴的范围,x轴0-6,y轴0-20
plt.show()

格式字符串由颜色,标记物和线条组成

fmt = '[marker][line][color]'  #其他组合也是允许的,例如[color][marker][line]

每一个参数都是可选的。

Markers(标记物)

字符 描述
'.' 点标记
',' 像素标记
'o' 圆圈标记
'v' triangle_down标记
'^' 三角形标记
'<' triangle_left标记
'>' triangle_right标记
'1' tri_down标记
'2' tri_up标记
'3' tri_left标记
'4' tri_right标记
's' 方形标记
'p' 五边形标记
'*' 星标
'h' 六角形标记
'H' 六角标记
'+' 加号
'x' X标记
'D' 钻石笔
'd' thin_diamond标记
`' '`
'_' 标记线

line(线形)

字符 描述
'-' 实线样式
'--' 虚线样式
'-.' 点划线样式
':' 虚线样式

color(颜色)

字符 颜色
'b' 蓝色
'g' 绿色
'r'
'c' 青色
'm' 品红
'y' 黄色
'k' 黑色
'w' 白色

如何参数中只有颜色这一选择项,则可以使用任何matplotlib.colors规格,例如全名(‘green')或十六进制表示('#008000')


处理多个图形和轴

在下面这个例子中一个figure下创建了两个子图:

import matplotlib.pyplot as plt
import numpy as np


def f(t):
    return np.exp(-t) * np.cos(2*np.pi*t)

t1 = np.arange(0.0, 5.0, 0.1)
t2 = np.arange(0.0, 5.0, 0.02)

plt.figure()
plt.subplot(211)  #211:   2行1列的第一个子图
plt.plot(t1, f(t1), 'bo', t2, f(t2), 'k')   #在其一子图上绘制了两个图形

plt.subplot(212)   #212:   2行1列的第二个子图
plt.plot(t2, np.cos(2*np.pi*t2), 'r--')   
plt.show()

同样:可以创建多个figure

plt.figure(1)                # 第一个图形
plt.subplot(211)             # 第一个图形中的第一个子图
plt.plot([1, 2, 3])
plt.subplot(212)             # 第一个图形中的第二个子图
plt.plot([4, 5, 6])


plt.figure(2)                # 第二个图形
plt.plot([4, 5, 6])          # 默认创建一个 subplot(111)

plt.figure(1)             # 此时figure(1)仍然存在,并且此时subplot(212)是figure(1)当前使用
plt.subplot(211)          # 使得subplot(211)是figure(1)当前使用
plt.title('Easy as 1, 2, 3') # 声明subplot(211)的标题

plt.show()

为图形添加文字说明

annotate方法提供了注释方式

参数:xy表示注释的位置,xytext是文本的位置。这两个参数都是(x,y)元组

ax = plt.subplot(111)

t = np.arange(0.0, 5.0, 0.01)
s = np.cos(2*np.pi*t)
line, = plt.plot(t, s, lw=2)

plt.annotate('local max', xy=(2, 1), xytext=(3, 1.5),
             arrowprops=dict(facecolor='black', shrink=0.05),
             )

plt.ylim(-2, 2)		#规定y值范围(-2,2)
plt.show()

更多详细注释请参见官方文档基本注释高级注释




图片教程

利用matplotlib处理图片

导入

import matplotlib.pyplot as plt
import matplotlib.image as mpimg

将图像数据导入到NumPy数组

这是我们要处理的图片:

让我们打开并输出它:

img = mpimg.imread('C:\\Users\\wangz\\Desktop\\Pic.png') #图片路径
print(img)

将NumPy数组绘制成图像

imshow()函数将numpy数组中的数据渲染成图像。

imgplot = plt.imshow(img)

伪彩色应用于图像

伪彩色是增强对比度和更轻松地可视化数据的有用工具。

伪彩色仅与单通道,灰度,发光度图像有关。我们目前有一个RGB图像。由于R,G和B都是相似的(请参见上方或数据中的内容),我们可以选择一个数据通道:

lum_img = img[:,:,0]   #数组切片,更多相关切片请看个人博客关于NumPy学习
plt.imshow(lum_img)

同样,对于亮度图像,将应用默认的颜色图(又名查找表:LUT)。默认名称为viridis,也有其他可供选择:

plt.imshow(lum_img,cmap="hot")    #暖色调显示

image-20201120212946492

您还可以使用set_cmap()方法更改现有打印对象上的颜色图

imgplot = plt.imshow(lum_img)
imgplot.set_cmap('nipy_spectral')

可以通过添加颜色条来了解颜色代表什么价值,可通过matplotlib.pyplot.colorbar()函数实现

imgplot = plt.imshow(lum_img)
plt.colorbar()

如果你想增强图像的对比度,或扩大特定区域的对比度,同时牺牲颜色变化不大或无关紧要的细节。直方图是个好工具。要创建图像数据的直方图,我们使用hist()函数。

plt.hist(lum_img.ravel(),bins=256,range=(0.0,1.0),fc='k',ec='k')

在获取图像的主要的区域[0.0,0.7]后 (如直方图所示),

我们可以通过传递clim参数或者调用set_clim()方法修改图像对比度

imgplot = plt.imshow(lum_img,clim=(0.0,0.7))



Artist教程

使用Artist对象在画布上渲染

matplotlib API有三层。

  • matplotlib.backend_bases.FigureCanvas是图形被绘制到的区域

  • matplotlib.backend_bases.Renderer是知道如何在FigureCanvas上绘制的对象

  • matplotlib.artist.Artist是知道如何使用渲染器在画布上作画的对象。

FigureCanvas和Renderer处理与用户界面工具包(如wxPython)或绘图语言(如PostScript®)对话的所有细节,而Artist处理所有高层构造,如表示和布局图形、文本和线条。


引言

​ 有两种类型的Artist: primitives和containers。

​ primitives代表了我们想要在画布上绘制的标准图形对象:Line2D, Rectangle, Text, AxesImage等;

​ containers是放置它们的地方 (Axis, Axes and Figure)。


​ 标准用法是创建一个Figure实例,使用Figure创建一个或多个轴或子图实例,并使用Axes实例方法创建primitives。

在下面的示例中,我们使用matplotlib.pyplot.figure()创建一个Figure实例.

fig = plt.figure()
ax = fig.add_subplot(2,1,1)

如果要在任意位置创建Axes,只需使用add_axes()方法

参数:[left,bottom,width,height]

fig2 = plt.figure()
ax2 = fig2.add_axes([0,0,0.7,0.3])
ax3 = fig2.add_axes([1,1,0.7,0.3])



自定义对象

每个matplotlib的Artist对象具有以下属性

属性 描述
alpha 透明度 - 范围0-1
animated 用于促进动画绘制的布尔值
axes Artist对象存在的轴,可能没有
clip_box 剪辑Artist的边界框
clip_on 是否开启剪辑
clip_path Artist被剪辑的路径
contains 一个选择函数,用于测试Artist是否包含选择的点
figure Artist存在的figure示例,可能没有
label 文本标签(例如:用于自动标签)
picker 控制对象选择的python对象
transform 转换
visible 是否应该绘制Artist的布尔值
zorder 决定绘图顺序的数字
rasterized 布尔值;将向量转换为光栅图形 (用于压缩和eps透明度)

每个属性都可以通过老式的setter或getter访问。

例如,将当前的alpha乘以一半:

a = o.get_alpha()
o.set_alpha(0.5*a)

如果要一次设置多个属性,则还可以将set方法与关键字参数一起使用

例如:

o.set(alpha=0.5,zorder=2)

如果你是在python shell上进行交互工作,检查Artist属性的便捷方法是使用matplotlib.artist.getp()函数

该函数列出了属性及其值。

这也适用于从Artist派生的类,例如Figure和Rectangle。

对于创建的figure对象,使用上述命令:

#可以自己创建一个figure实例查看
matplotlib.artist.getp(fig.patch)
#结果
agg_filter = None
    alpha = None
    animated = False
    antialiased or aa = False
    bbox = Bbox(x0=0.0, y0=0.0, x1=1.0, y1=1.0)
    capstyle = butt
    children = []
    clip_box = None
    clip_on = True
    clip_path = None
    contains = None
    data_transform = BboxTransformTo(     TransformedBbox(         Bbox...
    edgecolor or ec = (1.0, 1.0, 1.0, 0.0)
    extents = Bbox(x0=0.0, y0=0.0, x1=432.0, y1=288.0)
    facecolor or fc = (1.0, 1.0, 1.0, 0.0)
    figure = Figure(432x288)
    fill = True
    gid = None
    hatch = None
    height = 1
    in_layout = False
    joinstyle = miter
    label = 
    linestyle or ls = solid
    linewidth or lw = 0.0
    patch_transform = CompositeGenericTransform(     BboxTransformTo(   ...
    path = Path(array([[0., 0.],        [1., 0.],        [1.,...
    path_effects = []
    picker = None
    rasterized = None
    sketch_params = None
    snap = None
    transform = CompositeGenericTransform(     CompositeGenericTra...
    transformed_clip_path_and_affine = (None, None)
    url = None
    verts = [[  0.   0.]  [432.   0.]  [432. 288.]  [  0. 288....
    visible = True
    width = 1
    window_extent = Bbox(x0=0.0, y0=0.0, x1=432.0, y1=288.0)
    x = 0
    xy = (0, 0)
    y = 0
    zorder = 1

更多关于给定对象的属性列表可查看 matplotlib.artist

对象容器

 既然我们知道了如何检查和设置要配置的给定对象的属性,那么我们需要知道如何获取该对象。

 在本节中,我们将回顾各种容器对象存储您想要获取的Artist的位置。


Figure容器

顶层容器Artist是matplotlib.figure.Figure,它包含图中的所有内容。图形的背景是一个矩形,存储在figure .patch中。

当你在途中添加子图(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])#添加一个新轴,参数分别是[left,bottom,width,height]

ax1

print(fig.axes)

由于该图保留了“当前轴”(请参见Figure.gcaFigure.sca)的概念 以支持pylab / pyplot状态机,66因此您不应直接从轴列表中插入或删除轴,而应使用 add_subplot()add_axes()方法插入,以及 delaxes()方法删除。但是,您可以自由地遍历轴列表或对其进行索引以访问Axes要自定义的实例。

这是一个打开所有轴网格的示例:

for ax in fig.axes:
    ax.grid(True)

图形还有自己的文本、线条、形状和图像,您可以使用它们直接添加primitives。图形的默认坐标系统将简单地以像素为单位(这通常不是你想要的),但是你可以通过设置你添加到图形中的Artist的transform属性来控制它。

更有用的是“图形坐标”,其中(0,0)是图形的左下角,而(1,1)是图形的右上角,可以通过将Artist变换设置为来获得fig.transFigure

import matplotlib.lines as lines

fig = plt.figure()

l1 = lines.Line2D([0, 1], [0, 1], transform=fig.transFigure, figure=fig)
l2 = lines.Line2D([0, 1], [1, 0], transform=fig.transFigure, figure=fig)
fig.lines.extend([l1, l2])

plt.show()

下面是该图包含的Artist的摘要

图形属性 描述
axes 轴的实例 (包括子图)
patch 矩形背景
images 图形图像形状列表-有用的原始像素显示
legends 图像图例(和Axes.legends不同)
lines 图像Line2D实例(很少使用,看Axes.lines)
patches 图像的形状(很少使用,看 Axes.patches)
texts 图像文本

Axes容器

 matplotlib.axes.Axes是matplotlib的中心——它包含图形中使用的绝大多数美工,以及用于创建和添加这些美工到自身的许多辅助方法,以及用于访问和定制其中包含的美工的辅助方法。

 和图一样,它包含了一个 Patch,在笛卡尔坐标系中是一个矩形,在极坐标中是一个圆;这个patch决定了作图区域的形状、背景和边界:

ax = fig.add_subplot(111)
rect = ax.patch  # 一个矩形实例
rect.set_facecolor('green')   #设置背景颜色为绿色

当你调用绘图方法,例如规范化 plot()并且传入数组或列表的值为参数时,该方法将创建一个matplotlib.lines.Line2D()实例,使用作为关键字参数传递的所有Line2D属性更新该line,并将该line添加到Axes.lines容器,并返回给您:

x,y = np.random.rand(2,100)
line,=ax.plot(x,y,'-',color='blue',linewidth=2)

plot返回的是一个lines列表,因为你可以传入多个x,y来绘制。

例如:

print(ax.lines)

同样,创建patches的方法,像bar()创建了矩阵列表,会添加patches到Axes.patches列表中

fig = plt.figure()
ax = fig.add_subplot(111)
n,bins,rectangles = ax.hist(np.random.randn(1000),50)
print(rectangles)
print(len(ax.patches))

有很多axis辅助方法用于创建primitive Artists并将它们添加到各自的容器中。

下面的表格总结了他们的一个小样例,他们创造的Artist类型,以及把他们储存在哪里

Helper method Artist Container
ax.annotate - text annotations Annotate(注释) ax.texts
ax.bar - bar charts Rectangle ax.patches
ax.errorbar - error bar plots Line2D and Rectangle ax.lines and ax.patches
ax.fill - shared area Polygon(多边形) ax.patches
ax.hist - histograms Rectangle ax.patches
ax.imshow - image data AxesImage ax.images
ax.legend - axes legends Legend(图例) ax.legends
ax.plot - xy plots Line2D ax.lines
ax.scatter - scatter charts PolygonCollection (多边形集合) ax.collections
ax.text - text Text ax.texts

下面这个是Axes容器的Artist对象的概括:

Axes attribute Description
artists Artist 实例的列表
patch Axes的背景的矩阵实例的列表
collections 集合实例的列表
images 轴图像的列表
legends 图例实例的列表
lines Line2D实例的列表
patches Patch实例列表
texts 文本实例列表
xaxis matplotlib.axis.XAxis实例
yaxis matplotlib.axis.YAxis实例

Axis容器

matplotlib.axis.Axis实例处理刻度线、网格线、刻度标签和axis标签的绘制。

每个Axis对象包含一个label属性(这是pyplot在调用xlabel和ylabel时修改的内容)以及一个主刻度和次要刻度列表。这些刻度是axis.XTickaxis.YTick的实例,其中包含呈现刻度和刻度标签的actual line和文本primitives。

​ 因为刻度是根据需要动态创建的(例如,在移动和缩放时),所以应该通过它们的accessor方法axis.Axis.get_major_ticks and axis.Axis.get_minor_ticks访问主要刻度和次要刻度的列表。尽管刻度包含了所有的primitives,并且将在下面覆盖,Axis实例有accessor方法返回刻度行,刻度标签,刻度位置等:

fig,ax = plt.subplots()
axis = ax.xaxis
axis.get_ticklocs()
axis.get_ticklabels()

请注意,刻度线是标签的两倍,因为默认情况下,顶部和底部有刻度线,但x轴下方仅是刻度线;但是,可以自定义。

axis.get_ticklines()

以下是的一些有用的Axis的accessor方法的摘要 (这些访问器有相应的setters,例如 set_major_formatter()

Accessor 方法 描述
get_scale axis的比例:如“对数”或“线性”
get_view_interval The interval instance of the axis view limits
get_data_interval The interval instance of the axis data limits
get_gridlines 用于轴的网格线列表
get_label 轴的标签 -文本实例
get_ticklabels 一个文本实例列表-keyword minor=True|False
get_ticklines Line2D实例列表- keyword minor=True|False
get_ticklocs 刻度位置- keyword minor=True|False
get_major_locator 主要刻度的 ticker.Locator 实例
get_major_formatter 主要刻度的 ticker.Formatter实例
get_minor_locator 次要刻度的 ticker.Locator 实例
get_minor_formatter 次要刻度的ticker.Formatter实例
get_major_ticks 主要刻度的实例列表
get_minor_ticks 次要刻度的实例列表
grid 为主要刻度或次要刻度打开或关闭网格

举个栗子

可以自定义轴和刻度属性

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是一个文本实例
    label.set_color('red')
    label.set_rotation(45)
    label.set_fontsize(16)
    
for line in ax1.yaxis.get_ticklines():
	#line是一个Line2D实例
    line.set_color('green')
    line.set_markersize(25)
    line.set_markeredgewidth(3)

plt.show()

Tick容器

matplotlib.axis.Tick 是从FigureAxes 再到 Axis 最后到 Tick 的容器对象。

Tick包含了刻度和网格线,以及上下刻度的标签实例。

这些中的每一个都可以作为Tick的属性直接访问

Tick属性 描述
tick1line Line2D 实例
tick2line Line2D 实例
gridline Line2D 实例
label1 文本实例
label2 文本实例

举个栗子

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

np.random.seed(19680801)

fig, ax = plt.subplots()
ax.plot(100*np.random.rand(20))


ax.yaxis.set_major_formatter(ticker.FormatStrFormatter('%0.2f'))

ax.yaxis.set_tick_params(which='major', labelcolor='green',
                         labelleft=False, labelright=True)

plt.show()



图例指南

 在Matplotlib中灵活地生成图例

 在阅读这一章节前请熟悉关于 legend()的讲解

一些常用用语:

  • 图例条目

图例由一个或多个图例条目组成。一项仅由一个键和一个标签组成。

  • 图例键

每个图例标签左侧的彩色/图案标记。

  • 图例标签

描述键所代表的文本。

  • 图例句柄

用于在图例中生成适当条目的原始对象。

(也不知道这样子翻译的对不对,先放一下英文版,等明白了再回来改)

  • legend entry

    A legend is made up of one or more legend entries. An entry is made up of exactly one key and one label.

  • legend key

    The colored/patterned marker to the left of each legend label.

  • legend label

    The text which describes the handle represented by the key.

  • legend handle

    The original object which is used to generate an appropriate entry in the legend.


控制图例条目

调用无参的legend()会自动获取图例handles和它们的关联标签

这个功能等效于:

#等效于ax.legend()
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles, labels)

get_legend_handles_labels()函数返回存在于轴上的handles或artists,可用于生成结果图例的条目——(要注意的是,并非所有的Artist都可以添加到图例中,这种情况下“proxy(代理)”就需要创建)

带有空字符串作为标签或标签以“ _”开头的artists将被忽略。

要完全控制添加到图例中的内容,通常可以将适当的handles直接传递给legend():

line_up, = plt.plot([1,2,3],label='Line 2')
line_down, = plt.plot([3,2,1],label='Line 1')
plt.legend(handles=[line_up,line_down])

在某些情况下,无法设置handles的标签,因此可以将标签列表传递给legend():

line_up, = plt.plot([1,2,3],label='Line 2')
line_down, = plt.plot([3,2,1],label='Line 1')
plt.legend([line_up,line_down],['Line Up','Line Down'])

创建专门用于添加图例的Artist(又名代理艺术家)

并不是所有的handles都能自动转换为图例条目,所以总是有必要创建一个artist。图例handles不必存在于图形或轴上才能使用。

import matplotlib.patches as mpatches

red_patch = mpatches.Patch(color='red',label='The red data')
plt.legend(handles=[red_patch])
plt.show()

有许多受支持的图例handles。除了创建颜色patch之外,我们还可以创建带有标记的线:

import matplotlib.lines as mlines

blue_line = mlines.Line2D([],[],color='blue',marker='*',markersize=15,label='Blue Star')
plt.legend(handles=[blue_line])
plt.show()

图例位置

图例的位置可以通过关键字loc来指定。请在官方文档legend()查看更多细节

bbox_to_anchor关键字为手动图例的位置提供了很大程度的控制。

例如,如果你想让坐标轴图例位于图形的右上角而不是坐标轴的角落,只需指定角落的位置和该位置的坐标系统:

plt.plot([1,2,3],[3,2,1],label='Line')
#plt.gcf().transFigure获取当前figure
plt.legend(bbox_to_anchor=(1, 1),
           bbox_transform=plt.gcf().transFigure)

更多自定义图例放置的例子:

plt.subplot(211)
plt.plot([1,2,3],label="Line 1")
plt.plot([3,2,1],label="Line 2")
plt.legend(bbox_to_anchor=(0.,1.02,1.,.102),loc='lower left',ncol=2,mode="expand",borderaxespad=0.)

plt.subplot(223)
plt.plot([1,2,3],label="Line 1")
plt.plot([3,2,1],label="Line 2")
plt.legend(bbox_to_anchor=(1.05,1),loc='upper left',borderaxespad=0.)

plt.show()

同一个Axes下多个图例

手动将图例添加到当前Axes下:

line1, = plt.plot([1,2,3],label="Line 1",linestyle='--')
line2, = plt.plot([3,2,1],label="Line 2",linewidth=5)
#为第一条线创建图例
first_legend = plt.legend(handles=[line1],loc='upper right')
#将first_legend手动地添加到当前Axes
ax = plt.gca().add_artist(first_legend)
#为第二条线创建图例
plt.legend(handles=[line2],loc='lower right')

plt.show()

图例Handlers

为了创建图例条目,handles被作为参数提供给适当的HandlerBase子类。

使用自定义Handlers的最简单示例是实例化一个现有的legend_handler.HandlerBase的子类。

为了简单起见,我们选择legend_handler.HandlerLine2D,它接受numpoints参数(numpoints也是legend()函数上的一个关键字)。

然后,我们可以将实例到Handler的映射作为关键字传递给legend。

from matplotlib.legend_handler import HandlerLine2D

line1, = plt.plot([3,2,1],marker='o',label='Line 1')
line2, = plt.plot([1,2,3],marker='o',label='Line 2')

plt.legend(handler_map={line1: HandlerLine2D(numpoints=3)})

除了用于errorbar、stem plot和histograms等复杂图形类型的Handlers外,默认的handler_map还有一个特殊的元组handler(legend_handler.HandlerTuple),它简单地为给定元组中的每个项绘制一个又一个的handles。

下面的例子演示了将两个图例键组合在一起:

from numpy.random import randn

z = randn(10)

red_dot, = plt.plot(z, "ro", markersize=15)
# 白色十字图案放在前五个数据上显示
white_cross, = plt.plot(z[:5], "w+", markeredgewidth=3, markersize=15)

plt.legend([red_dot, (red_dot, white_cross)], ["Attr A", "Attr A+B"])

legend_handler.HandlerTuple 类也可以用来为同一个条目分配几个图例键:

from matplotlib.legend_handler import HandlerLine2D, HandlerTuple

p1, = plt.plot([1, 2.5, 3], 'r-d')
p2, = plt.plot([3, 2, 1], 'k-o')

l = plt.legend([(p1, p2)], ['Two keys'], numpoints=1,
               handler_map={tuple: HandlerTuple(ndivide=None)})

实现自定义的图例handler

可以实现自定义handler来将任何handle转换为图例键(handles不一定需要是matplotlib artists对象)。

handler必须实现一个legend_artist方法,该方法为图例返回一个artist对象来使用。

legend_artist所需的签名,记录在legend_artist中。

import matplotlib.patches as mpatches


class AnyObject:
    pass


class AnyObjectHandler:
    def legend_artist(self, legend, orig_handle, fontsize, handlebox):
        x0, y0 = handlebox.xdescent, handlebox.ydescent
        width, height = handlebox.width, handlebox.height
        patch = mpatches.Rectangle([x0, y0], width, height, facecolor='red',
                                   edgecolor='black', hatch='xx', lw=3,
                                   transform=handlebox.get_transform())
        handlebox.add_artist(patch)
        return patch


plt.legend([AnyObject()], ['My first handler'],
           handler_map={AnyObject: AnyObjectHandler()})

或者,如果我们想要全局地接受AnyObject实例,而不需要一直手动设置handler_map关键字,我们可以用:

from matplotlib.legend import Legend
Legend.update_default_handler_map({AnyObject: AnyObjectHandler()})

虽然这里的功能很明显,但请记住,已经实现了许多handlers,并且您想要实现的可能已经很容易地通过现有的类实现了。

例如,产生椭圆的图例键,而不是矩形的:

from matplotlib.legend_handler import HandlerPatch


class HandlerEllipse(HandlerPatch):
    def create_artists(self, legend, orig_handle,
                       xdescent, ydescent, width, height, fontsize, trans):
        center = 0.5 * width - 0.5 * xdescent, 0.5 * height - 0.5 * ydescent
        p = mpatches.Ellipse(xy=center, width=width + xdescent,
                             height=height + ydescent)
        self.update_prop(p, orig_handle, legend)
        p.set_transform(trans)
        return [p]


c = mpatches.Circle((0.5, 0.5), 0.25, facecolor="green",
                    edgecolor="red", linewidth=3)
plt.gca().add_patch(c)

plt.legend([c], ["An ellipse, not a rectangle"],
           handler_map={mpatches.Circle: HandlerEllipse()})



使用GridSpec和其他函数自定义图形布局

  以下函数或方法实现创建axes上的网格的组合

  或许是创建figures和axes最主要的方式,与 matplotlib.pyplot.subplot() 类似,
但是同时创建并放置图形上的所有轴。更多详情请看matplotlib.figure.Figure.subplots.

  指定将放置子图的网格的几何形状。

  需要设置网格的行数和列数。以及子图的布局参数可以调整

  在给定的GridSpec上指定子图的位置

  一个类似于subplot() 的辅助函数,但是使用基于0的索引并让subplot占用多个单元格。本文章没有介绍该函数。


导入

import matplotlib
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec



快速入门指南

使用subplots()非常简单。它返回一个Figure实例和一个Axes对象数组 。

fig1,f1_axes = plt.subplots(ncols=2,nrows=2,constrained_layout=True)

对于像上面这样的简单用例,gridspec可能过于冗长。

你必须分别创建图形和GridSpec 实例,然后将gridspec实例的元素传递给 add_subplot() 函数来创建axes对象。

gridspec元素的访问方式通常与numpy数组相同。

fig2 = plt.figure(constrained_layout=True)
spec2 = gridspec.GridSpec(ncols=2,nrows=2,figure=fig2)
f2_ax1 = fig2.add_subplot(spec2[0,0])
f2_ax2 = fig2.add_subplot(spec2[0,1])
f2_ax3 = fig2.add_subplot(spec2[1,0])
f2_ax4 = fig2.add_subplot(spec2[1,1])

可以看出和subplots()方式结果相同

gridspec的强大之处在于能够创建跨越行和列的子图。注意,NumPy slice Syntax 用于选择每个子图将占据的gridspec部分。

请注意,我们还使用了便捷方法Figure.add_gridspec 代替gridspec.GridSpec,有可能为用户节省了导入时间,并使名称空间更整洁。

fig3 = plt.figure(constrained_layout=True)
gs = fig3.add_gridspec(3,3)

#关于切片可参考另一篇文章Numpy学习中的切片学习
f3_ax1 = fig3.add_subplot(gs[0,:])
f3_ax1.set_title('gs[0,:]')
f3_ax1 = fig3.add_subplot(gs[1,:-1])
f3_ax1.set_title('gs[1,:-1]')
f3_ax1 = fig3.add_subplot(gs[1:,-1])
f3_ax1.set_title('gs[1:,-1]')
f3_ax1 = fig3.add_subplot(gs[-1,0])
f3_ax1.set_title('gs[-1,0]')
f3_ax1 = fig3.add_subplot(gs[-1,-2])
f3_ax1.set_title('gs[-1,-2]')

接下来展示的方法与上面的方法类似,

初始化统一的网格规范,然后使用numpy索引和切片为给定的子图分配多个“单元格”。

fig4 = plt.figure(constrained_layout=True)
spec4 = fig4.add_gridspec(ncols=2,nrows=2)
anno_opts = dict(xy=(0.5,0.5),xycoords='axes fraction',va='center',ha='center')

f4_ax1 = fig4.add_subplot(spec4[0,0])
f4_ax1.annotate('GridSpec[0,0]',**anno_opts)
fig4.add_subplot(spec4[0, 1]).annotate('GridSpec[0, 1:]', **anno_opts)
fig4.add_subplot(spec4[1, 0]).annotate('GridSpec[1:, 0]', **anno_opts)
fig4.add_subplot(spec4[1, 1]).annotate('GridSpec[1:, 1:]', **anno_opts)

  另一个方式是使用width_ratios和height_ratios参数。这些关键字参数是数字列表。

  请注意,绝对值是没有意义的,只有它们的相对比率重要。这意味着width_ratio =[2, 4, 8]与width_ratio =[1, 2, 4]在同样宽的数字内相等。

fig5 = plt.figure(constrained_layout=True)
widths = [2,3,1.5]
heights = [1,3,2]
spec5 = fig5.add_gridspec(ncols=3,nrows=3,width_ratios=widths,height_ratios=heights)

for row in range(3):
    for col in range(3):
        ax = fig5.add_subplot(spec5[row,col])
        label = 'Width: {}\nHeight: {}'.format(widths[col],heights[row])
        ax.annotate(label,(0.1,0.5),xycoords='axes fraction',va='center')

 学习使用width_ratio和height_ratio特别有用,因为函数subplots()在gridspec_kw参数中接受它们。

 为此,GridSpec 接受的任何参数都可以通过gridspec_kw参数传递给subplots()

 此示例在不直接使用gridspec实例的情况下重新创建前面的图。

gs_kw = dict(width_ratios=widths,height_ratios=heights)
fig6,f6_axes = plt.subplots(ncols=3,nrows=3,constrained_layout=True,gridspec_kw=gs_kw)

for r,row in enumerate(f6_axes):
    for c,ax in enumerate(row):
        label = 'Width:{}\nHeight:{}'.format(widths[c],heights[r])
        ax.annotate(label,(0.1,0.5),xycoords='axes fraction',va='center')

subplots和get_gridspec方法可以组合使用,因为有时使用subplots创建大多数子图,然后删除其中一些并组合它们更方便。

在这里,我们将最后一列中底部的两个轴组合起来创建一个布局。

fig7,f7_axs = plt.subplots(ncols=3,nrows=3)
gs = f7_axs[1,2].get_gridspec()

#删除[1,-1],[2,-1]的axes
for ax in f7_axs[1:,-1]:
    ax.remove()
axbig = fig7.add_subplot(gs[1:,-1])    
axbig.annotate('Big Axes \nGridSpec[1:, -1]', (0.1, 0.5),
               xycoords='axes fraction', va='center')

#调整子图之间及其周围的填充。
fig7.tight_layout()



精细调整Gridspec布局

当显示地使用GridSpec时,可以通过改变gridspec的参数来调整子图的布局

请注意,此选项与constrained_layout或者 Figure.tight_layout 都不兼容,两者都通过调整子图大小以填充figure。

参数请看:matplotlib.gridspec.GridSpec

fig8 = plt.figure(constrained_layout=False)
gs1 = fig8.add_gridspec(nrows=3,ncols=3,left=0.05,right=0.48,wspace=0.05)
f8_ax1 = fig8.add_subplot(gs1[:-1,:])
f8_ax2 = fig8.add_subplot(gs1[-1,:-1])
f8_ax3 = fig8.add_subplot(gs1[-1,-1])



GridSpec之SubplotSpec

你可以通过SubplotSpec 创建GridSpec,在这种情况下,它的布局参数被设置为给定SubplotSpec的位置。

fig10 = plt.figure(constrained_layout=False)
gs0 = fig10.add_gridspec(1,2)

gs00 = gs0[0].subgridspec(2,3)
gs01 = gs0[1].subgridspec(3,2)

for i in range(2):
    for j in range(3):
        fig10.add_subplot(gs00[i,j])
        fig10.add_subplot(gs01[j,i])



文章翻译自官方文档
如果你发现文章中出现的错误或者任何疑问欢迎在下方评论区评论


利益相关
更多资源关注公众号“北方向北”(扫描右侧二维码也可关注)
点个大拇指支持支持,感谢

posted @ 2021-01-24 20:08  云北海  阅读(449)  评论(0编辑  收藏  举报