matplotlib画图时标注最大值

背景

在上一篇使用matplotlib绘制时间序列图表中,本来想只展示最大值,一直没找到方法,就先标注了所有的点的数值,看起来有点不够直接。今天终于搞定了,记录一下。

思路

源数据:index 为 ‘data’,数据为’title’

1
2
3
4
5
6
7
8
9
cacu.head(5)
Out[5]:
title
date
2015-01-01 2
2015-02-01 0
2015-03-01 0
2015-04-01 0
2015-05-01 2
  • matpoltlib标注数值

    在绘图的时候,可以使用ax.text()方法在坐标系中标注文字,使用方法如下:

    1
    2
    3
    # 显示全部数值
    for a,b in zip(cacu.index, cacu.values):
    ax.text(a, b, b[0])
  • 寻找最大值:

    在pandas中有现成的方法可以找到最大值和最大值的索引:

    最大值的索引:

    1
    2
    3
    4
    cacu.idxmax()
    Out[6]:
    title 2018-07-01
    dtype: datetime64[ns]

    最大值:

    1
    2
    3
    4
    cacu.max()
    Out[8]:
    title 50
    dtype: int64

    也可根据索引取值:

    1
    2
    3
    4
    5
    cacu.loc[cacu.idxmax()]
    Out[7]:
    title
    date
    2018-07-01 50
  • 画图标注

    根据最上面的标注,应该直接输入最大值的坐标(x为索引,y为值)就可以了,结果有了如下的报错:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    ax.text(cacu.idxmax(), cacu.max(), cacu.max())
    /Users/zhengk/PycharmProjects/web_scraping_and_data_analysis/venv/lib/python3.7/site-packages/pandas/core/ops.py:1649: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
    result = method(y)
    Traceback (most recent call last):
    File "/Users/zhengk/PycharmProjects/web_scraping_and_data_analysis/venv/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3291, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
    File "<ipython-input-9-cebfed8d464d>", line 1, in <module>
    ax.text(cacu.idxmax(), cacu.max(), cacu.max())
    File "/Users/zhengk/PycharmProjects/web_scraping_and_data_analysis/venv/lib/python3.7/site-packages/matplotlib/axes/_axes.py", line 722, in text
    x=x, y=y, text=s)
    File "/Users/zhengk/PycharmProjects/web_scraping_and_data_analysis/venv/lib/python3.7/site-packages/matplotlib/text.py", line 163, in __init__
    self.set_text(text)
    File "/Users/zhengk/PycharmProjects/web_scraping_and_data_analysis/venv/lib/python3.7/site-packages/matplotlib/text.py", line 1191, in set_text
    if s != self._text:
    File "/Users/zhengk/PycharmProjects/web_scraping_and_data_analysis/venv/lib/python3.7/site-packages/pandas/core/generic.py", line 1479, in __nonzero__
    .format(self.__class__.__name__))
    ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

    我们仔细看上面最大值的返回结果类型,而并非一个坐标。

    1
    2
    type(cacu.idxmax())
    Out[11]: pandas.core.series.Series

    而我们真正需要的应该是title列的最大索引:

    1
    2
    3
    4
    type(cacu['title'].idxmax())
    Out[12]: pandas._libs.tslibs.timestamps.Timestamp
    cacu['title'].idxmax()
    Out[13]: Timestamp('2018-07-01 00:00:00', freq='MS')

    对应的最大值也一样:

    1
    2
    3
    4
    cacu['title'].max()
    Out[15]: 50
    type(cacu['title'].max())
    Out[16]: numpy.int64

    再次画图:

    1
    2
    3
    x = cacu['title'].idxmax()
    y = cacu['title'].max()
    ax.text(x, y, y, verticalalignment='bottom', horizontalalignment='center', fontsize='large')
  • 结果

    plot

结论

这里出现问题其实还是对matplotlib和pandas的基本概念没有弄明白,什么时候获取的是值,什么时候获取的是序列,还需要多加练习。

另外,给图添加标注还有可以使用plt.annotate()方法:

1
2
3
x = cacu['title'].idxmax()
y = cacu['title'].max()
plt.annotate(y, xy=(x,y))

完整代码参考:https://github.com/keejo125/web_scraping_and_data_analysis/tree/master/weixin