Reputation: 2012
I've been trying to find a solution to this for quite some time. I am using pandas and matplotlib to write a plotting library. I am currently in the process of correcting an error in design which was using strings instead of timestamps. One reason this is an error because it prevents any easy way of filling missing timestamps.
The goal is to create a stacked bar chart that looks similar to the following chart but with only a portion of the timestamp. (HH:MM, YYYY-MM-DD, YYYY-MM, etc.) This bar chart is produced with a regular pandas Index.
df = pd.read_csv('/path/to/file.csv', index_col='ts')
Decent Chart - not enough rep to embed images yet
After converting my index to a pandas DateTimeIndex the following chart is produced with the same data.
df = pd.read_csv('/path/to/file.csv', index_col='ts', parse_dates=True, infer_datetime_format=True)
After some manipulation here is the structure of the data frame being used for plotting:
work_type CYCLECOUNT PICK REPLENISHMENT
ts
2018-10-25 05:00:00 35 0 5
2018-10-25 06:00:00 95 0 1
2018-10-25 07:00:00 125 0 1
2018-10-25 08:00:00 8 0 0
2018-10-25 09:00:00 19 0 3
2018-10-25 11:00:00 0 0 89
2018-10-25 12:00:00 1 0 59
2018-10-25 13:00:00 1 541 208
2018-10-25 14:00:00 0 516 123
2018-10-25 15:00:00 0 390 95
2018-10-25 16:00:00 2 315 167
2018-10-25 17:00:00 0 784 87
2018-10-25 18:00:00 1 521 145
2018-10-25 19:00:00 1 768 196
2018-10-25 20:00:00 0 769 113
2018-10-25 21:00:00 4 785 139
2018-10-25 22:00:00 0 858 81
2018-10-25 23:00:00 2 568 33
2018-10-26 00:00:00 6 530 60
2018-10-26 01:00:00 13 163 50
2018-10-26 02:00:00 12 4 158
2018-10-26 03:00:00 6 5 92
Here is the code being used to generate the chart:
def create_stacked_bar_chart(
self, dataframe, focus_total, ax: matplotlib.axes.Axes=None,
top_bar_lbls=False, mid_bar_lbls=False, mid_bar_as_percent=False
):
i = 0 # part_map keys
k = 0 # pivot_df row index
barwidth = 0.5
part_map = dict()
column_names = dataframe.columns.values
if ax is None:
fig, ax = self.create_figure()
for col in column_names:
if i == 0:
part_map[i] = ax.bar(
dataframe.index,
dataframe[col].values,
barwidth, zorder=3
)
else:
barstart = 0
for j in range(i):
barstart += dataframe[column_names[j]]
part_map[i] = ax.bar(
dataframe.index, dataframe[col].values,
barwidth, bottom=barstart, zorder=3
)
I have also tried dataframe.index.to_pydatetime() in the ax.bar() function which seems to have no effect. I've tried numerous things but to_pydatetime() seems to be recommended in many places.
Upvotes: 8
Views: 2856
Reputation: 2012
Update: This solution works for the chart in question in this post but for anyone that might come across this...
===> The unit for bar width on a date x axis is days <===
This was solved by changing the following line from:
barwidth = 0.5
to
barwidth = 0.5 * (1 / dataframe.shape[0])
Where dataframe.shape[0]
is equal to the number of rows in the dataframe allowing for dynamic sizing.
Upvotes: 9