Python数据可视化之matplotlib

534 阅读6分钟

1. 概述

matplotlib介绍

matplotlib 是Python最著名的绘图库,它提供了一整套和matlab相似的命令API,十分适合交互式地进行制图。而且也可以方便地将它作为绘图控件,嵌入GUI应用程序中。

matplotlib由来

matplotlib是一个开源项目,由John Hunter发起。关于matplotlib的由来,有一个小故事。John Hunter和他研究癫痫症的同事借助一个专有软件做脑皮层电图分析,但是他所在的实验室只有一份该电图分析软件的许可。他和许多一起工作的同事不得不轮流使用该软件的硬件加密狗。于是,John Hunter便有了开发一个工具来替代当前所使用的软件的想法。当时MATLAB被广泛应用在生物医学界中,John Hunter等最初是想开发一个基于MATLAB的版本,但是由于MATLAB的一些限制和不足,加上他本身对Python非常熟悉,于是就有了matplotlib的诞生。

2. 数据可视化

绘制基本函数

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-1, 1, 50)  # -1到1平分成50个点
y = 2*x + 1  # 要绘制的函数

plt.plot(x, y)  # 需要按(横坐标,纵坐标)的顺序
plt.show()  # 展示图片

图像设置

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 50)  # -3到3平分成50个点
y1 = 2*x + 1
y2 = x**2

plt.figure()  # 以下所有数据属于此figure
plt.plot(x, y1)

plt.figure(num=2, figsize=(8, 5))  # figure参数:num=序号, figsize=(长, 宽)
plt.plot(x, y1, color='red', linewidth=1.0, linestyle='--')  # plot参数: color=颜色, linewidth=线宽, linestyle=线条样式
plt.plot(x, y2)

plt.show()

坐标系

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 50)  # -3到3平分成50个点
y1 = 2*x + 1
y2 = x**2

plt.figure(num=1, figsize=(8, 5))
plt.plot(x, y1, color='red', linewidth=1.0, linestyle='--')
plt.plot(x, y2)

plt.xlim((-1, 2))  # 设置x轴范围
plt.ylim((-2, 3))  # 设置y轴范围
plt.xlabel('I am X')  # 添加x轴说明
plt.ylabel('I am Y')  # 添加y轴说明

new_ticks = np.linspace(-1, 2, 5)  # 设置ticks
plt.xticks(new_ticks)  # 将x轴刻度标识换为自定义的ticks
plt.yticks([-2, -1.8, -1, 1.22, 3,],
            [r'$really\ bad$', r'$bad$', r'$normal-\alpha$', r'$good$', r'$really\ good$'])  # 设置y轴不同值对应的刻度
                                                                                 # r识别正则表达 $符修改数学字体 输出空格:\+空格 \转置符

plt.show()

axis.png

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 50)
y1 = 2*x + 1
y2 = x**2

plt.figure()
plt.plot(x, y2)
plt.plot(x, y1, color='red', linewidth=1.0, linestyle='--')

plt.xlim((-1, 2))
plt.ylim((-2, 3))
plt.xlabel('I am x')
plt.ylabel('I am y')

new_ticks = np.linspace(-1, 2, 5)
plt.xticks(new_ticks)
plt.yticks([-2, -1.8, -1, 1.22, 3],
            [r'$really\ bad$', r'$bad\ \alpha$', r'$normal$', r'$good$', r'$really\ good$'])

# gca = 'get current axis'
ax = plt.gca()  # 拿出当前的整个坐标轴
ax.spines['right'].set_color('none')  # 将右边线设置为无(隐藏右边框)
ax.spines['top'].set_color('none')  # 将上边线设置为无(隐藏上边框)
ax.xaxis.set_ticks_position('bottom')  # 将下边线设置为x轴
ax.yaxis.set_ticks_position('left')  # 将左边线设置为y轴
ax.spines['bottom'].set_position(('data', 0))  # 将横坐标的位置固定在纵坐标值为0处 参数还可以有outward,axes(百分比)等
ax.spines['left'].set_position(('data', 0))  # 将纵坐标的位置固定在横坐标值为0处

