Matplotlib 实战:写一个任意函数极值可视化脚手架

办公安全微服务治理关系型数据库

picture.image

作者:月小水长,Java、Python、Android coder。

Matplotlib简介

Matplotlib 是 Python 从 Matlab 迁移过来的一个 2D 绘图库,它可以在各种平台上以各种硬拷贝格式和交互式环境生成出具有出版品质的图形,通过几行代码,就能开发出直方图、饼状图、散点图、三维图等各式各样的专业图表,具有极强的自定义性和可扩展性。下面是 Matplotlib 官网 的几个示例图表:

picture.image

picture.image

同时由于 Matplotlib 是基于 NumPy (一个科学计算包)和 tkinter (一个图形框架) 二次开发的,Matplotlib 在科学计算结果可视化领域越来越受到欢迎。

Matplotlib组成

  • figure:整个画布,包含一个或多个 axes

  • axes:画布中的某一个图表,包含一个 plot

  • artist:元素,包括图中所示的 label、line 等,也包括 plot

不得不说的 backend

backend 是为Matplotlib中的绘图功能做幕后工作的,对应的 frontend 指的就是你编辑的绘图命令。通过设置 backend 可以使得 Matplotlib 适应不同的应用场景,或者说输出形式,例如:Python 中的命令行模式下弹出的figure,图形界面的工具 wxPython中 嵌入的 Matplotlib,网页应用服务,批处理脚本生成可视化数据等。

backend 可以分为两类:交互式的,包括命令行以及图形界面的集成开发环境;非交互式的,比如输出图片文件(格式为 PNG,JPG,PDF等)的。

常见的 backend 类型:

不可交互型可交互型
AGG:渲染为 png 文件Qt5Agg:使用 Qt5 渲染,IPython 中可使用 %matplotlib qt5
PS:渲染为 ps 文件macosx:使用 Cocoa 画布渲染,Ipython 中可使用 %matplotlib osx
PDF:渲染为 pdf 文件nbAgg:Jupyter Notebook 中使用的 backend,Jupyter 中使用 %matplotlib notebook 来激活
SVG:渲染为 svg 文件WXAgg:使用 wxWidgets 库来渲染,Ipython 中可使用 %matplotlib wx

假如我们要激活 WXAgg 渲染模式,可以使用

import matplotlib
matplotlib.use('WXAgg')

注意激活语句最后紧跟着导入语句,中间不能有 plt.plot() 之类的绘图语句

Matplotlib基本用法

由于Matplotlib是第三方库,请先确保你的电脑上已经安装成功 Matplotlib 库;

一般有下面两种办法:

  1. 在命令行下输入: pip install matplotlib
  2. 通过下载whl文件安装,可以参考:

https://blog.csdn.net/ygdxt/article/details/80517024

导入

根据开源社区的习惯,一般这样导入

import matplotlib.pyplot as plt

创建画布

plt.figure()

如果在 plt.figure() 后直接 plt.show(),将弹出一个空白图表的画布窗口

具体绘图

Matplotlib 的绘图是面向过程的,具体的绘图操作差不多都在这一步完成,比如我想在一个子图中绘制出 sin(x) 和 cos(x) ,控制代码如下:


          
              

            x = np.arange(0,np.pi*2,0.01)  
y1 = np.sin(x)  
y2 = np.cos(x)  
#下面两句代码可以简化为一句代码:  
#plt.plot(x,y1,x,y2)  
plt.plot(x,y1)  
plt.plot(x,y2)  

          
        

plt.show() 之后,其效果图如下:

picture.image

plot() 函数只是 Matplotlib 库中最简单的绘图函数,除了横坐标x、纵坐标y外,它还可以通过关键字参数 c (color) 控制线条的颜色,比如 plt.plot(x,y1,c="y") 可以使上图中曲线 sin(x) 的颜色变成黄色,通过关键字参数 s (size) 控制线条的粗细等,有具体需求的时候可以查对应的的 API 手册。

