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

问题描述

我正在尝试调整程序,以增加条形图的交互性,因此,当我单击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,'1994': np.random.normal(43500,140000,'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],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。您需要调用figure.canvas.draw()内部的onclick才能显示更改。

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,'1994': np.random.normal(43500,140000,'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],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)