matplotlib数据可视化小试

为什么有这么一出

最早接触到数据可视化应该是大学的时候了吧,那个时候使用的工具是matlab,可以用matlat对数据进行分析,进行可视化。但是那个时候总觉得matlab很难用,或者说matlab的代码不太友好,不过我现在也基本忘记了具体怎么使用matlab了。

工作的原因,需要利用监控数据进行软件性能的定标,这个过程就需要用到数据可视化。把海量的数据进行分析,然后可视化,或者可视化然后分析,也算数据挖掘的范畴吧。具体内容是,拉取小米监控(open-falcon)的历史数据,然后分析CPU,QPS,BandWidth之间的关系。

选择了matplotlib

数据可视化工具有很多,各种语言的也不一样。我的老本行是使用c/c++,这方面的类库好像很少,正好,刚入门了python,python的第三方库很丰富,数据可视化方面的类库也很丰富,说出来的有Pandas、Seaborn、ggplot、Bokeh、pygal、Plotly、matplotlib,详细可以查看这篇文章。最终选择了matplotlib作为我的数据可视化工具,原因很简单,我分析了自己的需求,需要实现坐标图,可能涉及动画,可能涉及3D,可能涉及散点图等,同时网上关于matplotlib的例子很丰富,官网上的例子也很详尽,上手应该很容易,所以最终选择了matplotlib。

关于matplotlib的介绍,官网如是说:

Matplotlib is a Python 2D plotting library which produces publication quality figures in a variety of hardcopy formats and interactive environments across platforms. Matplotlib can be used in Python scripts, the Python and IPython shell, the jupyter notebook, web application servers, and four graphical user interface toolkits.

screenshots screenshots screenshots screenshots
Matplotlib tries to make easy things easy and hard things possible. You can generate plots, histograms, power spectra, bar charts, errorcharts, scatterplots, etc., with just a few lines of code. For a sampling, see the screenshots, thumbnail gallery, and examples directory

For simple plotting the pyplot module provides a MATLAB-like interface, particularly when combined with IPython. For the power user, you have full control of line styles, font properties, axes properties, etc, via an object oriented interface or via a set of functions familiar to MATLAB users.

matplotlib使用

安装

1
yum install python-matplotlib

画一条正弦曲线

matplotlib的能耐很大,强烈建议你去官网阅读下它的图库。可以看到matplotlib能做的事情很多。

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env  python
# -*- coding:utf-8 -*-
import matplotlib.pyplot as plt
import numpy as np


x = np.linspace(0, 2 * np.pi, 1000)
y = np.sin(x)
#plt.plot(x,np.sin(x),x,np.sin(2*x))
#plt.plot(x,y,marker='o',mec='b',mfc='w')
plt.plot(x,y,mec='b',mfc='w')
plt.show()

分别注释plt.plot()语句可以得到不同的图谱,上面的结果如下:

简单分析代码,首先利用numpy库产生坐标轴x,y的值对,然后把(x,y)值对传入plot函数,最后调用plt.show()显示出来。

正是由于这个demo的试验,同时拉取了小米监控的数据,分析后想要得到cpu/bandwidth之间的关系,无非就是一个个(bandwidth,cpu)的值对,最终利用matplotlib以散点图的形式展示出来。这也是最终选择了mtplotlib的一个原因,先试验,或者说调研,看看能不能满足自己的需求。

保存画出的曲线图

保存画出的曲线图有两种方法,第一种方式是ply.show()显示后在图谱的左下角可以手动点击保存到本地;第二种方式就是如下:

1
2
3
from matplotlib.pyplot  import savefig
#plt.show()
savefig('./sinx.png')

散点图

先上代码,下面分别是两种不同的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python
import matplotlib.pyplot as plt
import numpy as np
#from matplotlib.pyplot import savefig
plt.switch_backend('agg')

n = 100

for color in ['red','blue','green']:
x,y=np.random.rand(2,n)
scale=100*np.random.rand(n)
plt.scatter(x,y,c=color,s=scale,label=color,alpha=0.6,edgecolors='white')

plt.title('Scatter')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.grid(True)
plt.show()

散点图如下:

解释:x,y=np.random.rand(2,n)产生随机的散点对,scale参数表示点的大小,然后利用for循环对红色,蓝色,绿色循环,设置参数label的值。最终的核心函数是scatter,这是画散点图的函数。具体的参数用法可以去matplotlib的官网查看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/usr/bin/python
import matplotlib.pyplot as plt
import numpy as np
import random
#from matplotlib.pyplot import savefig
#plt.switch_backend('agg')

n = 100

