2017-07-17 57 views
1

我有一個matplotlib條形圖,它使用yerr來模擬箱形圖。使用onclick的y值更新(或重繪?)matplotlib條形圖

我想這個條形圖上

  1. 點擊
  2. 得到這個y值單擊
  3. 在這個Y值
  4. 運行繪製一個紅色橫線 - 條形圖數據對y值的測試使用scipy.stats.ttest_1samp
  5. 更新條形圖顏色(藍色如果t < < -2和紅色如果 >> 2)

我可以做每個步驟分別,但不在一起。

我不知道如何反饋y值以運行t - 測試和更新圖表。我可以在第一次運行時提供y值,並正確地爲條形圖着色,但我無法使用click y值更新條形圖。

這裏有一些玩具數據。

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統計信息,但我認爲這與更新條形圖是分開的,我可以自行添加。

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() 

單擊後,會出現水平線,但條形圖顏色不會更新。

enter image description here

+1

能否請您檢查,如果這尚未在這個問題回答說:https://開頭堆棧溢出。com/questions/43133017/how-to-change-colors-automatically-once-a-parameter-is-change至少這是相當類似的,直到使用完全相同的數據,並根據需要更新顏色。至於統計數據,你可以編輯你的問題來更具體地詢問。 – ImportanceOfBeingErnest

+0

@ImportanceOfBeingErnest是的,這實現了同樣的大局目標。我可以適應這個做我想做的事(置信區間,* t * - 測試等)。我仍然對如何傳回點擊數據感興趣......儘管您的鏈接解決方案是更好的選擇。 –

+1

我不確定我是否理解「傳回點擊數據」的含義。下面的答案是否解決了這個問題?如果是這樣,你可以接受它,如果沒有,我建議你更詳細地瞭解你的要求,並明確說明鏈接問題的答案以及下面的答案對你的幫助有多大。 – ImportanceOfBeingErnest

回答

1

你想利用內幕onpick新的y值重新計算ttests。然後,您可以像以前一樣重新計算顏色。然後,您可以循環使用ax.bar創建的條(爲了便於訪問,我將它們保存爲self.bars),並使用bar.set_facecolor和新計算的顏色。

我還添加了一個嘗試,除了構造改變行的y值,如果你再次點擊,而不是創建一個新行。

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() 

下面是一些例子輸出:

enter image description here

enter image description here

enter image description here