pyplot 模块中其他一些重要的绘制函数列表如下:

名称功能
plt.hist()画直方图
plt.scatter()画散点图
plt.bar()画柱形图
plt.annotate()给图像加注释

注:绘图部分由于 API 过多,在此仅列出基础函数,后面我会视情况专门出一个针对此部分的教程

显示

plt.show()

将整个画布以及上面的子图显示出来。

用 Matplotlib 解决一个实际问题

假设我们现在要解决一个需求

求任意多项式函数的极值并将计算结果可视化

全部代码

Tips:听说看代码时认真看注释,效果更好哦。


          
              

            # -*- coding: utf-8 -*-  
# author:           inspurer(月小水长)  
# pc\_type           lenovo  
# create\_time:      2019/5/26 13:19  
# file\_name:        my\_differ.py  
# github            https://github.com/inspurer  
# 微信公众号         月小水长(ID: inspurer)  
  
  
from sympy import *  
import numpy as np  
import matplotlib.pyplot as plt  
import mpl\_toolkits.axisartist as axisartist  
  
  
def count\_extreme(args):  
    # 声明符号 x  
    sign\_x = Symbol("x")  
    # 声明 y 符号表达式  
    sign\_y = 0  
    # 数值 x  
    num\_x = np.arange(-5,5,0.01)  
    # print(num\_x,num\_x.shape)  
    # num\_y = np.zeros((1,len(num\_x)))  
    num\_y = np.zeros(len(num\_x))  
    # print(num\_y, num\_x.shape)  
    for item in args:  
        sign\_y += item[0]*sign\_x**item[1]  
        num\_y += item[0]*num\_x**item[1]  
    # y 对 x 求导  
    dy = diff(sign\_y,sign\_x)  
    # 返回导函数的零点  
    extreme\_x\_list = solve(dy,sign\_x)  
    if len(extreme\_x\_list)==0:  
        return "no extrem vaule"  
    print(extreme\_x\_list)  
    # 声明定义域  
    fig = plt.figure()  
    # 使用axisartist.Subplot方法创建一个绘图区对象ax  
    ax = axisartist.Subplot(fig, 111)  
    # 将绘图区对象添加到画布中  
    fig.add\_axes(ax)  
  
    ## 引入 axisartist 会再次造成乱码,可以通过annotate解决  
    plt.annotate('X轴', xy=(max(num\_x),0), xycoords='data',xytext=(0,5),  
                 textcoords='offset points', fontsize=16, fontproperties='SimHei')  
    plt.annotate('Y轴', xy=(0,max(num\_y)), xycoords='data',xytext=(5,0),  
                 textcoords='offset points', fontsize=16, fontproperties='SimHei')  
    # plt.xlabel("X轴",fontproperties='SimHei',fontsize=14)  
    # # 标签里面必须添加字体变量:fontproperties='SimHei',fontsize=14。不然中文显示可能会乱码  
    # plt.ylabel("Y轴",fontproperties='SimHei',fontsize=14)  
    # sympy 转成 str  
    plt.title(str(sign\_y))  
    plt.plot(num\_x,num\_y)  
    for i,extreme\_x in enumerate(extreme\_x\_list):  
        extreme\_y = sign\_y.evalf(subs={sign\_x:extreme\_x})  
        # if the slove is not real  
        # the class is sympy,core.numbers.Zero  
        if (isinstance(extreme\_y,numbers.Zero)):  
            return "extreme value is not real"  
        p = plt.scatter(extreme\_x,extreme\_y,s=50,c="red")  
        #  xytext -- 为注解内容位置坐标,当该值为None时,注解内容放置在xy处  
        #  xycoords and textcoords 是坐标xy与xytext的说明,若textcoords=None,则默认textNone与xycoords相同,  
        #  若都未设置,默认为data,  
        #  arrowprops 用于设置箭头的形状,类型为字典类型  
        plt.annotate('y(%.6s)=%.6s ' % (extreme\_x,extreme\_y), xy=(extreme\_x, extreme\_y), xycoords='data', xytext=((-1)**(i+1)*30, (-1)**(i+1)*30),  
                     textcoords='offset points', fontsize=16,fontproperties='SimHei',  
                     arrowprops=dict(arrowstyle='->', connectionstyle="arc3,rad=.2"))  
  
        plt.legend(handles=[p], labels=['points of extreme value'],loc='best')  
  
        # 通过set\_visible方法设置绘图区所有坐标轴隐藏  
        ax.axis[:].set\_visible(False)  
  
        #ax.new\_floating\_axis代表添加新的坐标轴  
        ax.axis["x"] = ax.new\_floating\_axis(0, 0)  
  
        #给x坐标轴加上箭头  
        ax.axis["x"].set\_axisline\_style("->", size=1.0)  
        #添加y坐标轴,且加上箭头  
        ax.axis["y"] = ax.new\_floating\_axis(1, 0)  
        ax.axis["y"].set\_axisline\_style("-|>", size=1.0)  
        #设置x、y轴上刻度显示方向  
  
        ax.axis["x"].set\_axis\_direction("top")  
        ax.axis["y"].set\_axis\_direction("right")  
  
        # 我们先把原始的如上图的所有坐标轴隐藏,即长方形的四个边。  
        #  
        # 然后用ax.new\_floating\_axis在绘图区添加坐标轴x、y,这里的ax.new\_floating\_axis(0, 0),第一个0代表平行直线,第二个0代表该直线经过0点。同样,ax.axis[  
        #     "y"] = ax.new\_floating\_axis(1, 0),则代表竖直曲线且经过0点。  
        #  
        # 再次,x.axis["x"].set\_axisline\_style("->", size=1.0)  
        # 表示给x轴加上箭头,"->"  
        # 表示是空箭头,size = 1.0  
        # 表示箭头大小。ax.axis["y"].set\_axisline\_style("-|>", size=1.0)  
        # 中  
        # "-|>"  
        # 则是实心箭头。  
        #  
        # 最后,设置x、y轴上刻度显示方向,对于x轴是刻度标签在上面还是下面,y轴则是刻度标签在左边还是右边。  
  
    plt.grid(True)  
    plt.grid(color='black', linestyle='--')  # 修改网格颜色,类型为虚线,网格是跟坐标刻度来的  
    plt.show()  
  
  
