问题描述
我有一个 matplotlib
条形图,它使用 yerr
来模拟箱形图.
I have a matplotlib
bar chart that uses yerr
to simulate a box plot.
我愿意
- 点击此条形图
- 获取此点击的y值
- 在此 y 值处绘制一条红色水平线
- 使用
scipy.stats.ttest_1samp
对条形图数据与y值进行t测试 - 更新条形图的颜色(如果 t << -2则为蓝色,如果 t >> 2则为红色)
- click on this bar chart
- get the y value for this click
- draw a red horizontal line at this y value
- run a t-test of bar chart data vs y value using
scipy.stats.ttest_1samp
- 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 条形图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!