plt.show()

axis_more.png

图例

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 50)
y1 = 2*x + 1
y2 = x**2

plt.figure()

plt.xlim((-1, 2))
plt.ylim((-2, 3))
plt.xlabel('I am x')
plt.ylabel('I am y')

new_ticks = np.linspace(-1, 2, 5)
plt.xticks(new_ticks)
plt.yticks([-2, -1.8, -1, 1.22, 3],
            [r'$really\ bad$', r'$bad\ \alpha$', r'$normal$', r'$good$', r'$really\ good$'])

l1, = plt.plot(x, y2, label='up')  # 用参数label给线命名为up
l2, = plt.plot(x, y1, color='red', linewidth=1.0, linestyle='--', label='down')  # 用参数label给线命名为down

# 打印图例
# 参数handles传入线条(需要在线条定义处加逗号)
# 参数label对图例进行对应命名(覆盖线条命名)
# 参数loc设置图例的位置,best会自动选取方便显示的地方
plt.legend(handles=[l1, l2, ], labels=['aaa', 'bbb'], loc='best')

plt.show()

注解

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 50)
y = 2*x + 1

plt.figure(num=1, figsize=(8, 5))
plt.plot(x, y)

ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
ax.spines['bottom'].set_position(('data', 0))
ax.spines['left'].set_position(('data', 0))

x0 = 1
y0 = 2*x0 + 1
plt.scatter(x0, y0, s=50, color='b')  # 打印出点(x0, y0), 参数s定义点的大小, 参数color定义点的颜色
plt.plot([x0, x0], [y0, 0], 'k--', lw=2.5)  # 在指定两点间绘制线宽(lw)为2.5的黑色(k)虚线(--)

# method 1
# r正则表达 %传入字符串 参数xy确定打印注解的位置 参数xytext表示注释相对于基准点的位置 参数arrowprops定义箭头属性(用dic包含)
plt.annotate(r'$2x+1=%s$' % y0, xy=(x0, y0), xycoords='data', xytext=(+30, -30), textcoords='offset points', fontsize=16,
             arrowprops=dict(arrowstyle='->', connectionstyle='arc3, rad=.2'))  # 参数arrowstyle表示箭头形状 参数connectionstyle表示弧度角度

# method 2
# 设置文本的起始点和终止点,文本内容,以及字体
plt.text(-3.7, 3, r'$This\ is\ some\ text.\ \mu\ \sigma_i\ \alpha_t$', fontdict={'size':16, 'color':'r'})

plt.show()

tick能见度

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 50)
y = 0.1*x

plt.figure()
plt.plot(x, y, linewidth=10)
plt.ylim(-2, 2)
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
ax.spines['bottom'].set_position(('data', 0))
ax.spines['left'].set_position(('data', 0))

for label in ax.get_xticklabels() + ax.get_yticklabels():  # 将坐标刻度顺次取出
    label.set_fontsize(12)  # 设置字体大小
    label.set_bbox(dict(facecolor='yellow', edgecolor='g', alpha=0.7))  # 设置坐标框填充色,边界色,透明度

plt.show()

散点图

import matplotlib.pyplot as plt
import numpy as np

n = 1024
X = np.random.normal(0, 1, n)  # 随机生成n个满足均值为0,方差为1的正态分布的点
Y = np.random.normal(0, 1, n)
T = np.arctan2(Y, X)  # 表示颜色数值

plt.scatter(X, Y, s=75, c=T, alpha=0.5)  # 绘制散点图 参数s表示点的大小 参数c表示点的颜色 参数alpha表示透明度

plt.xlim((-1.5, 1.5))
plt.ylim((-1.5, 1.5))
plt.xticks(())  # 隐藏所有的刻度值
plt.yticks(())

plt.show()

柱状图

import matplotlib.pyplot as plt
import numpy as np

