本文介绍了使用来自 onclick 的 y 值更新(或重绘?)matplotlib 条形图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 matplotlib 条形图,它使用 yerr 来模拟箱形图.

I have a matplotlib bar chart that uses yerr to simulate a box plot.

我愿意

  1. 点击此条形图
  2. 获取此点击的y值
  3. 在此 y 值处绘制一条红色水平线
  4. 使用scipy.stats.ttest_1samp
  5. 对条形图数据与y值进行t测试
  6. 更新条形图的颜色(如果 t << -2则为蓝色,如果 t >> 2则为红色)
  1. click on this bar chart
  2. get the y value for this click
  3. draw a red horizontal line at this y value
  4. run a t-test of bar chart data vs y value using scipy.stats.ttest_1samp
  5. update bar chart colors (blue if t << -2 and red if t >> 2)

我可以单独完成这些步骤中的每一个,但不能一起完成.

I can do each of these steps separately, but not together.

我不知道如何返回 y 值以运行 t 测试并更新图表.我可以在第一次运行时输入一个 y 值并正确地为条形图着色,但我无法使用点击 y 值更新条形图.

I don't know how to feed the y value back to run the t-test and update the chart. I can feed a y value on first run and correctly color the bar charts, but I can't update the bar charts with the click y value.

这里有一些玩具数据.

import pandas as pd
import numpy as np

np.random.seed(12345)

df = pd.DataFrame([np.random.normal(32000,200000,3650), 
                   np.random.normal(43000,100000,3650), 
                   np.random.normal(43500,140000,3650), 
                   np.random.normal(48000,70000,3650)], 
                  index=[1992,1993,1994,1995])

这是我拼凑的东西,以绘制图表并添加线.我还想添加一个将颜色映射到 t 统计信息的插图,但是我认为这与更新条形图是分开的,我可以自己添加它.

And here is what I have pieced together to draw the chart and add the line. I would also like to add an inset that maps colors to t statistics, but I think that is separate from updating the bar chart and I can add that on my own.

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

class PointPicker(object):
    def __init__(self, df, y=0):

        # moments for bar chart "box plot"
        mus = df.mean(axis=1)
        sigmas = df.std(axis=1)
        obs = df.count(axis=1)
        ses = sigmas / np.sqrt(obs - 1)
        err = 1.96 * ses
        Nvars = len(df)

        # map t-ststistics to colors
        ttests = ttest_1samp(df.transpose(), y)
        RdBus = plt.get_cmap('RdBu')
        colors = RdBus(1 / (1 + np.exp(ttests.statistic)))

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

        # bar chart "box plot"
        self.ax.bar(list(range(Nvars)), mus, yerr=ci, capsize=20, picker=5, color=colors)
        plt.xticks(list(range(Nvars)), df.index)
        plt.tick_params(top='off', bottom='off', left='off', right='off', labelleft='on', labelbottom='on')
        plt.gca().get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
        plt.title('Random Data for 1992 to 1995')

        self.fig.canvas.mpl_connect('pick_event', self.onpick)
        self.fig.canvas.mpl_connect('key_press_event', self.onpress)

    def onpress(self, event):
        """define some key press events"""
        if event.key.lower() == 'q':
            sys.exit()

    def onpick(self,event):
        x = event.mouseevent.xdata
        y = event.mouseevent.ydata
        self.ax.axhline(y=y, color='red')
        self.fig.canvas.draw()

if __name__ == '__main__':

    plt.ion()
    p = PointPicker(df, y=32000)
    plt.show()

我点击后,出现水平线,但条形图颜色没有更新.

After I click, the horizontal line appears, but the bar chart colors do not update.

推荐答案

您要使用 onpick 中的新y值重新计算 ttests .然后,您可以像以前一样重新计算颜色.然后,您可以遍历使用 ax.bar 创建的条(此处将它们另存为 self.bars 以方便访问),并使用 bar.set_facecolor 使用新计算的颜色.

You want to recalculate the ttests using the new y value inside onpick. Then, you can recalculate the colors in the same way as you did before. You can then loop over the bars created with ax.bar (here I save them as self.bars for easy access), and use bar.set_facecolor with the newly calculated color.

我还添加了一个尝试,除了构造以在您第二次单击时更改该行的 y 值,而不是创建一个新行.

I also added a try, except construct to change the yvalue of the line if you click a second time, rather than create a new line.

import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from scipy.stats import ttest_1samp

np.random.seed(12345)

df = pd.DataFrame([np.random.normal(32000,200000,3650), 
                   np.random.normal(43000,100000,3650), 
                   np.random.normal(43500,140000,3650), 
                   np.random.normal(48000,70000,3650)], 
                  index=[1992,1993,1994,1995])


class PointPicker(object):
    def __init__(self, df, y=0):

        # Store reference to the dataframe for access later
        self.df = df

        # moments for bar chart "box plot"
        mus = df.mean(axis=1)
        sigmas = df.std(axis=1)
        obs = df.count(axis=1)
        ses = sigmas / np.sqrt(obs - 1)
        err = 1.96 * ses
        Nvars = len(df)

        # map t-ststistics to colors
        ttests = ttest_1samp(df.transpose(), y)
        RdBus = plt.get_cmap('RdBu')
        colors = RdBus(1 / (1 + np.exp(ttests.statistic)))

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

        # bar chart "box plot". Store reference to the bars here for access later
        self.bars = self.ax.bar(
                list(range(Nvars)), mus, yerr=ses, capsize=20, picker=5, color=colors)
        plt.xticks(list(range(Nvars)), df.index)
        plt.tick_params(top='off', bottom='off', left='off', right='off', labelleft='on', labelbottom='on')
        plt.gca().get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
        plt.title('Random Data for 1992 to 1995')

        self.fig.canvas.mpl_connect('pick_event', self.onpick)
        self.fig.canvas.mpl_connect('key_press_event', self.onpress)

    def onpress(self, event):
        """define some key press events"""
        if event.key.lower() == 'q':
            sys.exit()

    def onpick(self,event):
        x = event.mouseevent.xdata
        y = event.mouseevent.ydata

        # If a line already exists, just update its y value, else create a horizontal line
        try:
            self.line.set_ydata(y)
        except:
            self.line = self.ax.axhline(y=y, color='red')

        # Recalculate the ttest
        newttests = ttest_1samp(df.transpose(), y)
        RdBus = plt.get_cmap('RdBu')
        # Recalculate the colors
        newcolors = RdBus(1 / (1 + np.exp(newttests.statistic)))

        # Loop over bars and update their colors
        for bar, col in zip(self.bars, newcolors):
            bar.set_facecolor(col)

        self.fig.canvas.draw()

if __name__ == '__main__':

    #plt.ion()
    p = PointPicker(df, y=32000)
    plt.show()

这是一些示例输出:

这篇关于使用来自 onclick 的 y 值更新(或重绘?)matplotlib 条形图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-02 21:30