#for color in ['red','blue','green']:
color = 'blue'

x = np.random.rand(500)
y = np.random.rand(500)
size = np.random.rand(500) * 50
color = np.random.rand(500)
plt.scatter(x,y,size,color)
plt.colorbar()

'''
plt.title('Scatter')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.grid(True)
'''

plt.show()

散点图如下:
代码类似。

3D曲面图

先上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/env  python
# -*- coding: utf-8 -*-
"""
Created on Thu Sep 24 16:17:13 2015
"""

from matplotlib import pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
#from matplotlib.pyplot import savefig
#plt.switch_backend('agg')

fig = plt.figure()
ax = Axes3D(fig)
X = np.arange(-4, 4, 0.25)
Y = np.arange(-4, 4, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)

# 具体函数方法可用 help(function) 查看,如:help(ax.plot_surface)
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='rainbow')

plt.show()
#savefig('/home/niki/sharedmac/3dqumiantu.png')

3D曲面图如下:

代码就不多解释了,具体用到可以去官网查看API。这个3D曲面是可以用鼠标拖动翻转的,如下:

动画制作

利用matplotlib制作动画也是可行的,废话不多说,先上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from matplotlib import pyplot as plt
from matplotlib import animation
import numpy as np

#first set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1,xlim=(0, 2), ylim=(-4, 4))
line, = ax1.plot([], [], lw=2)
def init():
line.set_data([], [])
return line

# animation function. this is called sequentially
def animate(i):

x = np.linspace(0, 2 * np.pi , 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
line.set_data(x, y)
return line

anim1=animation.FuncAnimation(fig, animate, init_func=init, frames=100, interval=5)
plt.show()

代码解读:核心函数FuncAnimation,大致思想是隔一定时间去更新坐标系里的数据,然后可以设置更新的时间,次数等,具体可以去查看API。动画如下:

多项式拟合

在我的场景下,构建好散点图后还不行,还需要对散点图进行多项式拟合,得到近似的一些曲线表达式。

最小二乘法

关于线性拟合的知识不展开来讲,这里可以参考这篇博文线性回归:最小二乘曲线拟合算法,代码如下:

1
2
3
4
5
import numpy as np

def matrix_lstsqr(x, y):
X = np.vstack([x, np.ones(len(x))]).T
return (np.linalg.inv(X.T.dot(X)).dot(X.T)).dot(y)

另外一种实现方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# from __future__ import division # python 2

def classic_lstsqr(x_list, y_list):
N = len(x_list)
x_avg = sum(x_list)/N
y_avg = sum(y_list)/N
var_x, cov_xy = 0, 0
for x,y in zip(x_list, y_list):
temp = x - x_avg
var_x += temp**2
cov_xy += temp * (y - y_avg)
slope = cov_xy / var_x
y_interc = y_avg - slope*x_avg
return (slope, y_interc)

两种方式的异同参考上面提到的博文。

高次多项式拟合

线性拟合有时候并不能很好的对散点图进行拟合,有时候我们需要提高次数,进行高次多项式的拟合,得到更加精确的表达式,但是这里也注意,过高的次数会产生过拟合现象。

1
2
3
4
5
6
7
8
9
10
11
#start多项式拟合
#最高次項为6次方的多項式
line4 = np.polyfit(x, y, 6) #返回多项式的系数
pn4 = np.poly1d(line4) #根据多项式的系数生成一个多项式计算器
ftext4 = 'y = a*x^6 +b*x^5+c*x^4+d*x^3+e*x^2+f*x+g ={}*x^6+ {}*x^5 +{}*x^4+{}*x^3+{}*x^2+{}*x+{}'.format(line4[0],line4[1],line4[2],line4[3],line4[4],line4[5],line4[6])
print ftext4

xaxis = np.linspace(0,max(x),17000) #0~400采样17000个点,自己的理解
ax.plot(xaxis, pn4(xaxis),color[1],markersize=3) #markersize表示点>的大小
ax.legend(['6th degree poly',loc='lower right')
ax.grid(True)

这里随便贴一张我项目里最后的图片:

一壶茶喝完

本篇博客是坐在阳光小镇咖啡餐厅酒吧里一个下午写的,由于是回忆的来写,写的期间为了得到文中的图片,又重新调整了一些代码,可能当时觉得很难或者不易的代码现在看起来比较简单,所以就写的简略了些,见谅。如果后续有想到的再补充。简单来说,matplotlib上手也很容易,官网的例子也很丰富。

好了,到此为止。

洛神柠檬茶
buy me a cola!

欢迎关注我的其它发布渠道