Нажмите на интересующее значение оси 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,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)  ~~~

person user14198723    schedule 05.10.2020    source источник


Ответы (1)


У вас в основном две проблемы:

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,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)
person ted930511    schedule 06.10.2020
comment
Спасибо за вашу помощь! - person user14198723; 08.10.2020