matplotlib易混概念理解与画图详解

0. 前言

最近因为项目进度,需要使用matplotlib画图。等真正动手画图的时候,突然发现虽然使用matplotlib时间也不短了,但是认知好像还不是很清晰很全面。每次需要调一下格式,改变一下坐标轴形式什么的,都需要重新google搜索。离开了google感觉完全画不来图,效率也低,俗称的面向google编程。痛定思痛,等项目需求满足完,图画完以后,决心抽出时间来,好好整理一下matplotlib的相关知识点。

1.figure, axes, axis

很多同学,包括我自己,最初画图,都是从plt.figure(), plt.plot()这种方式开始的。但是这种方式,只是matplotlib提供了的一个api,如果想要画出更漂亮,更细致的图,这种方式可能就没法达到目的。

同时,在google的过程中,我们经常会发现matplotlib里面包含各种元素,像什么figure,axes,axis等等出现频率很高,而且实现的方式多种多样。综合自己的使用体验,感觉大家为什么开始阶段会对matplotlib迷茫,主要是对figure,axes,axis等这些概念理解不清楚。要对matplotlib理解清楚,首先需要从根本上理解清楚这些概念。

matplotlib官方文档

上面为官网地址,从官网上面先截一张图,通过这张图首先可以看得比较清晰。
在这里插入图片描述

上面这张图比较清晰的描述了matplotlib中的几个关键元素。

Figure
The whole figure (marked as the outer red box). 
The figure keeps track of all the child Axes,
a smattering of ‘special’ artists (titles, figure legends, etc), 
and the canvas. 
(Don’t worry too much about the canvas,
 it is crucial as it is the object that actually does the drawing to get you your plot, 
but as the user it is more-or-less invisible to you). 
A figure can have any number of Axes, but to be useful should have at least one.

通过上面的描述,我们可以对figure元素下个简单定义:
figure是图中的红色区域,可以简单认为就是整个画布。画图的第一件事就是创建一个figure,然后基于该figure做各种操作。

Axes
This is what you think of as ‘a plot’,
it is the region of the image with the data space (marked as the inner blue box).
A given figure can contain many Axes, 
but a given Axes object can only be in one Figure.
The Axes contains two (or three in the case of 3D) Axis objects
(be aware of the difference between Axes and Axis) 
which take care of the data limits (the data limits can also be controlled via set via the set_xlim() and set_ylim() Axes methods).
Each Axes has a title (set via set_title()), an x-label (set via set_xlabel()), and a y-label set via set_ylabel()).

Axes这个名称很误导人,尤其容易与Axis混淆,文档里也提到了这点,但是这段文档的解释很精彩,把上面这段话看明白基本就明白了matplotlib中的大部分逻辑。

1.axes是你认为的’a plot’,图中的蓝色部分。换句话说,axes才是真正的图片内容。
2.一个figure里面可以包含多个axes,但是一个axes只能在一个figure中。
3.特别提示,Axes与Axis的不同。
4.数据范围的限制可以通过Axes中set_xlim与set_ylim方法。
5.每个Axes可以通过set_title设置一个title,通过set_xlabel与set_ylabel设置xlabel与ylabel。

Axis
These are the number-line-like objects (circled in green).
They take care of setting the graph limits and generating the ticks
(the marks on the axis)
and ticklabels (strings labeling the ticks).
The location of the ticks is determined by a Locator object and
the ticklabel strings are formatted by a Formatter.
The combination of the correct Locator and Formatter
gives very fine control over the tick locations and labels.

1.Axis是图中的绿色区域,是坐标轴的部分。
2.Axis可以控制图片的范围并生成ticks, ticks是axis上的标识。
3.ticks的位置是由Locator对象决定,格式由Formatter对象决定。
4.通过合适的Locator对象与Formatter对象,可以对tick的位置与样式进行很好的控制。

2.比较合理的画图方式

通过第一部分的分析,比较合理的画图可以为下面这种:

 fig, axes = plt.subplot()
