【问题标题】:Click on Y axis value of interest to adjust color bars单击感兴趣的 Y 轴值以调整彩条
【发布时间】:2025-11-30 17:10:02
【问题描述】:

我正在尝试调整一个程序,以便为我的条形图添加交互性,因此当我单击 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)  ~~~

【问题讨论】:

    标签: python matplotlib bar-chart python-interactive


    【解决方案1】:

    你基本上有两个问题:

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

    2.你绘制条的方式不好,你可以把它们一起绘制,但我没有改变那部分,我只是对你的代码做了一些最小的编辑让它运行。

    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)
    

    【讨论】:

    • 感谢您的帮助!
    最近更新 更多