前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Matplotlib 实战:写一个任意函数极值可视化脚手架

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

作者头像
月小水长
发布2019-07-30 14:53:18
1.2K0
发布2019-07-30 14:53:18
举报
文章被收录于专栏:月小水长月小水长

Matplotlib简介

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

同时由于 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) ,控制代码如下:

代码语言:javascript
复制
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() 之后,其效果图如下:

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:听说看代码时认真看注释,效果更好哦。

代码语言:javascript
复制
# -*- 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 为例的,只需在代码的最后一行按照格式修改即可

可视化结果

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-06-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 月小水长 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 不得不说的 backend
  • 导入
  • 创建画布
  • 具体绘图
  • 显示
  • 函数计算用到了第三方库 sympy ,感兴趣的同学可以先学习,有不懂的地方可以通过留言;否则可以忽略,我们的注意力放在绘图部分
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档