def subplots(nrows=1, ncols=1, sharex=False, sharey=False, squeeze=True,
             subplot_kw=None, gridspec_kw=None, **fig_kw):
    """
    Create a figure and a set of subplots.

    This utility wrapper makes it convenient to create common layouts of
    subplots, including the enclosing figure object, in a single call.

    Parameters
    ----------
    nrows, ncols : int, optional, default: 1
        Number of rows/columns of the subplot grid.
 ......

通过subplots的源码注释不难看出,该方法Create a figure and a set of subplots.。产生的fig,axes就是我们上面提到的figure与axes,我们可以通过调整没一个axes来达到精细化画图的目的。

3.每个Axes中的元素

前面提到,我们得到Axes以后,就可以针对Axes对象开始调整各种元素画图。下面再通过官方文档里的一张图,可以了解Axes里面到底包含那些内容。

Matplotlib Basic Usage

在这里插入图片描述
图中的元素,包含有常用的line, grid, legend, markers, tick, title等等,画图的过程,实际上就是对这些元素调整优化的过程,下面我们可以来进行实验。

4.逐步优化画图

首先我们用subplots画个最基本的图

def plot_data():
    import matplotlib.pyplot as plt
    import numpy as np
    fig, axes = plt.subplots(2, 1)


    y1 = np.random.randint(100, 110, 10)
    y2 = np.random.uniform(0.3, 0.6, 10)

    dates = np.arange(20211201, 20211211)
    axes[0].plot(dates, y1)
    axes[1].plot(dates, y2)

    plt.show()

上面的图,包含两幅子图,横坐标为dates,纵坐标分别为y1, y2。
图片效果如下

在这里插入图片描述

上面的图很明显各种问题
1.坐标轴被遮挡。
2.横坐标自动使用了科学计数法。

首先我们解决这两个问题,并加上标题。

def plot_data():
    import matplotlib.pyplot as plt
    import numpy as np
    fig, axes = plt.subplots(2, 1)


    y1 = np.random.randint(100, 110, 10)
    y2 = np.random.uniform(0.3, 0.6, 10)

    dates = np.arange(20211201, 20211211)
    axes[0].plot(dates, y1)
    axes[1].plot(dates, y2)

    # 设置tick的格式为plain
    axes[0].ticklabel_format(useOffset=False, style='plain')
    axes[1].ticklabel_format(useOffset=False, style='plain')

    # 设置标题
    axes[0].set_title("uv num")
    axes[1].set_title("ctr num")

    # 自动排版,让标题,坐标轴不遮挡
    fig.tight_layout()
    plt.show()

在这里插入图片描述
上面的图,x坐标的数字显示不全,我们先把所有的数字都显示出来

def plot_data():
    import matplotlib.pyplot as plt
    import numpy as np
    fig, axes = plt.subplots(2, 1)


    y1 = np.random.randint(100, 110, 10)
    y2 = np.random.uniform(0.3, 0.6, 10)

    dates = np.arange(20211201, 20211211)
    axes[0].plot(dates, y1)
    axes[1].plot(dates, y2)

    # 设置tick的格式为plain
    axes[0].ticklabel_format(useOffset=False, style='plain')
    axes[1].ticklabel_format(useOffset=False, style='plain')

    # 把所有ticks都显示
    axes[0].set_xticks(dates)
    axes[1].set_xticks(dates)

    # 设置标题
    axes[0].set_title("uv num")
    axes[1].set_title("ctr num")

    # 自动排版,让标题,坐标轴不遮挡
    fig.tight_layout()
    plt.show()

在这里插入图片描述
这个时候坐标重叠了,需要修改一下ticks样式

def plot_data():
    import matplotlib.pyplot as plt
    import numpy as np
    fig, axes = plt.subplots(2, 1)

    y1 = np.random.randint(100, 110, 10)
    y2 = np.random.uniform(0.3, 0.6, 10)

    dates = np.arange(20211201, 20211211)
    axes[0].plot(dates, y1)
    axes[1].plot(dates, y2)

    # 设置tick的格式为plain
    axes[0].ticklabel_format(useOffset=False, style='plain')
    axes[1].ticklabel_format(useOffset=False, style='plain')

    # 把所有ticks都显示
    axes[0].set_xticks(dates)
    axes[1].set_xticks(dates)

    # ticks旋转60度
    axes[0].tick_params(axis='x', labelsize='small', rotation=60)
    axes[1].tick_params(axis='x', labelsize='small', rotation=60)



    # 设置标题
    axes[0].set_title("uv num")
    axes[1].set_title("ctr num")

    # 自动排版,让标题,坐标轴不遮挡
    fig.tight_layout()
    plt.show()

在这里插入图片描述

我们希望对每个点做上标记,并对点,线的格式进行设置

def plot_data():
    import matplotlib.pyplot as plt
    import numpy as np
    fig, axes = plt.subplots(2, 1)

    y1 = np.random.randint(100, 110, 10)
    y2 = np.random.uniform(0.3, 0.6, 10)

    dates = np.arange(20211201, 20211211)
    #显示每个数据点
    axes[0].plot(dates, y1, color="b", linewidth=1.0, marker="o", markerfacecolor='r', markersize = 4)
    axes[1].plot(dates, y2, color="b", linewidth=1.0, marker="o", markerfacecolor='r', markersize = 4)

    # 设置tick的格式为plain
    axes[0].ticklabel_format(useOffset=False, style='plain')
    axes[1].ticklabel_format(useOffset=False, style='plain')

    # 把所有ticks都显示
    axes[0].set_xticks(dates)
    axes[1].set_xticks(dates)

    # ticks旋转60度
    axes[0].tick_params(axis='x', labelsize='small', rotation=60)
    axes[1].tick_params(axis='x', labelsize='small', rotation=60)


    # 设置标题
    axes[0].set_title("uv num")
    axes[1].set_title("ctr num")

    # 自动排版,让标题,坐标轴不遮挡
    fig.tight_layout()
    plt.show()

在这里插入图片描述
再给图片加上网格线

def plot_data():
    import matplotlib.pyplot as plt
    import numpy as np
    fig, axes = plt.subplots(2, 1)

    y1 = np.random.randint(100, 110, 10)
    y2 = np.random.uniform(0.3, 0.6, 10)

    dates = np.arange(20211201, 20211211)
    #显示每个数据点
    axes[0].plot(dates, y1, color="b", linewidth=1.0, marker="o", markerfacecolor='r', markersize = 4)
    axes[1].plot(dates, y2, color="b", linewidth=1.0, marker="o", markerfacecolor='r', markersize = 4)

    # 设置tick的格式为plain
    axes[0].ticklabel_format(useOffset=False, style='plain')
    axes[1].ticklabel_format(useOffset=False, style='plain')

    # 把所有ticks都显示
    axes[0].set_xticks(dates)
    axes[1].set_xticks(dates)

    # ticks旋转60度
    axes[0].tick_params(axis='x', labelsize='small', rotation=60)
    axes[1].tick_params(axis='x', labelsize='small', rotation=60)
    
    # 网格线
    axes[0].grid(which='major', axis='x', linewidth=0.75, linestyle='-', color='0.75')
    axes[0].grid(which='minor', axis='x', linewidth=0.25, linestyle='-', color='0.75')
    axes[0].grid(which='major', axis='y', linewidth=0.75, linestyle='-', color='0.75')
    axes[0].grid(which='minor', axis='y', linewidth=0.25, linestyle='-', color='0.75')

    axes[1].grid(which='major', axis='x', linewidth=0.75, linestyle='-', color='0.75')
    axes[1].grid(which='minor', axis='x', linewidth=0.25, linestyle='-', color='0.75')
    axes[1].grid(which='major', axis='y', linewidth=0.75, linestyle='-', color='0.75')
    axes[1].grid(which='minor', axis='y', linewidth=0.25, linestyle='-', color='0.75')

    # 设置标题
    axes[0].set_title("uv num")
    axes[1].set_title("ctr num")

    # 自动排版,让标题,坐标轴不遮挡
    fig.tight_layout()
    plt.show()

在这里插入图片描述
基本上,想要针对那个元素优化,参考Basic Usage图中对应的位置,设置相应的参数即可。

5.坐标轴显示指定时间格式

def plot_data():
    import matplotlib.pyplot as plt
    import matplotlib.dates as mdates
    import numpy as np
    from datetime import datetime
    
    fig, axes = plt.subplots(2, 1)

    y1 = np.random.randint(100, 110, 10)
    y2 = np.random.uniform(0.3, 0.6, 10)

    dates = np.arange(20211201, 20211211)
    dates = [str(i) for i in dates]

    xs = [datetime.strptime(d, "%Y%m%d").date() for d in dates]

    # 把所有ticks都显示
    axes[0].set_xticks(xs)
    axes[1].set_xticks(xs)

    # ticks旋转60度
    axes[0].tick_params(axis='x', labelsize='small', rotation=60)
    axes[1].tick_params(axis='x', labelsize='small', rotation=60)

    axes[0].grid(which='major', axis='x', linewidth=0.75, linestyle='-', color='0.75')
    axes[0].grid(which='minor', axis='x', linewidth=0.25, linestyle='-', color='0.75')
    axes[0].grid(which='major', axis='y', linewidth=0.75, linestyle='-', color='0.75')
    axes[0].grid(which='minor', axis='y', linewidth=0.25, linestyle='-', color='0.75')

    axes[1].grid(which='major', axis='x', linewidth=0.75, linestyle='-', color='0.75')
    axes[1].grid(which='minor', axis='x', linewidth=0.25, linestyle='-', color='0.75')
    axes[1].grid(which='major', axis='y', linewidth=0.75, linestyle='-', color='0.75')
    axes[1].grid(which='minor', axis='y', linewidth=0.25, linestyle='-', color='0.75')

    # 将横坐标按指定日期格式显示
    axes[0].xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
    axes[1].xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))

    # 设置标题
    axes[0].set_title("uv num")
    axes[1].set_title("ctr num")

    axes[0].plot(xs, y1, color="b", linewidth=1.0, marker="o", markerfacecolor='r', markersize = 4)
    axes[1].plot(xs, y2, color="b", linewidth=1.0, marker="o", markerfacecolor='r', markersize = 4)



    # 自动排版,让标题,坐标轴不遮挡
    fig.tight_layout()
    plt.show()

在这里插入图片描述

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值