Reputation: 396
I have a dictionary of time series data in the following structure:
# {"second": [size, label]}
dict = {0.6: [100, 0],
1.1: [120, 1],
1.8: [220, 2]}
The dictionary above keeps track of the size and label until the corresponding second. Considering the example above, I'd like to plot lines in the same graph:
green line for the label 0 between seconds: ( 0, 0.6 ]
(0.6 included)
blue line for the label 1 between seconds: ( 0.6, 1.1 ]
(0.6 excluded, 1.1 included)
red line for the label 2 between seconds: ( 1.1, 1.8 ]
(1.1 excluded, 1.8 included)
I have many data points in a dictionary for approximately 10 minutes of data. I am planning to split the x-axis e.g. for every 10 seconds, so the data above will be shown as tiny spikes in the whole graph. I cannot use scattering for this case, there should be one line graph across the time [0 to n) (composed of different graphs with different labels(colors) as in the points above).
Is this achievable by using matplotlib, or do I need to find another way? Thanks!
Upvotes: 0
Views: 500
Reputation: 80299
plt.plot
by default draws lines between the given positions. As only one point is given at each call, no lines are drawn. plt.scatter
can draw one (or more) points with a given color.
You can first collect all the x and all the y values into lists, and then draw a line plot(plt.plot
). If you want a step function, you can use plt.step
instead. On top of those lines you can plot colored dots (plt.scatter
). Or you could draw short lines via plt.plot([x_0, x_1], [y, y])
.
Here is an example:
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
dict = {0.22: [100, 0],
0.68: [180, 1],
1.12: [210, 2]}
legendMap = {0: ["blue", "A"],
1: ["red", "B"],
2: ["green", "C"]}
x = list(dict.keys())
x.sort() # needed in case the values wouldn't be ordered
y = [dict[xi][0] for xi in x]
# leave out the following line if you don't need the vertical lines
plt.step([0] + x, [y[0]] + y, color='black', ls=':', lw=0.5, where='pre')
used_legend_ids = set()
for xi0, xi1, yi in zip([0] + x[:-1], x, y):
legend_id = dict[xi1][1]
color, label = legendMap[legend_id]
if legend_id in used_legend_ids:
label = None
else:
used_legend_ids.add(legend_id)
plt.plot([xi0, xi1], [yi] * 2, color=color, label=label)
plt.xticks(x)
plt.gca().yaxis.set_major_locator(MultipleLocator(25)) # set a tick every 25 units
plt.legend()
plt.show()
PS: To draw bars instead of horizontal lines, you could replace
plt.plot([xi0, xi1], [yi] * 2, color=color, label=label)
by
plt.bar(xi0, yi, width=xi1-xi0, align='edge', color=color, label=label, alpha=0.4)
Or even have both the bars and the lines (in that case you should leave out one of the two label=label
parameters, to avoid a double legend).
To draw the plot of the comments, you could iterate through y
similar as through x
:
for xi0, xi1, yi0, yi1 in zip([0] + x[:-1], x, [0] + y[:-1], y):
legend_id = dict[xi1][1]
color, label = legendMap[legend_id]
if legend_id in used_legend_ids:
label = None
else:
used_legend_ids.add(legend_id)
plt.plot([xi0, xi1], [yi0, yi1], color=color, label=label)
Upvotes: 1