如何在pyplot中自动注释最大值

Posted

技术标签:

【中文标题】如何在pyplot中自动注释最大值【英文标题】:How to automatically annotate maximum value in pyplot 【发布时间】:2017-09-08 13:15:00 【问题描述】:

我试图弄清楚如何在图形窗口中自动注释最大值。我知道您可以通过手动输入 x,y 坐标来使用 .annotate() 方法注释您想要的任何点,但我希望注释是自动的,或者自己找到最大点。

到目前为止,这是我的代码:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from pandas import Series, DataFrame

df = pd.read_csv('macrodata.csv') #Read csv file into dataframe
years = df['year'] #Get years column
infl = df['infl'] #Get inflation rate column

fig10 = plt.figure()
win = fig10.add_subplot(1,1,1)
fig10 = plt.plot(years, infl, lw = 2)

fig10 = plt.xlabel("Years")
fig10 = plt.ylabel("Inflation")
fig10 = plt.title("Inflation with Annotations")

【问题讨论】:

【参考方案1】:

如果 xy 是要绘制的数组,则通过

获得最大值的坐标
xmax = x[numpy.argmax(y)]
ymax = y.max()

这可以合并到一个函数中,您可以简单地使用您的数据调用该函数。

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-2,8, num=301)
y = np.sinc((x-2.21)*3)


fig, ax = plt.subplots()
ax.plot(x,y)

def annot_max(x,y, ax=None):
    xmax = x[np.argmax(y)]
    ymax = y.max()
    text= "x=:.3f, y=:.3f".format(xmax, ymax)
    if not ax:
        ax=plt.gca()
    bbox_props = dict(boxstyle="square,pad=0.3", fc="w", ec="k", lw=0.72)
    arrowprops=dict(arrowstyle="->",connectionstyle="angle,angleA=0,angleB=60")
    kw = dict(xycoords='data',textcoords="axes fraction",
              arrowprops=arrowprops, bbox=bbox_props, ha="right", va="top")
    ax.annotate(text, xy=(xmax, ymax), xytext=(0.94,0.96), **kw)

annot_max(x,y)


ax.set_ylim(-0.3,1.5)
plt.show()

【讨论】:

很漂亮:) 因为对于哪种方法可能适用于哪种输入存在一些混淆:此答案中提出的方法适用于输入数据为 numpy 数组 以及 熊猫系列。纯 python 列表将不起作用 - 在这种情况下,请参阅 @Anil_M's answer 这个问题。【参考方案2】:

我没有macrodata.csv 的数据可供使用。但是,一般来说,假设您有xy 轴数据作为列表,您可以使用以下方法获取max 的自动定位。

工作代码:

import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)

x=[1,2,3,4,5,6,7,8,9,10]
y=[1,1,1,2,10,2,1,1,1,1]
line, = ax.plot(x, y)

ymax = max(y)
xpos = y.index(ymax)
xmax = x[xpos]

ax.annotate('local max', xy=(xmax, ymax), xytext=(xmax, ymax+5),
            arrowprops=dict(facecolor='black', shrink=0.05),
            )

ax.set_ylim(0,20)
plt.show()

剧情:

【讨论】:

运行时收到此错误消息:TypeError: 'RangeIndex' object is not callable - 我的轴数据位于 DataFrame 中,而不是数组中。这就是我收到错误消息的原因吗?因为仅通过查看您的代码,我就知道它应该可以工作。 第 12 行:( xpos = y.index(ymax) ) 在 python 2.7 和 3.6 中都试过,没有抛出任何错误并且能够绘制图表。不知道你到底发生了什么。 这里,y 是一个 python 列表。列表有一个.index 方法。但是,pandas 系列没有这个方法;因此它失败了。 @ImportanceOfBeingErnest:是的,这就是为什么我说xy 被假定为列表。【参考方案3】:

@ImportanceOfBeingErnest 在他的response 中提出的方法非常简洁,但是如果数据位于索引不是基于零的统一索引([0,1, 2,..,N]),并且希望针对索引进行绘图 - 其值为 x's-。

我冒昧地调整了上述解决方案并将其与 pandas plot 函数一起使用。我还写了对称的min 函数。

def annot_max(x,y, ax=None):
    maxIxVal = np.argmax(y);
    zeroBasedIx = np.argwhere(y.index==maxIxVal).flatten()[0];
    xmax = x[zeroBasedIx];
    ymax = y.max()
    text= "k=:d, measure=:.3f".format(xmax, ymax)
    if not ax:
        ax=plt.gca()
    bbox_props = dict(boxstyle="round,pad=0.3", fc="w", ec="k", lw=0.72)
    arrowprops=dict(arrowstyle="-",connectionstyle="arc3,rad=0.1")
    kw = dict(xycoords='data',textcoords="axes fraction",
              arrowprops=arrowprops, bbox=bbox_props, ha="right", va="top")
    ax.annotate(text, xy=(xmax, ymax), xytext=(0.94,0.90), **kw)

def annot_min(x,y, ax=None):
    minIxVal = np.argmin(y);
    zeroBasedIx = np.argwhere(y.index==minIxVal).flatten()[0];
    xmin = x[zeroBasedIx];
    ymin = y.min()
    text= "k=:d, measure=:.3f".format(xmin, ymin)
    if not ax:
        ax=plt.gca()
    bbox_props = dict(boxstyle="round,pad=0.3", fc="w", ec="k", lw=0.72)
    arrowprops=dict(arrowstyle="-",connectionstyle="arc3,rad=0.1")
    kw = dict(xycoords='data',textcoords="axes fraction",
              arrowprops=arrowprops, bbox=bbox_props, ha="right", va="top")
    ax.annotate(text, xy=(xmin, ymin), xytext=(0.94,0.90), **kw)

用法很简单,例如:

ax = df[Series[0]].plot(grid=True, use_index=True, \
                  title=None);
annot_max(df[Series[0]].index,df[Series[0]],ax);
plt.show();

我希望这对任何人都有帮助。

【讨论】:

【参考方案4】:

这样的事情会起作用:

infl_max_index = np.where(infl == max(infl)) #get the index of the maximum inflation
infl_max = infl[infl_max_index] # get the inflation corresponding to this index
year_max = year[infl_max_index] # get the year corresponding to this index

plt.annotate('max inflation', xy=(year_max, infl_max))

【讨论】:

仅供参考,argmax 是获取最大值索引的内置方法。 @Alex 我明白了:ValueError: Can only tuple-ndex with MultiIndex

以上是关于如何在pyplot中自动注释最大值的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 pyplot.bar 仅绘制正误差条?

如何在 Django QuerySet 中注释两个字段的最大值

如何在Eclipse中如何自动添加注释和自定义注释风格

在 PyPlot 中反转 Y 轴

如何删除 pyplot.bar 中的轴?

如何在Eclipse中如何自动添加注释和自定义注释风格