Python Bokeh - blending
<p>I am trying to create a bar chart from a dataframe <code>df</code> in Python Bokeh library. The data I have simply looks like:</p>

<pre><code>value datetime
5    01-01-2015
7    02-01-2015
6    03-01-2015
...  ... (for 3 years)
</code></pre>

<p>I would like to have a bar chart that shows 3 bars per month: </p>

<ul>
<li>one bar for the MEAN of 'value' for the month</li>
<li>one bar for the MAX of 'value' for the month</li>
<li>one bar for the mean of 'value' for the month</li>
</ul>

<p>I am able to create one bar chart any of MEAN/MAX/MIN with:</p>

<pre><code>from bokeh.charts import Bar, output_file, show
p = Bar(df, 'datetime', values='value', title='mybargraph',
         agg='mean', legend=None)
output_file('test.html')
show(p)
</code></pre>

<p>How could I have the 3 bar (mean, max, min) on the same plot ? And if possible stacked above each other.</p>

<p>It looks like <code>blend</code> could help me (like in this example: <a href="http://bokeh.pydata.org/en/latest/docs/gallery/stacked_bar_chart.html" rel="nofollow">http://bokeh.pydata.org/en/latest/docs/gallery/stacked_bar_chart.html</a>) but I cannot find detailed explanations of how it works. The bokeh website is amazing but for this particular item it is not really detailed. </p>

<p>Anyone to help me? </p>

<p>That blend example put me on the right track.</p>

<pre><code>import pandas as pd
from pandas import Series
from dateutil.parser import parse
from bokeh.plotting import figure
from bokeh.layouts import row
from bokeh.charts import Bar, output_file, show
from bokeh.charts.attributes import cat, color
from bokeh.charts.operations import blend

output_file("datestats.html")
</code></pre>

<p>Just some <strong>sample data</strong>, feel free to alter it as you see fit.
First I had to wrangle the data into a proper format.</p>

<pre><code># Sample data
vals = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
dates = ["01-01-2015", "02-01-2015", "03-01-2015", "04-01-2015",
         "01-02-2015", "02-02-2015", "03-02-2015", "04-02-2015",
         "01-03-2015", "02-03-2015", "03-03-2015", "04-03-2015"
         ]
</code></pre>

<p>It looked like your date format was "day-month-year" - I used the dateutil.parser so pandas would recognize it properly.</p>

<pre><code># Format data as pandas datetime objects with day-first custom
days = []
days.append(parse(x, dayfirst=True) for x in dates)
</code></pre>

<p>You also needed it grouped by month - I used pandas resample to downsample the dates, get the appropriate values for each month, and merge into a dataframe.</p>

<pre><code># Put data into dataframe broken into min, mean, and max values each for month
ts = Series(vals, index=days[0])
firstmerge = pd.merge(ts.resample('M').min().to_frame(name="min"),
                      ts.resample('M').mean().to_frame(name="mean"),
                      left_index=True, right_index=True)
frame = pd.merge(firstmerge, ts.resample('M').max().to_frame(name="max"),
                 left_index=True, right_index=True)
</code></pre>

<p>Bokeh allows you to use the pandas dataframe's index as the chart's x values,
as <a href="https://github.com/bokeh/bokeh/issues/2970" rel="nofollow">discussed here</a> 
but it didn't like the datetime values so I added a new column for date labels.  See timeseries comment below***.</p>

<pre><code># You can use DataFrame index for bokeh x values but it doesn't like timestamp
frame['Month'] = frame.index.strftime('%m-%Y')
</code></pre>

<p>Finally we get to the charting part.  Just like the Olympic medal example, we pass some arguments to Bar.
Play with these however you like, but <strong>note</strong> that I added the legend by building it outside of the chart altogether.  If you have a lot of data points it gets very messy on the chart the way it's built here.</p>

<pre><code># Main object to render with stacking
bar = Bar(frame,
          values=blend('min', 'mean', 'max',
                       name='values', labels_name='stats'),
          label=cat(columns='Month', sort=False),
          stack=cat(columns='values', sort=False),
          color=color(columns='values',
                      palette=['SaddleBrown', 'Silver', 'Goldenrod'],
                      sort=True),
          legend=None,
          title="Statistical Values Grouped by Month",
          tooltips=[('Value', '@values')]
          )

# Legend info (displayed as separate chart using bokeh.layouts' row)
factors = ["min", "mean", "max"]
x = [0] * len(factors)
y = factors
pal = ['SaddleBrown', 'Silver', 'Goldenrod']
p = figure(width=100, toolbar_location=None, y_range=factors)
p.rect(x, y, color=pal, width=10, height=1)
p.xaxis.major_label_text_color = None
p.xaxis.major_tick_line_color = None
p.xaxis.minor_tick_line_color = None

# Display chart
show(row(bar, p))
</code></pre>

<p><a href="http://i.stack.imgur.com/WLbkq.png" rel="nofollow"><img src="http://i.stack.imgur.com/WLbkq.png" alt="Bokeh_output"></a></p>

<p>If you copy/paste this code, this is what you will <em>show</em>.<br>
If you render it yourself or if you serve it: hover over each block to see the tooltips (values).</p>

<p>I didn't abstract everything I could (colors come to mind).</p>

<p>This is the type of chart you wanted to build, but it seems like a different chart style would display the data more informatively since stacked totals (min + mean + max) don't provide meaningful information.  But I don't know what your data really are.</p>

<p>***You might consider a <a href="http://bokeh.pydata.org/en/0.11.0/docs/reference/charts.html#timeseries" rel="nofollow">timeseries chart</a>.  This could remove some of the data wrangling done before plotting.</p>

<p>You might also consider <a href="http://bokeh.pydata.org/en/latest/docs/user_guide/charts.html#grouping" rel="nofollow">grouping your bars</a> instead of stacking them.  That way you could easily visualize each month's numbers.</p>

python bar-chart bokeh