n = 12  # 柱状图柱形数量
X = np.arange(n)  # X生成0~11
Y1 = (1 - X/float(n)) * np.random.uniform(0.5, 1.0, n)  # 根据X产生Y数据
Y2 = (1 - X/float(n)) * np.random.uniform(0.5, 1.0, n)

plt.bar(X, +Y1, facecolor='#9999ff', edgecolor='white')  # 生成柱状图的数值 朝向+上-下,填充颜色,边界颜色
plt.bar(X, -Y2, facecolor='#ff9999', edgecolor='white')

for x, y in zip(X, Y1):  # zip()把X和Y1的值分别传到x和y中
    plt.text(x, y + 0.05, '%.2f'% y, ha='center', va='bottom')  # 加文本的位置,内容,横向对齐方式,纵向对齐方式

for x, y in zip(X, Y2):  # zip()把X和Y1的值分别传到x和y中
    plt.text(x, - y - 0.05, '-%.2f'% y, ha='center', va='top')

plt.xlim(-0.5, n)
plt.xticks(())
plt.ylim(-1.25, 1.25)
plt.yticks(())

plt.show()

等高线图

import matplotlib.pyplot as plt
import numpy as np


def f(x, y):
    # the height function
    return (1 - x/2 + x**5 + y**3) * np.exp(-x**2-y**2)  # 高度公式

n = 256
x = np.linspace(-3, 3, n)
y = np.linspace(-3, 3, n)
X, Y = np.meshgrid(x, y)  # 绘制底图为网格图

# use plt.contourf to filling contours
# X, Y and value for (X, Y) point
plt.contourf(X, Y, f(X, Y), 8, alpha=0.75, cmap=plt.cm.hot)  # 绘制等高线图的三维点信息,分高线的分隔部分数量,透明度,数值对应的热度颜色

# use plt.contour to add contour lines
C = plt.contour(X, Y, f(X, Y), 8, colors='black', linewidth=0.5)  # 绘制等高线,分高线的分隔部分数量,颜色,线条宽度

# adding label
plt.clabel(C, inline=True, fontsize=10)  # 给等高线加上数字描述,画在线里,字体大小

plt.xticks(())
plt.yticks(())
plt.show()

数字图像

import matplotlib.pyplot as plt
import numpy as np

# image data
a = np.array([0.313660827978, 0.365348418405, 0.423733120134,
              0.365348418405, 0.439599930621, 0.525083754405,
              0.423733120134, 0.525083754405, 0.651536351379]).reshape(3, 3)

plt.imshow(a, interpolation='nearest', cmap='bone', origin='lower')  # 展示图片, 图片样式, 颜色对应, 深色位置
plt.colorbar(shrink=0.9)  # 添加标注 参数shrink表示标注压缩比例(压缩到原来的90%)

plt.xticks(())
plt.yticks(())
plt.show()

3D图像

import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D  # 3D图模块

fig = plt.figure()  # 绘制3D图背景
ax = Axes3D(fig)  # 添加坐标轴

# X, Y value
X = np.arange(-4, 4, 0.25)  # 设定x轴
Y = np.arange(-4, 4, 0.25)  # 设定y轴
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
# height value
Z = np.sin(R)  # 设定z轴

ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=plt.get_cmap('rainbow'))  # 绘制3D图: 坐标轴信息, 线跨(密)度, 颜色
ax.contourf(X, Y, Z, zdir='z', offset=-2, cmap='rainbow')  # 绘制等高线: 投射面, 投射轴位置, 颜色
ax.set_zlim(-2, 2)


plt.show()

多图合一

import matplotlib.pyplot as plt

plt.figure()

plt.subplot(2, 2, 1)  # 将figure分成两行两列, 第一部分
plt.plot([0, 1], [0, 1])

plt.subplot(2, 2, 2)  # 将figure分成两行两列, 第二部分
plt.plot([0, 1], [0, 2])

plt.subplot(2, 2, 3)  # 将figure分成两行两列, 第三部分
plt.plot([0, 1], [0, 3])

plt.subplot(2, 2, 4)  # 将figure分成两行两列, 第四部分
plt.plot([0, 1], [0, 4])

