文章目录
一、Matplotlib配色
1.1 预定义的配色
在matplotlib中默认了很多颜色,比如’k
‘代表黑色,’r
‘代表红色,这些都是最简单的配色,其他还有例如’azure
’,’cyan
'等也是我常用到的浅色预定义配色,更多预定义配色可以在官网查看:
如果认为颜色过深,还可以用aplha
参数来调整,取值范围为0-1。
这里我们用ax.add_patch()
来做两个交叠的矩形来展示,其中zorder
表示各个图层的位置,数值大的在数值小的上层:
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
fig,axes=plt.subplots(1,2,figsize=(8,4))
ax=axes[0]
ax.add_patch(Rectangle(xy=(0.5,0.5),width=.3,height=.3,fc='tomato',zorder=1,label='zorder=1'))
ax.add_patch(Rectangle(xy=(0.3,0.3),width=.3,height=.3,fc='royalblue',zorder=2,label='zorder=2'))
ax.set_title('alpha=1,blue over red')
ax.legend(loc='best')
ax=axes[1]
ax.add_patch(Rectangle(xy=(0.5,0.5),width=.3,height=.3,fc='tomato',zorder=2,label='zorder=2',alpha=0.3))
ax.add_patch(Rectangle(xy=(0.3,0.3),width=.3,height=.3,fc='royalblue',zorder=1,label='zorder=1',alpha=0.3))
ax.set_title('alpha=0.3,red over blue')
ax.legend(loc='best')
也可以直接在matplotlib.colors.cnames
查看所有名字和对应的16进制码
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.colors as colors
import math
%matplotlib notebook
names={}
import matplotlib
for name, hex in matplotlib.colors.cnames.items():
names.update({name:hex})
fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111)
ratio = 1.0 / 3.0
count = math.ceil(math.sqrt(len(colors.cnames)))
x_count = count * ratio
y_count = count / ratio
x = 0
y = 0
w = 1 / x_count
h = 1 / y_count
for c in colors.cnames:
pos = (x / x_count, y / y_count)
ax.add_patch(patches.Rectangle(pos, w, h, color=c))
ax.annotate(c, xy=pos)
if y >= y_count-1:
x += 1
y = 0
else:
y += 1
plt.show()
得到各色的预览图:
1.2 colormaps
在RGB色彩理论中,用三维数组来表示红色、绿色和蓝色三种颜色的光色,再利用这三种颜色的组合得到其他的颜色,一般的RGB是三个0-255的数值组成,而在matplotlib中常用0-1的小数来表示,例如设置参数时用c=[1,0,0]
也可以等同于c='r'
,也可以用c=[1,0,0,0.5]
等同于设置为红色的同时设置了alpha=0.5
,后面提到的sm.to_rgba()实际上就是把颜色转换成了四维的数据。
colormap是将数值映射成色彩,不同的数据可以用某条由一种颜色到另一种颜色(或者某一种颜色到白色再到另一种颜色)的色带中的某个颜色来反映出来,这样就可以利用颜色创造出另一维可视化数据。
在matplotlib中常常将颜色由一种颜色到另一种颜色制作成一个连续的色带,同时用一个实数区间来与色带相对应,每一个实数对应色带上的一种颜色,故而在应用colormap的时候往往需要将对应数据的取值区间进行规范化。
在实际应用过程中,主要分为四个部分,假设需要着色的基数据记为x
:
- 对数据集进行规范化
可以用matplotlib.colors模块中的Normalize()
或者使用plt.Normalize()
,括号中的参数为数据集的最大值和最小值,得到必要参数norm
。 - 选定colormap的色带
可以使用预定义的colormap也可以自己定义colormap得到必要参数cmap
- 将色带上的颜色应用在规范化后的数据上,本文介绍两种办法:
(I)直接用cmap
映射正则化后的数据colors=[cmap(norm(val)) for val in x]
,之后在做图的时候添加参数c=colors
即可
(II)利用matplotlib
中的cm
模块中的cm.ScalarMappable(norm=None, cmap=None)
利用norm
来规范化数据cmap
为数据找到对应的颜色,得到可映射标量ScalarMappable
对象,记为sm
,做图的时候添加参数c=sm.to_rgba(x)
(其中rgba中的rgb是指RGB色彩理论,a是指alpha表示颜色的透亮度)即可。
ScalarMappable
对象还可以用于制作色阶图,可以用
plt.colorbar(sm) #设置参数orientation='horizontal'则可以将色阶图转为在水平
对于散点图等其他全数据做图的情况下,也可以不设置可映射标量ScalarMappable
对象,直接使用c=x,cmap=cmap
,如下例子中所示。
1.2.1 预定义的colormaps
在matplotlib中有许多预定义的colormaps,在环境中导入matplotlib中的cm模块即可查看预定义的colormaps,具体颜色可见官网:
在matplotlib中的cm模块中选择适合的colormap,可以用cm.get_cmap()
或者也可以用matplotlib.colormaps[]
来取colormap
import matplotlib.pyplot as plt
from matplotlib import cm
fig,axes=plt.subplots(1,2,figsize=(10,4))
#子图1:直接根据x值大小来给点上色
plt.sca(axes[0])
x=np.linspace(1,10,20)
y=[1]*len(x)
plt.scatter(x,y,c=x, cmap='viridis')
#子图2:创建ScalarMappable来根据x值大小给点上色
plt.sca(axes[1])
x=np.linspace(1,10,20)
y=[1]*len(x)
#根据数据范围得到正则化规则
norm=plt.Normalize(np.min(x),np.max(x))
#得到色带'viridis'
cmap=cm.get_cmap('viridis')
#创建可映射标量`ScalarMappable`类
sm=cm.ScalarMappable(norm=norm,cmap=cmap)
plt.scatter(x,y,c=sm.to_rgba(x))
#根据sm创建色阶图
plt.colorbar(sm)
1.2.2 自定义的colormaps
利用matplotlib.colors
中的ListedColormapListed
来自定义colormap,可以阅读官网文档:
- 离散的色阶图
首先我们先得到一个色阶图共4个类的离散的colormap:
from matplotlib.colors import ListedColormap
from matplotlib import cm
import matplotlib.pyplot as plt
cmap=ListedColormap(["darkorange", "gold", "lawngreen", "lightseagreen"])
plt.figure()
x=np.linspace(1,10,20)
y=[1]*len(x)
norm=plt.Normalize(np.min(x),np.max(x))
sm=cm.ScalarMappable(norm=norm,cmap=cmap)
plt.scatter(x,y,c=sm.to_rgba(x))
plt.colorbar(sm)
- 连续的colormap
实际上,看似连续的colormap也是由一个个颜色块组合在一起的,如果我们将256个颜色块组合在一起,那么他们看起来也就连续了。在这里我们将两种色带拆开来粘在一起,例如我们上半部分取’Oranges_r’的色带,下半部分取’Blues’的色带,各取128个颜色类,用np.vstack将两组数据拼合起来得到新的colormap:
from matplotlib.colors import ListedColormap
from matplotlib import cm
import matplotlib.pyplot as plt
top = cm.get_cmap('Oranges_r', 128)
bottom = cm.get_cmap('Blues', 128)
newcolors = np.vstack((top(np.linspace(0, 1, 128)),
bottom(np.linspace(0, 1, 128))))
newcmp = ListedColormap(newcolors, name='OrangeBlue')
plt.figure()
x=np.linspace(1,10,20)
y=[1]*len(x)
norm=plt.Normalize(np.min(x),np.max(x))
sm=cm.ScalarMappable(norm=norm,cmap=newcmp)
plt.scatter(x,y,c=sm.to_rgba(x))
plt.colorbar(sm)
二、Animation制作动画
注意:如果是使用jupyter notebook,在导入matplotlib库后用%matplotlib notebook
来查看动画
在matplotlib中,制作动画实际上是利用backend
的renders
不断清空原画面内容然后作画的过程。在动画运行过程就是把一张一张的图像连起来,因为人肉眼捕捉画面的频率有限,当每一秒插入了足够多的张数的画纸的时候,看起来就像动画里。每一张画纸就是一帧(frame
),可以把画板理解成流(stream
)。
在matplotlib
中有一个animation
模块可以用来制作动画,在这里我们主要介绍函数控制型动画的制作animation.FuncAnimation()
。
顾名思义,函数控制型动画,就是指用函数来控制stream
的变化,主要由以下几个部分来构成一张动画
- fig:图像
- func:控制动画的函数
- frames:一个完整的动画的帧数
- init_func:初始帧的函数
- interval:帧与帧之间间隔的时长,单位:毫秒
- blit:改变整个画面还是仅改动变化部分
对于控制函数应该如何写,可以参考以下例子,与普通的在画布上做图一样,可以参考
链接:Matplotlib入门(一):架构概述、面向对象编程绘图与函数式绘图基础:
import pandas as pd
import numpy as np
import matplotlib.animation as animation
import matplotlib.pyplot as plt
def update(curr):
#plt.cla():clearn current axes
plt.cla()
bins = np.arange(-4, 4, 0.5)
plt.hist(x[:curr], bins=bins)
plt.axis([-4,4,0,30])
#plt.gca():get current axes
plt.gca().set_title('Sampling the Normal Distribution')
plt.gca().set_ylabel('Frequency')
plt.gca().set_xlabel('Value')
plt.annotate('n = {}'.format(curr), [3,25])
fig = plt.figure()
a = animation.FuncAnimation(fig=fig, func=update, frames=100,interval=10,blit=False)
以下是动画的第83帧:
另一个例子见:
制作动画实例:绘制正态分布形成过程的动画
三、 设置交互模式
Matplotlib中的交互性和动画非常相似。不过,为了实现互动,我们必须更深入到Artist
层。特别是,我们必须引用当前图形的canvas
(画布对象)。
canvas
处理所有绘图事件,并与给定的后端紧密连接。例如,移动鼠标指针将创建一个事件,单击将创建一个事件,按键盘上的键将创建一个事件。这不仅发生在硬件层面,也发生在软件层面。事实上,事件驱动编程已经渗透到计算机程序员经常使用软件的大多数方式中。从HTML和JavaScript,到较低级别的C代码。
可以将事件视为与函数调用关联的一段数据。当事件发生时,软件环境(在我们的例子中是Matplotlibs后端)将使用相关数据调用函数。
在这里我们介绍鼠标单击创建事件和移动创建事件的交互模式。
3.1 鼠标单击创建事件的交互
交互模式和animation十分相似的一点是都要创建控制函数,然后直接在当前canvas
上的mpl_connect()
设置'button_press_event'
和对应的控制函数即可:
控制函数的传入值为事件event,可以用event.x和event.y
得到点击位置x和y对应的像素点值,用event.xdata和event.ydata
来获得点击位置x和y的值:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib notebook
plt.figure()
data = np.random.rand(10)
plt.plot(data)
#控制函数
def onclick(event):
plt.cla()
plt.plot(data)
plt.gca().set_title('Event at pixels {},{} \nand data {:.2f},{:.2f}'.format(event.x, event.y, event.xdata, event.ydata))
plt.scatter(event.xdata,event.ydata,s=10,c='r')
plt.gcf().canvas.mpl_connect('button_press_event', onclick)
如此,在图像点击时便会产生红点,并将其坐标展示在title上:
3.2 移动鼠标指针将创建事件的交互
在当前canvas
上的mpl_connect()
设置'motion_notify_event'
和对应的控制函数即可实现对鼠标移动事件的交互,而设置'button_press_event'
和'button_release_event'
分别表示鼠标按压和释放事件的交互:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
text = ax.text(0.5, 0.5, 'event', ha='center', va='center', fontdict={'size': 20})
def call_back(event):
info = 'name:{}\n button:{}\n x,y:{},{}\n xdata,ydata:{:.2f}{:.2f}'.format(event.name, event.button,event.x, event.y,event.xdata, event.ydata)
text.set_text(info)
fig.canvas.draw_idle()
fig.canvas.mpl_connect('button_press_event', call_back)
fig.canvas.mpl_connect('button_release_event', call_back)
fig.canvas.mpl_connect('motion_notify_event', call_back)
plt.show()
- 鼠标移动时
- 鼠标按压时
- 鼠标释放时
四、应用实例
可以查看以下实例:
Applied Plotting, Charting & Data Representation in Python :Assignment 3
总结
- 介绍了
matplotlib
中配色的重要工具colormap
,cmap
的查找与创建方法,介绍了ScalarMappable
对象的创建与使用 - 介绍了
matplotlib
中animation
制作动画的办法,主要介绍了函数控制动画的方法 - 介绍了
matplotlib
中在图上交互的办法,主要介绍点击、拖动鼠标、按压鼠标、释放鼠标产生的事件