if \_\_name\_\_ == "\_\_main\_\_":  
    # examples  
    # wanted: 1/3*x**3-3/2*x**2+2*x  
    # args: [(1/3,3),(-3/2,2),(2,1)]  
    print(count\_extreme([(1/3,3),(-3/2,2),(2,1)]))  

          
        

函数计算用到了第三方库 sympy ,感兴趣的同学可以先学习,有不懂的地方可以通过留言;否则可以忽略,我们的注意力放在绘图部分

其中函数表达式是以 y = 1/3*x**3-3/2*x**2+2*x 为例的,

只需在代码的最后一行按照格式修改即可

可视化结果

picture.image

如此一来,当我们想快速查看一个复杂函数时的变化趋势时,不需要写任何绘图代码就能快速绘图,只需要将函数表达式按照上述格式写出即可,而且可以一眼看出函数的极值点和极值,下一步的工作就是把最值,函数凹凸性功能实现。

picture.image

▼ 点击成为 社区注册会员 「在看」 一下,一起PY!

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
字节跳动客户端性能优化最佳实践
在用户日益增长、需求不断迭代的背景下,如何保证 APP 发布的稳定性和用户良好的使用体验?本次分享将结合字节跳动内部应用的实践案例,介绍应用性能优化的更多方向,以及 APM 团队对应用性能监控建设的探索和思考。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论