I am trying to adjust a program, in order to add interactivity to my bar chart, so when I click on Y axis and choose a new value of interest, the color of the bars is adjusted accordingly. I appreciate any help on this as I am new to python and I don't know why the function Clickchart() is not working when I click on my chart.
This is my code
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) ~~~
You basically have two issues:
1.You need to call
figure.canvas.draw()
insideonclick
for the change to display.2.The way you plot bars is not good, you can plot them collectively, but I dont change that part, I just made some minimum edit to you code to make it run.