# Plotting Stacked Histogram for Time-series data

Given the dataset:

timestamp                     item       itemcount
2019-03-18 07:40:08.759        A          10
2019-03-18 08:40:08.759        B          5
..................................................
2019-05-20 07:40:08.759        D          4
2019-05-21 07:40:08.759        E          8


I want to plot stacked histogram like:

where the x-axis should be the date and y axis the itemcount and stack will be each item. I want the graph with subplots for every month.

I am new here so will be happy to get any feedback on my mistakes. Thank you.

here's one sample code i found online which plots the same graph in the figure above.

  # Import Data

# Prepare data
x_var = 'manufacturer'
groupby_var = 'class'
df_agg = df.loc[:, [x_var, groupby_var]].groupby(groupby_var)
vals = [df[x_var].values.tolist() for i, df in df_agg]

# Draw
plt.figure(figsize=(16,9), dpi= 80)
colors = [plt.cm.Spectral(i/float(len(vals)-1)) for i in range(len(vals))]
n, bins, patches = plt.hist(vals, df[x_var].unique().__len__(), stacked=True, density=False, color=colors[:len(vals)])

# Decoration
plt.legend({group:col for group, col in zip(np.unique(df[groupby_var]).tolist(), colors[:len(vals)])})
plt.title(f"Stacked Histogram of $${x_var}$$ colored by $${groupby_var}$$", fontsize=22)
plt.xlabel(x_var)
plt.ylabel("Frequency")
plt.ylim(0, 40)
plt.xticks(ticks=bins, labels=np.unique(df[x_var]).tolist(), rotation=90, horizontalalignment='left')
plt.show()

• Can you include the necessary information and tags on your used framework/language and your code tried so far? (e.g. R & ggplot vs. Python & seaborn or matplotlib or...) – Fnguyen Sep 26 '19 at 11:10
• any library or framework is okay for me. I tried using matplotlib but was not able to do it. – naman Sep 26 '19 at 12:44
• so I can assume you use Python? (I'd add that to the question and tags because an R answer is unlikely to get you to your goal then). Can you show the matplotlibe code you tried so far, it may be easier to fix that instead of starting from 0. – Fnguyen Sep 26 '19 at 12:50
• yeah... I have no idea on how to plot this kind of graph. I have this dataset and wanted to plot a similar graph and found one online. – naman Sep 26 '19 at 15:49
• I have edited my question with the code – naman Sep 26 '19 at 15:51

This solution uses plotnine which is based on R ggplot and the grammar of graphics.

Generally you have to transform the timestamp to months first and then understand that:

X = Months Y = itemcount Group = item

This should help also for your matplotlib solution!

from datetime import datetime
import pandas as pd
from plotnine import *

df['month'] = pd.DatetimeIndex(df['timestamp']).month

p = (ggplot(pdf, aes(x = 'month', y = 'itemcount',fill='item')) + geom_bar( Star = 'identity',position='fill')

# fill here acts the same as group in matplotlib
$$$$

• getting an error msg as: stat_count() must not be used with a y aesthetic – naman Sep 28 '19 at 20:19
• @naman use stat = 'identity' in the geom_bar function. – Fnguyen Sep 29 '19 at 16:13
• thank you for your solution. – naman Oct 3 '19 at 9:18
• Can you suggest me how I can plot subplots for every month. I will take x as day. @Fnguyen – naman Oct 3 '19 at 10:04
• @naman you should really post a new question with reproducible sample data. – Fnguyen Oct 3 '19 at 11:30

You may apply Wolfram Language to your project. There is a free Wolfram Engine for developers you can download and with the Wolfram Client Library for Python you can use these functions in Python.

You may use the DateHistogram function for your plot. However, lets create an example data set in Python first.

import pandas as pd
import random
from datetime import datetime, timedelta

start_date = datetime(2019, 9, 27)
end_date = start_date + timedelta(days=365)

random.seed(91827364)

data = {
'timestamp' : list(map(
lambda r: start_date + (end_date - start_date) * r,
[random.random() for i in range(100)]
)),
'item' : random.choices(['A','B','C','D','E','F'], k=100),
'itemcount' : [random.randrange(1,20) for i in range(100)]
}

dfTimes = pd.DataFrame.from_dict(data)



Using DateHistogram and WeightedData on dfTimes the plot can be generated.

from wolframclient.evaluation import WolframLanguageSession
from wolframclient.language import wl, wlexpr

wolfSession = WolframLanguageSession()

dh = wolfSession.evaluate(
wl.DateHistogram(
wl.Query(
wl.RightComposition(wl.GroupBy(wlexpr('#["item"]&')), wl.KeySort),
wl.RightComposition(wl.Values, wl.Transpose, wl.Apply(wl.WeightedData)),
wl.RightComposition(['timestamp', 'itemcount'], wl.Values)
)(dfTimes),
'Month', 'Count',
PlotLabel='Sum(Item Count)',
ChartLayout="Stacked",
ChartLegends=wl.Automatic,
DateTicksFormat=['MonthNameShort',' ','YearShort'],
ImageSize=wl.Large,
ChartBaseStyle=wl.Opacity(1),
ChartStyle=wl.ColorData(["Indexed","Sunrise"])
)
)


wolfSession.terminate()


If you environment does not render dh then you can view the chart by Exporting in one of the supported Raster Image Formats or Vector Graphics Formats.

wolfSession.evaluate(
wl.Export(
'<path with image filename>',
dh
)
)
)


In Wolfram Language with a Dataset dfTimes containing the same data then, for comparison, the same chart is (Dataset gets a bit of syntax sugar with Query).

DateHistogram[
dfTimes[
GroupBy[#["item"] &] /* KeySort,
Values /* Transpose /* Apply[WeightedData],
{"timestamp", "itemcount"} /* Values
],
"Month", "Count",
PlotLabel -> "Sum(Item Count)",
ChartLayout -> "Stacked",
ChartLegends -> Automatic,
DateTicksFormat -> {"MonthNameShort", " ", "YearShort"},
ImageSize -> Large,
ChartBaseStyle -> Opacity[1],
ChartStyle -> ColorData[{"Indexed", "Sunrise"}]]
`

Hope this helps.

• Thank you for the solution. Tried the solution. But got stuck into many errors as: ''WolframKernelException: Cannot locate a kernel automatically. Please provide an explicit kernel path" – naman Sep 28 '19 at 20:21
• @naman You must download the free Wolfram Engine. – Edmund Sep 28 '19 at 21:00