zoukankan      html  css  js  c++  java
  • 『Matplotlib』数据可视化专项

    一、相关知识

    官网介绍

    matplotlib API

    相关博客

    matplotlib绘图基础

    漂亮插图demo

    使用seaborn绘制漂亮的热度图

    fig, ax = plt.subplots(2,2),其中参数分别代表子图的行数和列数,一共有 2x2 个图像。函数返回一个figure图像和一个子图ax的array列表。

    补充:gridspec命令可以对子图区域划分提供更灵活的配置。

    中文显示方框问题

    这是由于matplotlib文件夹内没有中文字体包导致的,实际上函数包本身是支持中文的,常见解决方案是拷贝字体文件到matplotlib中,不过我感觉太麻烦,找到了另外的方式,

    from pylab import mpl
    
    mpl.rcParams['font.sans-serif'] = ['FangSong']    # 指定默认字体
    mpl.rcParams['axes.unicode_minus'] = False        # 解决保存图像是负号'-'显示为方块的问题  

    加上这三行代码指定一下字体就行了(实际上最后一行可以不加)

    anaconda字体路径在:/anaconda2/lib/python2.7/site-packages/matplotlib/mpl-data/font/ttf

    一、常用绘制流程

    1.axes列表中包含各个子图句柄

    # 3x3子图
    fig, axes = plt.subplots(3, 3)
    # 子图间距设定
    fig.subplots_adjust(hspace=0.3, wspace=0.3)
    # 在分别绘制各个子图
    for i, ax in enumerate(axes.flat):
        pass
    

    2.每个子图句柄需要单独生成

    # 画布
    fig = plt.figure()
    # 添加子图
    ax = fig.add_subplot(211)
    pass
    # 添加子图
    ax2 = fig.add_subplot(212)
    pass
    

    3.使用plt包命名空间代指多个子图句柄

    【注】这种方法的句柄含在plt中,与上面的ax的方法属性并不相同,下面会详解

    # 添加子图
    plt.subplot(311)
    pass
    # 添加子图
    plt.subplot(312)
    pass
    # 添加子图
    plt.subplot(313)
    pass
    

    二、绘图功能

    【注】使用ax代指子图方法1、2的句柄,plt代指方法3中的命名空间。坐标生成:

    # 一维坐标生成
    x = np.linspace(0,10,100)
    
    # 二维网格生成
    u = np.linspace(-1,1,100)
    x,y = np.meshgrid(u,u) 
    

     坐标轴标签:

    xlabel = "True: {0}, Pred: {1}".format(cls_true[i], cls_pred[i])
    xlabel = "y"
    
    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel)
    
    plt.xlabel('x')
    plt.ylabel('y')
    

     坐标轴刻度:

    ax.set_xticks([])
    ax.set_yticks([])
    
    plt.xticks(range(len(x)), ['a', 'b', 'c', 'd', 'e', 'f'])
    plt.yticks(range(1, 8, 2))
    

     坐标网格:

    # 横纵坐标单位长度统一
    plt.axis('equal')
    # 网格
    plt.grid(True)
    
    # 网格
    ax.grid(True)
    

     图表标题:

    plt.title('Second Derivative')
    

     对数坐标:

     '''对数坐标'''
    
    plt.semilogx(x,y)  # 对x取对数
    plt.semilogy(x,y)  # 对y取对数
    plt.loglog(x,y)    # 同时取对数
    

    绘图:

    # 色彩填充
    ax.fill(x,y1,facecolor='g',alpha=0.3)
    ax.fill_between(x,y,y1,facecolor='b')
    # 等高线
    ax.contourf(x,y,z)
    # 显示数组,因为是数组所以才会有vmin和vmax的关键字
    ax.imshow()
    
    # 线性绘图
    plt.plot(x,y1,c='b',linestyle='',marker='^')
    

    三、经典实例

    饼状图

    import matplotlib.pyplot as plt
    
    plt.figure(figsize=(12,9))
    
    labels = ['part1', 'part2', 'part3']
    # 各个饼的比例
    sizes = [30, 20, 50]
    colors = ['yellowgreen', 'gold', 'lightskyblue']
    
    # 各个模块离圆心的距离,参数为距离
    explode = (0.05, 0.0, 0.0)  
    # 图 label的text 比例的text
    patches, l_texts, p_texts = plt.pie(sizes, explode=explode, labels=labels, colors=colors, labeldistance=0.8,
            autopct='%3.1f%%', shadow=True, startangle=90, pctdistance=0.6)
    
    # 设置x,y轴刻度一致,这样饼图才能是圆的
    plt.axis('equal')
    plt.legend()
    
    # 设置label的字体大小
    for t in l_texts:
        t.set_size(20)
    # 设置比例数字的字体大小
    for t in p_texts:
        t.set_size(20)
    
    plt.show()
    

     

    柱状图

    import numpy as np
    from matplotlib import pyplot as plt
    
    plt.figure(figsize=(9,6))
    
    n = 12
    X = np.arange(n)+1
    # numpy.random.uniform(low=0.0, high=1.0, size=None), normal
    Y1 = (1-X/float(n+1)) * np.random.uniform(0.5,1.0,n)
    Y2 = (1-X/float(n+1)) * np.random.uniform(0.5,1.0,n)
    
    # bar and barh
    width = 0.35
    plt.bar(X, Y1, width=width, facecolor='#9999ff', edgecolor='white')
    plt.bar(X+width, Y2, width=width, facecolor='#ff9999', edgecolor='white')
    plt.bar(X, -Y2, width=width, facecolor='#ff9999', edgecolor='white')
    
    # 柱状图添加说明文字
    for x,y in zip(X,Y1):
        plt.text(x, y+0.05, '%.2f' % y, ha='center', va= 'bottom')
        
    for x,y in zip(X,-Y2):
        plt.text(x+0.4, y-0.15, '%.2f' % y, ha='center', va= 'bottom')
    
    #plt.ylim(-1.25,+1.25)
    plt.show()
    

     

    import numpy as np
    from matplotlib import pyplot as plt
    
    plt.figure(figsize=(9,6))
    
    n = 12
    X = np.arange(n)+1
    # numpy.random.uniform(low=0.0, high=1.0, size=None), normal
    Y1 = (1-X/float(n+1)) * np.random.uniform(0.5,1.0,n)
    Y2 = (1-X/float(n+1)) * np.random.uniform(0.5,1.0,n)
    
    # bar and barh
    width = 0.35
    # 方法barh和参数height可以实现横向的柱状图
    plt.barh(X, Y1, height=width, facecolor='#9999ff', edgecolor='white')
    
    plt.show()
    

     

    概率分布图

    from matplotlib import pyplot as plt
    import numpy as np
    
    mu = 0
    sigma = 1
    x = mu + sigma*np.random.randn(10000)
    
    fig,(ax0,ax1)=plt.subplots(ncols=2, figsize=(9,6))
    
    ax0.hist(x, 20, normed=1, histtype='bar', facecolor='g', rwidth=0.8, alpha=0.75)
    ax0.set_title('pdf')
    # 累积概率密度分布
    ax1.hist(x, 20, normed=1, histtype='bar', rwidth=0.8, cumulative=True)
    ax1.set_title('cdf')
    
    plt.show()
    

     

    散点图

    atan2(a,b)是4象限反正切,它的取值不仅取决于正切值a/b,还取决于点 (b, a) 落入哪个象限: 当点(b, a) 落入第一象限时,atan2(a,b)的范围是 0 ~ pi/2;  当点(b, a) 落入第二象限时,atan2(a,b)的范围是 pi/2 ~ pi; 当点(b, a) 落入第三象限时,atan2(a,b)的范围是 -pi~-pi/2;  当点(b, a) 落入第四象限时,atan2(a,b)的范围是 -pi/2~0

    而 atan(a/b) 仅仅根据正切值为a/b求出对应的角度 (可以看作仅仅是2象限反正切): 当 a/b > 0 时,atan(a/b)取值范围是 0 ~ pi/2; 当 a/b < 0 时,atan(a/b)取值范围是 -pi/2~0

    故 atan2(a,b) = atan(a/b) 仅仅发生在 点 (b, a) 落入第一象限 (b>0, a>0)或 第四象限(b>0, a0 , 故 atan(a/b) 取值范围是 0 ~ pi/2,2atan(a/b) 的取值范围是 0 ~ pi,而此时atan2(a,b)的范围是 -pi~-pi/2,很显然,atan2(a,b) = 2atan(a/b)

    举个最简单的例子,a = 1, b = -1,则 atan(a/b) = atan(-1) = -pi/4, 而 atan2(a,b) = 3*pi/4

    from matplotlib import pyplot as plt
    import numpy as np
    
    plt.figure(figsize=(9,6))
    
    n = 1024
    
    # 均匀分布 高斯分布
    # rand 和 randn
    X = np.random.rand(1,n)
    Y = np.random.rand(1,n)
    
    # 设定颜色
    T = np.arctan2(Y,X)
    
    plt.scatter(X,Y, s=75, c=T, alpha=.4, marker='o')
    
    #plt.xlim(-1.5,1.5), plt.xticks([])
    #plt.ylim(-1.5,1.5), plt.yticks([])
    
    plt.show()
    

     

    不规则组合图

    # 定义子图区域
    left, width = 0.1, 0.65
    bottom, height = 0.1, 0.65
    bottom_h = left_h = left + width + 0.02

    rect_scatter = [left, bottom, width, height]
    rect_histx = [left, bottom_h, width, 0.2]
    rect_histy = [left_h, bottom, 0.2, height]

    plt.figure(1, figsize=(6, 6))

    # 需要传入[左边起始位置,下边起始位置,宽,高]
    # 根据子图区域来生成子图
    axScatter = plt.axes(rect_scatter)
    axHistx = plt.axes(rect_histx)
    axHisty = plt.axes(rect_histy)

    # ref : http://matplotlib.org/examples/pylab_examples/scatter_hist.html
    
    import numpy as np
    import matplotlib.pyplot as plt
    
    # the random data
    x = np.random.randn(1000)
    y = np.random.randn(1000)
    
    # 定义子图区域
    left, width = 0.1, 0.65
    bottom, height = 0.1, 0.65
    bottom_h = left_h = left + width + 0.02
    
    rect_scatter = [left, bottom, width, height]
    rect_histx = [left, bottom_h, width, 0.2]
    rect_histy = [left_h, bottom, 0.2, height]
    
    plt.figure(1, figsize=(6, 6))
    
    # 根据子图区域来生成子图
    axScatter = plt.axes(rect_scatter)
    axHistx = plt.axes(rect_histx)
    axHisty = plt.axes(rect_histy)
    
    # no labels
    #axHistx.xaxis.set_ticks([])
    #axHisty.yaxis.set_ticks([])
    
    # now determine nice limits by hand:
    N_bins=20
    xymax = np.max([np.max(np.fabs(x)), np.max(np.fabs(y))])
    binwidth = xymax/N_bins
    lim = (int(xymax/binwidth) + 1) * binwidth
    nlim = -lim
    
    # 画散点图,概率分布图
    axScatter.scatter(x, y)
    axScatter.set_xlim((nlim, lim))
    axScatter.set_ylim((nlim, lim))
    
    bins = np.arange(nlim, lim + binwidth, binwidth)
    axHistx.hist(x, bins=bins)
    axHisty.hist(y, bins=bins, orientation='horizontal')
    
    # 共享刻度
    axHistx.set_xlim(axScatter.get_xlim())
    axHisty.set_ylim(axScatter.get_ylim())
    
    plt.show()
    

     

    三维数据图

    使用散点图的点大小、颜色、透明度表示高维数据:

    import numpy as np
    import matplotlib.pyplot as plt
    
    fig = plt.figure(figsize=(9,6),facecolor='white')
    
    # Number of ring
    n = 50
    size_min = 50
    size_max = 50*50
    
    # Ring position
    P = np.random.rand(n,2)
    
    # Ring colors R,G,B,A
    C = np.ones((n,4)) * (0.5,0.5,0,1)
    # Alpha color channel goes from 0 (transparent) to 1 (opaque),很厉害的实现
    C[:,3] = np.linspace(0,1,n)
    
    # Ring sizes
    S = np.linspace(size_min, size_max, n)
    
    # Scatter plot
    plt.scatter(P[:,0], P[:,1], s=S, lw = 0.5,
                      edgecolors = C, facecolors=C)
    
    plt.xlim(0,1), plt.xticks([])
    plt.ylim(0,1), plt.yticks([])
    
    plt.show()
    

     

    美化

    # 美化matplotlib绘出的图,导入后自动美化
    import seaborn as sns
    
    # matplotlib自带美化风格
    # 打印可选风格
    print(plt.style.available #ggplot, bmh, dark_background, fivethirtyeight, grayscale)
    # 激活风格
    plt.style.use('bmh')
    

    一维颜色填充 & 三维绘图 & 三维等高线图

    『Python』Numpy学习指南第九章_使用Matplotlib绘图

    from mpl_toolkits.mplot3d import Axes3D

    ax = fig.add_subplot(111,projection='3d')

    ax.plot() 绘制3维线

    ax.plot_surface绘制三维网格(面)

    from mpl_toolkits.mplot3d import Axes3D   #<-----导入3D包
    import numpy as np
    import matplotlib.pyplot as plt
    
    fig = plt.figure(figsize=(9,6))
    ax = fig.add_subplot(111,projection='3d') #<-----设置3D模式子图
    
    # 新思路,之前都是生成x和y绘制z=f(x,y)的函数,这次绘制x=f1(z),y=f2(z) z = np.linspace(0, 6, 1000) r = 1 x = r * np.sin(np.pi*2*z) y = r * np.cos(np.pi*2*z) ax.plot(x, y, z, label=u'螺旋线', c='r') ax.legend() # dpi每英寸长度的点数 plt.savefig('3d_fig.png',dpi=200) plt.show()

     

     # ax.plot 绘制的是3维线,ax.plot_surface绘制的是三维网格(也就是面)

    from mpl_toolkits.mplot3d import axes3d
    import matplotlib.pyplot as plt
    from matplotlib import cm
    
    fig = plt.figure()
    ax = fig.add_subplot(111,projection='3d')
    X, Y, Z = axes3d.get_test_data(0.05)
    print(X,Y,Z)
    # ax.plot 绘制的是3维线,ax.plot_surface绘制的是三维网格(也就是面)
    ax.plot_surface(X, Y, Z, rstride=5, cstride=5, alpha=0.3)
    # 三维图投影制作,zdir选择投影方向坐标轴
    cset = ax.contour(X, Y, Z, 10, zdir='z', offset=-100, cmap=cm.coolwarm)
    cset = ax.contour(X, Y, Z, zdir='x', offset=-40, cmap=cm.coolwarm)
    cset = ax.contour(X, Y, Z, zdir='y', offset=40, cmap=cm.coolwarm)
    
    ax.set_xlabel('X')
    ax.set_xlim(-40, 40)
    ax.set_ylabel('Y')
    ax.set_ylim(-40, 40)
    ax.set_zlabel('Z')
    ax.set_zlim(-100, 100)
    
    plt.show()
    

     # 为等高线图添加标注

    cs = ax2.contour(X,Y,Z)
    ax2.clabel(cs, inline=1, fontsize=5)
    

     

    配置Colorbar

    # -*- coding: utf-8 -*-  
    #**********************************************************  
    import os  
    import numpy as np  
    import wlab #pip install wlab  
    import matplotlib  
    import matplotlib.cm as cm  
    import matplotlib.pyplot as plt  
    from matplotlib.ticker import MultipleLocator  
    from scipy.interpolate import griddata  
    matplotlib.rcParams['xtick.direction'] = 'out'  
    matplotlib.rcParams['ytick.direction'] = 'out'  
    #**********************************************************  
    FreqPLUS=['F06925','F10650','F23800','F18700','F36500','F89000']  
    #  
    FindPath='/d3/MWRT/R20130805/'  
    #**********************************************************  
    fig = plt.figure(figsize=(8,6), dpi=72, facecolor="white")  
    axes = plt.subplot(111)  
    axes.cla()#清空坐标轴内的所有内容  
    #指定图形的字体  
    font = {'family' : 'serif',  
            'color'  : 'darkred',  
            'weight' : 'normal',  
            'size'   : 16,  
            }  
    #**********************************************************  
    # 查找目录总文件名中保护F06925,EMS和txt字符的文件  
    for fp in FreqPLUS:  
        FlagStr=[fp,'EMS','txt']  
        FileList=wlab.GetFileList(FindPath,FlagStr)  
        #  
        LST=[]#地表温度  
        EMS=[]#地表发射率  
        TBH=[]#水平极化亮温  
        TBV=[]#垂直极化亮温  
        #  
        findex=0  
        for fn in FileList:  
            findex=findex+1  
            if (os.path.isfile(fn)):  
                print(str(findex)+'-->'+fn)  
                #fn='/d3/MWRT/R20130805/F06925_EMS60.txt'  
                data=wlab.dlmread(fn)  
                EMS=EMS+list(data[:,1])#地表发射率  
                LST=LST+list(data[:,2])#温度  
                TBH=TBH+list(data[:,8])#水平亮温  
                TBV=TBV+list(data[:,9])#垂直亮温  
        #-----------------------------------------------------------  
        #生成格点数据,利用griddata插值  
        grid_x, grid_y = np.mgrid[275:315:1, 0.60:0.95:0.01]  
        grid_z = griddata((LST,EMS), TBH, (grid_x, grid_y), method='cubic')  
        #将横纵坐标都映射到(0,1)的范围内  
        extent=(0,1,0,1)  
         #指定colormap  
        cmap = matplotlib.cm.jet  
        #设定每个图的colormap和colorbar所表示范围是一样的,即归一化  
        norm = matplotlib.colors.Normalize(vmin=160, vmax=300)  
        #显示图形,此处没有使用contourf #>>>ctf=plt.contourf(grid_x,grid_y,grid_z)  
        gci=plt.imshow(grid_z.T, extent=extent, origin='lower',cmap=cmap, norm=norm)  
        #配置一下坐标刻度等  
        ax=plt.gca()  
        ax.set_xticks(np.linspace(0,1,9))  
        ax.set_xticklabels( ('275', '280', '285', '290', '295',  '300',  '305',  '310', '315'))  
        ax.set_yticks(np.linspace(0,1,8))  
        ax.set_yticklabels( ('0.60', '0.65', '0.70', '0.75', '0.80','0.85','0.90','0.95'))  
        #显示colorbar  
        cbar = plt.colorbar(gci)  
        cbar.set_label('$T_B(K)$',fontdict=font)  
        cbar.set_ticks(np.linspace(160,300,8))  
        cbar.set_ticklabels( ('160', '180', '200', '220', '240',  '260',  '280',  '300'))  
        #设置label  
        ax.set_ylabel('Land Surface Emissivity',fontdict=font)  
        ax.set_xlabel('Land Surface Temperature(K)',fontdict=font) #陆地地表温度LST  
        #设置title  
        titleStr='$T_B$ for Freq = '+str(float(fp[1:-1])*0.01)+'GHz'  
        plt.title(titleStr)  
        figname=fp+'.png'  
        plt.savefig(figname)  
        plt.clf()#清除图形  
      
    #plt.show()  
    print('ALL -> Finished OK') 
    

    上面的例子中,每个保存的图,都是用同样的colormap,并且每个图的颜色映射值都是一样的,也就是说第一个图中如果200表示蓝色,那么其他图中的200也表示蓝色。

    示例的图形如下:

  • 相关阅读:
    Objects类源码详解(基于jdk1.8.0_261)
    Object类源码详解(基于jdk1.8.0_261)
    Collections工具类源码详解(基于jdk1.8.0_261)
    版本控制神器——git的基本使用
    数据结构练习1~插入排序~
    求指错啊急是求幂的
    编完了个代码大家给看看还能不能精简
    关于KMP算法
    有网友建议写一个新手指南或者FAQ一类的置顶你们认为呢
    c语言新手编程错误求解
  • 原文地址:https://www.cnblogs.com/hellcat/p/7070548.html
Copyright © 2011-2022 走看看