plt.show()

import matplotlib.pyplot as plt

plt.figure()

plt.subplot(2, 1, 1)  # 将figure分成两行, 第一行1列, 第一部分
plt.plot([0, 1], [0, 1])

plt.subplot(2, 3, 4)  # 将figure分成两行, 第二行3列, 第4部分
plt.plot([0, 1], [0, 2])

plt.subplot(2, 3, 5)  # 将figure分成两行, 第二行3列, 第5部分
plt.plot([0, 1], [0, 3])

plt.subplot(2, 3, 6)  # 将figure分成两行, 第二行3列, 第6部分
plt.plot([0, 1], [0, 4])

plt.show()

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

# method 1: subplot2grid
plt.figure()
ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=3, rowspan=1)  # 绘制小图:行列数,起始点,行跨度,列跨度
ax1.plot([1, 2], [1, 2])
ax1.set_title('ax1_title')

ax2 = plt.subplot2grid((3, 3), (1, 0), colspan=2, rowspan=1)
ax3 = plt.subplot2grid((3, 3), (1, 2), rowspan=2)
ax4 = plt.subplot2grid((3, 3), (2, 0))
ax4 = plt.subplot2grid((3, 3), (2, 1))


# method 2: gridspec
# plt.figure()
# gs = gridspec.GridSpec(3, 3)
# ax1 = plt.subplot(gs[0, :])
# ax2 = plt.subplot(gs[1, :2])
# ax3 = plt.subplot(gs[1:, 2])
# ax4 = plt.subplot(gs[-1, 0])
# ax5 = plt.subplot(gs[-1, -2])

# method 3: easy to define structure
# f, ((ax11, ax12), (ax21, ax22)) = plt.subplots(2, 2, sharex=True, sharey=True)
# ax11.scatter([1, 2], [1, 2])


plt.tight_layout()
plt.show()

图中图

import matplotlib.pyplot as plt

fig = plt.figure()
x = [1, 2, 3, 4, 5, 6, 7]
y = [1, 3, 4, 2, 5, 8, 6]

left, bottom, width, height = 0.1, 0.1, 0.8, 0.8
ax1 = fig.add_axes([left, bottom, width, height])  # 在图片内加图 加图位置(百分比形式)
ax1.plot(x, y, 'r')  # 线条颜色
ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax1.set_title('title')

left, bottom, width, height = 0.2, 0.6, 0.25, 0.25
ax2 = fig.add_axes([left, bottom, width, height])
ax2.plot(y, x, 'b')
ax2.set_xlabel('x')
ax2.set_ylabel('y')
ax2.set_title('title inside 1')

plt.axes([0.6, 0.2, 0.25, 0.25])
plt.plot(y[::1], x, 'g')
plt.xlabel('x')
plt.ylabel('y')
plt.title('title inside 2')

plt.show()

次坐标轴

import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure()
x = np.arange(0, 10, 0.1)
y1 = 0.05 * x**2
y2 = -1 * y1

fig, ax1 = plt.subplots()
ax2 = ax1.twinx()  # 用镜面形式将y轴对称反转
ax1.plot(x, y1, 'g-')
ax2.plot(x, y2, 'b--')

ax1.set_xlabel('X data')
ax1.set_ylabel('Y1', color='g')
ax2.set_ylabel('Y2', color='b')
plt.show()

动画

import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation

fig, ax = plt.subplots()

x = np.arange(0, 2*np.pi, 0.01)
line, = ax.plot(x, np.sin(x))

def animate(i):
    line.set_ydata(np.sin(x+i/10))
    return line,

def init():
    line.set_ydata(np.sin(x))
    return line,

ani = animation.FuncAnimation(fig=fig, func=animate, frames=100, init_func=init, interval=20, blit=False)  # 设置动画
plt.show()

3. 参考资料


文章中的所有代码经测试均可成功编译运行,可直接复制。具有显然结果或简单结论的代码不展示运行结果。如有问题欢迎随时交流~