Python 可视化与图像处理
python绘图库有很多,底层的就是matplotlib,另外还有基于matplotlib的更方便,代码可读性更强的库,比如seaborn、plotnine等。各个库之间的对比:
https://www.zhihu.com/question/39684179
matplotlib
在python下一般使用matplotlib包下的pyplot,所以通常import matplotlib.pyplot as plt方便使用它的绘图函数。下面仅记录matplotlib3.2.0之后的版本。
通用函数
plt.show()
显示绘图窗口。
plt.figure()
创建绘图新窗口并传给fig:
fig = plt.figure()
fig能使用下面绘图、创建子图等函数。不创建新窗口直接plt.function()也能绘图,默认一个窗口。
fig.add_subplot()
给窗口添加子图像,参数有三个,分别是子图像的行、列、索引。两种使用方式:
ax = fig.add_subplot(numbRow, numbCol, plotNum)
ax = fig.add_subplot(111)
前一种是一般的用逗号隔开,明确三个参数。后一种是三个整数参数直接合成一个整数传入,这要求这个整数只能是3位的,这样才能唯一确定用户传入的参数。(比如223,就是把图像划分成2*2的格子,添加一个子图像在第三个格子里)
fig.subplots()
同时创建窗口和多个子图像的方法,用法如下:
import matplotlib.pyplot as plt fig, axs = plt.subplots(2,2) axs[0,0].plot([0,1],[0,1]) plt.show()
fig为创建的窗口对象,axs为多个子图对象的二维数组,因此可以通过索引获取子图对象。
plt.imsave()
用于保存图像,因为源代码中没有提示,很容易因为传参顺序而出错。用法如下:
plt.imsave(name,img)#先传名字再传img数组
图例
为图像添加图例,在画图函数中添加label属性就行。如:
ax.plot(X,Y,label = '图例')
然后使用legend()函数显示所有的图例,它可以设置图例的位置等参数:
ax.legend(loc='best') #看这个介绍https://blog.csdn.net/qq_35240640/article/details/89478439
显示中文(不然可能乱码):
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签 plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
图像标题
ax.set_title('aaa',fontsize=12,color='r')
坐标轴设置
坐标轴一般设置
ax.set_xlim([-2, 2])#设置x坐标轴范围 ax.set_ylim([-2, 2])#设置y坐标轴范围 ax.set_xlabel('xxxxxxxxxxx')#设置x坐标轴名称 ax.set_ylabel('yyyyyyyyyyy')#设置y坐标轴名称 ticks = np.arange(-2, 2, 0.3) ax.set_xticks(ticks)#设置x轴刻度 ax.set_yticks(ticks)#设置y轴刻度 ax.axis('scaled')#设置坐标轴宽高等比于x、y范围 ax.axis('image')#类似于scaled,暂时没发现区别 ax.axis('off')#关闭坐标轴 ax.axis('equal')#图像宽高比例不变,坐标轴范围变 ax.axis('tight')#坐标轴紧紧贴合图像,不设置默认就是这个 ax.axis('square')#设置坐标轴宽高比为1:1,坐标轴跨度取较大的那个 ax.spines['right'].set_color('none') #包含'top','bottom','right','left'4个轴。这里设置右边轴消失 ax.spines['left'].set_position(('data',0)) #将左边的轴移动到与横坐标0处对齐 ax.spines['bottom'].set_position(('data',0)) #将下面的轴移动到与纵坐标0处对齐
变换坐标轴位置(除了使用上述的spines外),给坐标轴加箭头等
import mpl_toolkits.axisartist as axisartist fig = plt.figure() ax = axisartist.Subplot(fig, 1,1,1) fig.add_axes(ax) #使用这两句定义ax而不是add_subplot ax.axis[:].set_visible(False) #隐藏'top','bottom','left','right','x','y'六个坐标轴 ax.axis["x"] = ax.new_floating_axis(0, 0) #定义新的坐标轴给x轴,第一个0表示x方向,第二个0表示x轴处于y轴的0位置 ax.axis["y"] = ax.new_floating_axis(1, 0) #定义新的坐标轴给y轴,第一个1表示y方向,第二个0表示y轴处于x轴的0位置 ax.axis["x"].set_axisline_style("->", size = 1)#设置x轴的风格,使用箭头 ax.axis["y"].set_axisline_style("->", size = 1)
动态图像
plt.cla()
ax.clear()
这两个函数用于将子图清空,配合暂停函数
plt.pause(0.1)
即可实现动态图像。
二维图像
contourf()和contour()
画等高线图。这两个函数差一个字母,但用法一样,区别如下:
使用方法:
ax.contourf(X, Y, Z, levels=10, alpha=0.5, cmap='jet')
X是生成网格的X坐标数组(二维数组array,或者matrix),Y是和X相同类型的Y坐标,Z是对应网格的每个格点的函数值数组(也是二维数组array,或者matrix),网格的生成是使用numpy库中的meshgrid()函数。levels是图像中等高线的数量,我这里设置为10。alpha是图像的透明度,介于0~1,我这里设置为0.5半透明。可以设置透明度有个好处就是可以把很多图画在同一个画布上,方便比较。cmap是图像的颜色类型,有很多预设的颜色类型,我这里用一个叫‘jet’的颜色类型,当然也可以自己定义,具体设置网上再找吧。后三项有预设值,可以省略。
效果图:
看起来不是很圆润,这是因为我的网格规模就是7*7的,它画图就按照你的网格数量来画,所以有棱有角的。有一点奇怪的就是,网格是有限的,它是怎么画出这么多的等高线的?我猜它应该是线性插值插进去的。反正也就一个图用来看的,不用特别准确。但是如果要准确怎么办?那就把网格设置地密一些!别让等高线的密度比网格的密度大太多就好了。
另外,可以用clabel()这个函数用来标注等高线图的数值:
plt.clabel(C, inline=False, fontsize=12)
C代表刚刚画的等高线图(在用contour()等函数画完以后传给C,C = contour(...)),inline是否画在线内,fontsize数字的大小。
plot()
ax.plot(x, y, ls="-", lw=2, label="plot figure", color='black',alpha=0.5...)
用来画二维面上的点、线。当然也可以在三维的空间里面画,就画在三维坐标系的xOy面上。重要参数介绍:
x: 要画的线的各个点在x轴上的坐标(一维数组)
y: 要画的线的各个点在y轴上的坐标(一维数组或二维数组,第一维规模要和x轴的数组一致,第二维规模的大小就是画线的数量)
ls:折线图的线条风格,这里是一个减号
lw:折线图的线条宽度
label:标记图内容的标签文本
color:颜色
alpha:透明度
还有很多的参数可以调节,这里不一一列举,请看链接。另外,很多其它画线的函数也都支持一些个性化的参数,比如color、alpha、width等等,参数汇总看链接。
bar()
ax.bar(range(len(values)), values)
绘制条形图,第一个参数为横坐标,第二个参数为横坐标对应的值。
示例代码:
import matplotlib.pyplot as plt import numpy as np values = np.random.normal(0,1,[20]) plt.bar(range(len(values)),values) plt.show()
hist()
ax.hist(data,bins=50,range=[-5,5],density=True,cumulative=True,rwidth=0.9,orientation = 'vertical')
画频次直方图,这个函数会自动对数据做统计,如果是已经统计好的数据,可以使用上面的bar()函数画图。重要参数介绍:
x:待统计的一维数据。
bins:柱子的数量
range:数据统计的范围
density:是否转换为频率密度图(密度图,乘以范围宽度才是这个范围内数据的频率占比)
cumulative:是否累加,若为真,柱子统计的是小于等于这个值的所有数据。
rwidth:柱子的宽度。
orientation:柱子是垂直还是水平放置。
以下统计一个正态分布的累计柱状图:
hist2d()与hexbin()
ax.hist2d(x,y,bins=30,cmap='Blues')
二维频次直方图。参数与上述一维频次直方图类似。以下显示二维正态分布抽样频次统计图(旁边的色度条是plt.colorbar(),子图如何加还没研究...):
ax.hexbin(x,y,gridsize=30,cmap='Blues')
就是方格变成六边形格,gridsize表示格子大小:
绘制二维热度图
以上二维频次直方图函数会先对输入做统计,再进行绘图。如果是已经统计好的二维数据,我们可以用imshow()函数来画。示例代码如下:
import matplotlib.pyplot as plt values = np.random.randint(0,100,[5,5]) hot = plt.imshow(values, cmap=plt.cm.hot_r) #第二个参数是颜色风格 plt.colorbar(hot) #设置刻度条 plt.show()
三维图像
建立三维坐标系
fig = plt.figure() #添加绘图窗口 ax = fig.add_subplot(221,projection = '3d') #窗口内添加3d子图 ax = fig.add_subplot(projection = '3d') #如果只画一张图,可以用这个
plot_surface()
ax.plot_surface(X, Y, Z, rstride = 1, cstride = 1, cmap='jet')
画三维的曲面图,并且带有梯度颜色。
X、Y、Z就是每个网格点在对应坐标轴的值,cmap是涂色类型。rstride 是在行上每几个网格点计算一次梯度来图上对应梯度的颜色。cstride 就是列上的。它们越大,画梯度颜色的“补丁”也越大,对应地,“补丁”的数量也越少。如下图,一个是1,一个是2,“补丁”就一个是20,一个是10。
外部图像
图像导入与显示
import matplotlib.pyplot as plt import pylab #原本在jupyter里才能显示的图片,可以用窗口显示 img=plt.imread("image.jpg") #读取图片,读取到的是:高度×宽度×3RGB 的array数组 fig = plt.figure() #创建窗口 ax = fig.add_subplot(111) #创建子图 ax.imshow(img) #子图中添加图片 pylab.show() #显示窗口
cv2
图像批处理
从压缩包中直接读取图片
import zipfile import cv2 import numpy as np import matplotlib.pyplot as plt path = 'D:/Datasets/dogs-vs-cats/train.zip'#压缩包地址 with zipfile.ZipFile(path,mode='r') as f: for name in f.namelist(): if '.jpg' not in name: continue print(name) with f.open(name,mode='r') as image_file: content = image_file.read() # 读取图片 img = np.asarray(bytearray(content), dtype='uint8') #将jpg格式转码 img = cv2.imdecode(img, cv2.IMREAD_COLOR)#再转化为BGR格式,注意不是RGB,顺序反了 ,不重组的话在plt颜色显示异常 b,g,r = cv2.split(img) img = cv2.merge([r,g,b]) #将BGR拆分再重组为RGB plt.imshow(img) plt.show() break
图形拉伸
import cv2 cv2.resize(img,(w,h),interpolation=0)
将存在数组中的图像拉伸成w宽,h高。interpolation=0表示最近邻插值,不作平滑处理。其它插值参数(interpolation)请看链接。
seaborn
import seaborn as sns
seaborn简化了matplotlib的绘图操作,并且让图像更精美,绘制matplotlib图像时,使用sns.set(),可让图像更具特色。
mayavi
import mayavi.mlab as mlab
mayavi是专门绘制三维图形的库,虽然matplotlib也能绘制,但是matplotlib并不支持光线追踪,所以没有遮挡的效果。绘制各种图像的函数和matplotlib差不多。mayavi文档、简易实例。
mesh()
绘制三维图形表面,用法和matplotlib的plot_surface类似,但是创建网格时推荐用mgrid,meshgrid的索引顺序不对。
mlab.mesh(x, y, z )#绘制光滑表面 mlab.mesh(x, y, z, representation="wireframe", line_width=1.0)#绘制线而不是表面
下图画了一个卷起来的彩带:
代码如下:
import mayavi.mlab as mlab import numpy as np roll = 10 r = 0.5 w = 0.8 theta = np.linspace(np.pi*0.5,np.pi*2*roll,num=roll*100)[:,np.newaxis] h = np.linspace(-1,1,num=2)[np.newaxis,:]+0.5 x = y = z = np.zeros([len(theta),len(h[0,:])]) x = x + np.cos(theta)*theta*r/np.pi y = y + np.sin(theta)*theta*r/np.pi z = z + h - theta*w/np.pi print(y.shape,z.shape) mlab.mesh(x, y, z)#绘制光滑表面 mlab.show()
plot3d()
画三维坐标系中的曲线。用法和matplotlib的plot类似。同样推荐用mgrid创建网格。
mlab.plot3d(x,y,z)
numpy
用numpy的一些函数生成格式化的绘图数据。
linspace()
linspace(a, b, n),传回一个在a、b之间的插值列表(包括a、b),插值的数量是n。这个差值列表类型是array,而不是list,array里的数据类型是固定的,都是float。而列表list里面则并不是固定的,里面可以存任何东西。array是numpy下定义的一个类型,这个类型类似C++的数组,随机查找很快。所以处理大批量同类数据的时候,最好使用array类型。
具体使用和其他参数:
https://www.cnblogs.com/antflow/p/7220798.html
meshgrid()
用于生成对应列表的网格(网格也是用列表存,二维网格是对每一维来说是二维列表,三维网格对每一维来说是三维列表),用于绘制梯度图等。使用方法如下:
1. [X, Y] = meshgrid(x,y)或者python还支持X,Y = meshgrid(x,y),不加方括号也行,当然直接A = meshgrid(x,y),传给一个值也行,就是后面不太好处理。
2. [X, Y] = meshgrid(x)与[X, Y] = meshgrid(x, x)是等同的
3. [X, Y, Z] = meshgrid(x, y, z)生成三维的网格
生成的网格索引顺序在二维X、Y中是先Y再X,三维X、Y、Z中顺序是Y、X、Z。例如,在三维网格中,如果要获得x[2],y[7],z[3]位置的Y轴坐标,就是Y[7][2][3]。在二维网格中,如果要获得x[2],y[7]位置的X轴坐标,就是X[7][2]。
下图显示8*3的网格的X的列表:
mgrid
与meshgrid类似,同样能生成对应的网格。但是它并不是函数,而是以索引的形式使用的属性,并且还可以生成类似的2维以上的网格。另外,它和meshgrid的不同之处在于它们生成的网格的索引方式是相反的。推荐使用mgrid,它更容易理解。以下是实例:
import numpy as np a = np.mgrid[0:10:2,0:10:1] print(a)
索引的第二个冒号传入整数表示数的间隔,不包含最后一个数。传入复整数表示数的个数,比如5j表示范围内5个数,包含最后一个数。