单击感兴趣的 Y 轴值以调整颜色条

Click on Y axis value of interest to adjust color bars

我正在尝试调整一个程序,以便为我的条形图添加交互性,因此当我单击 Y 轴并选择一个新的感兴趣值时,条形的颜色会相应调整。感谢任何帮助,因为我是 python 的新手,我不知道为什么当我点击我的图表时函数 Clickchart() 不起作用。

这是我的代码

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import scipy.stats as stats
import matplotlib 
import ipywidgets as wdg
from scipy.stats import norm
import matplotlib.gridspec as gridspec
from IPython.display import display
from matplotlib.cm import ScalarMappable


np.random.seed(12345)

#Raw Data

data = pd.DataFrame( { '1992': np.random.normal(32000,200000,3650), 
                   '1993': np.random.normal(43000,100000,3650), 
                   '1994': np.random.normal(43500,140000,3650), 
                   '1995': np.random.normal(48000,70000,3650) } ) 

#Mean of data
mean=data.mean(axis=0)

#Margin error of the standard error of the mean
sem=data.sem(axis=0)*1.96

    
# Create lists for the plot
year = ['1992', '1993', '1994', '1995']
x_pos = np.arange(len(year))

#Assume the user provides the y axis value of interest as a parameter or variable


my_cmap = matplotlib.cm.get_cmap('seismic')

#Y = int(input("Enter y axis value of interest: "))

#Create and display textarea widget
txt = wdg.Textarea(
    value='',
    placeholder='',
    description='Y Value:',
    disabled=False)

Y=42000

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

#fig, ax = plt.subplots()

i=0

def get_color(y,m,ci):
    low = m-ci
    high = m+ci
    if y<=low:
        out = 1-1e-10
    elif y>=high:
        out = 0
    else:
        out = 1-(y-low)/(high-low)
    return out

c_list=[my_cmap(get_color(Y,mean[i], sem[i])) for i in range(4)]

    
# Build the initial plot

i=0    
while i < 4:
    bars=ax.bar(x_pos[i], mean[i], yerr=sem[i], color=c_list[i], align='center', alpha=0.5, ecolor='black', capsize=10)
    i=i+1    

#Set the labels for the Visualization 
ax.set_ylabel('Mean of the Sample Data')
ax.set_xticks(x_pos)
ax.set_xticklabels(year)
ax.set_title('Custom Visualization of a Sample Data')
plt.axhline(y=Y, color = 'black')
#plt.text(3.7, Y, Y)
#plt.text(3.7, Y-2500, "Value of Interest")
ax.yaxis.grid(True)    

#Formats color bar
sm = ScalarMappable(cmap=my_cmap, norm=plt.Normalize(0,1))
sm.set_array([])
cbar = plt.colorbar(sm)
cbar.set_label('Probability', rotation=270,labelpad=25)

# Show the figure
plt.show()    
    
#Interactivity
class ClickChart(object):
    
    def __init__(self, ax):
        self.fig=ax.figure
        self.ax = ax
        self.horiz_line = ax.axhline(y=Y, color='black', linewidth=2)
        self.fig.canvas.mpl_connect('button_press_event', self.onclick)

### Event handlers
    def onclick(self, event):
        self.horiz_line.remove()
        self.ypress = event.ydata
        self.horiz_line = ax.axhline(y=self.ypress, color='red', linewidth=2)
        txt.value = str(event.ydata)
        self.color_bar(event)

    def color_bar(self, event):

        for index, bar in enumerate(bars):
            bar.set_color(c=cmap(self.calc_prob(index)))
            print(index)
    
    def calc_prob(self, index):
        global mean, sem
        mean2 = mean[index]
        err = sem[index]
        result = norm.cdf(self.ypress, loc=mean2, scale=err) 
        return result
click=ClickChart(ax)  ~~~

你基本上有两个问题:

1.You 需要在 onclick 中调用 figure.canvas.draw() 才能显示更改。

2.The 你绘制条形图的方式不好,你可以将它们一起绘制,但我没有改变那部分,我只是对你的代码进行了一些最小的编辑以使其成为 运行。

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import scipy.stats as stats
import matplotlib 
from scipy.stats import norm
import matplotlib.gridspec as gridspec
from matplotlib.cm import ScalarMappable


np.random.seed(12345)

#Raw Data

data = pd.DataFrame( { '1992': np.random.normal(32000,200000,3650), 
                   '1993': np.random.normal(43000,100000,3650), 
                   '1994': np.random.normal(43500,140000,3650), 
                   '1995': np.random.normal(48000,70000,3650) } ) 

#Mean of data
mean=data.mean(axis=0)

#Margin error of the standard error of the mean
sem=data.sem(axis=0)*1.96

    
# Create lists for the plot
year = ['1992', '1993', '1994', '1995']
x_pos = np.arange(len(year))

#Assume the user provides the y axis value of interest as a parameter or variable


my_cmap = matplotlib.cm.get_cmap('seismic')

Y=42000

fig = plt.figure()
ax = fig.add_subplot(111)
i=0
def get_color(y,m,ci):
    low = m-ci
    high = m+ci
    if y<=low:
        out = 1-1e-10
    elif y>=high:
        out = 0
    else:
        out = 1-(y-low)/(high-low)
    return out

c_list=[my_cmap(get_color(Y,mean[i], sem[i])) for i in range(4)]

i=0
# I think you need four bars, I dont think plotting individual bar is good
bars = []
while i < 4:
    bc=ax.bar(x_pos[i], mean[i], yerr=sem[i], color=c_list[i], align='center', alpha=0.5, ecolor='black', capsize=10)
    bars.append(bc[0])
    i=i+1    

#Set the labels for the Visualization 
ax.set_ylabel('Mean of the Sample Data')
ax.set_xticks(x_pos)
ax.set_xticklabels(year)
ax.set_title('Custom Visualization of a Sample Data')
plt.axhline(y=Y, color = 'black')
#plt.text(3.7, Y, Y)
#plt.text(3.7, Y-2500, "Value of Interest")
ax.yaxis.grid(True)    

#Formats color bar
sm = ScalarMappable(cmap=my_cmap, norm=plt.Normalize(0,1))
sm.set_array([])
cbar = plt.colorbar(sm)
cbar.set_label('Probability', rotation=270,labelpad=25)

# Show the figure
plt.show()    
    
#Interactivity
class ClickChart(object):
    
    def __init__(self, ax):
        self.fig=ax.figure
        self.ax = ax
        self.horiz_line = ax.axhline(y=Y, color='black', linewidth=2)
        self.fig.canvas.mpl_connect('button_press_event', self.onclick)

### Event handlers
    def onclick(self, event):
        self.horiz_line.remove()
        self.ypress = event.ydata
        self.horiz_line = ax.axhline(y=self.ypress, color='red', linewidth=2)
        self.color_bar(event)
        # pls add this line
        self.fig.canvas.draw()

    def color_bar(self, event):
        for index, bar in enumerate(bars):
            # should use my_cmap, not cmap
            bar.set_color(c=my_cmap(self.calc_prob(index)))
            print(index)
    
    def calc_prob(self, index):
        global mean, sem
        mean2 = mean[index]
        err = sem[index]
        result = norm.cdf(self.ypress, loc=mean2, scale=err) 
        return result
click=ClickChart(ax)