0

I have four sets of random normal distributed numbers. The means are used to plot bar chart with each set's 95% confidence intervals plotted with errorbar.

Given a value y, four different colors will be set to the bars corresponding to the four ranges y is in: 1. lower bound to avg; 2. avg to upper bound; 3. below lower; 4. above upper.

I want to use a slider to control the y value and update the bar color each time I slide, I tried to use the following code but the bar charts cannot be plotted every update.

Could someone give me some ideas?

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import scipy.stats as st
from matplotlib.widgets import Slider

np.random.seed(12345)

df = pd.DataFrame([np.random.normal(33500,150000,3650), 
                   np.random.normal(41000,90000,3650), 
                   np.random.normal(41000,120000,3650), 
                   np.random.normal(48000,55000,3650)], 
                  index=[1992,1993,1994,1995])

N = len(df.columns)-1  # Degree of Freedom
avg = df.mean(axis=1)  # Mean for each row
std = df.sem(axis=1)  # Unbiased Standard Deviation

year = df.index.map(str)  # Convert to String
conf95 = st.t.ppf(0.95, N)*std  # 95% Confidence Interval

upper = avg + conf95
lower = avg - conf95
colormap = ['blue', 'aqua', 'orange', 'brown']

ini = 39900
chk1 = ini>upper  # Check if y is greater than upper bound: blue
chk2 = ini<lower  # CHeck if y is smaller than lower bound: brown
chk3 = (ini>=lower) & (ini<=avg) # Check if y is in between avg and lower: orange
chk4 = (ini>avg) & (ini<=upper) # Check if y is in between avg and upper: aqua


fig, ax =plt.subplots()   
ax.bar(df.index[chk1.values], avg.iloc[chk1.values], width=1, edgecolor='k', color='blue')
ax.bar(df.index[chk2.values], avg.iloc[chk2.values], width=1, edgecolor='k', color='brown')
ax.bar(df.index[chk3.values], avg.iloc[chk3.values], width=1, edgecolor='k', color='orange')
ax.bar(df.index[chk4.values], avg.iloc[chk4.values], width=1, edgecolor='k', color='aqua')
ax.axhline(y=ini,xmin=0,xmax=10,linewidth=1,color='k')

ax.errorbar(df.index, avg, yerr=conf95, fmt='.',capsize=15, color='k')
plt.subplots_adjust(left=0.1, bottom=0.2)
plt.xticks(df.index, year)  # Map xlabel with String
plt.yticks(np.arange(0,max(avg)+1,max(avg)/5))

axcolor = 'lightgoldenrodyellow'
axy = plt.axes([0.1, 0.1, 0.7, 0.03], axisbg=axcolor)

sy = Slider(axy, 'y', 0.1, int(max(upper)+1), valinit=ini)

Until this step the color works fine. Then the update func does not work thou.

def update(val):
    ax.cla()
    yy = sy.val    
    chk1 = yy>upper
    chk2 = yy<lower
    chk3 = (yy>=lower) & (yy<=avg)
    chk4 = (yy>avg) & (yy<=upper)
    ax.bar(df.index[chk1.values], avg.iloc[chk1.values], width=1, edgecolor='k', color='blue')
    ax.bar(df.index[chk2.values], avg.iloc[chk2.values], width=1, edgecolor='k', color='brown')
    ax.bar(df.index[chk3.values], avg.iloc[chk3.values], width=1, edgecolor='k', color='orange')
    ax.bar(df.index[chk4.values], avg.iloc[chk4.values], width=1, edgecolor='k', color='aqua')
    ax.bar(df.index, avg, width=1, edgecolor='k', color='silver')
    ax.errorbar(df.index, avg, yerr=conf95, fmt='.',capsize=15, color='k')
    ax.axhline(y=yy,xmin=0,xmax=10,linewidth=1,color='k')
    fig.canvas.draw_idle()

sy.on_changed(update)  

Really appreciate any insights and Thank you guys very much!

Best Shawn

Darth BEHFANS
  • 409
  • 6
  • 10

1 Answers1

0

Simply delete the line

ax.bar(df.index, avg, width=1, edgecolor='k', color='silver')

I don't know why you put it there, but it will plot a complete unicolor barchart on top of the colored bars and hide them.


In order to make some interaction possible, an interactive backend needs to be used. So it will not work out of the box in IPython when %matplotlib inline mode is set. Options you have:
  • Using %matplotlib notebook in IPython Qt console or jupyter notebook.
  • Using a GUI backend when running code as a script, by adding plt.show(). In Spyder that can be ensured by running the script in a new dedicated window as sketched here.
Community
  • 1
  • 1
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • Sorry that line was a left over from previous trial. – Darth BEHFANS Mar 26 '17 at 23:24
  • But when I delete this line, whenever I slide the slider, the bars still disappear. Could you give me a little more hint on your method? – Darth BEHFANS Mar 26 '17 at 23:26
  • If I plot the unicolor barchart on the top of the previous one, how to have the color be updated per the new yy value from the slider event>. – Darth BEHFANS Mar 26 '17 at 23:28
  • The bars should not disappear when deleting this one line. When I simply copy the code from the question and delete that line, it works as expected. – ImportanceOfBeingErnest Mar 26 '17 at 23:32
  • Thank you! I used Pycharm and Spyder with IPython, in Pycharm the interactive was not active, while in Spyder that Bar disappearing problem persists... Then I run the code in Jupyter Notebook with Python 3 kernel the code works fine with %matplotlib notebook mode. Really appreciate your help! – Darth BEHFANS Mar 27 '17 at 00:05