I’m extremely new to matplotlib and I’m trying to create a discord bot in python that simply logs the server activity and displays it as a line graph based on what time the server is most active (msgs per 10sec / time of day). The problem is, the number of messages is different from the amount of seconds in a day 99.99% of the time, so the 2 lists don’t match and I get
ValueError: x and y must have same first dimension,
My lists are made like this:
instances= [(6209, 10), (42906, 20), (70182, 23), (30422, 18), (70503, 21), (8426, 12), (78322, 22), (27038, 17), (1453, 2), (36138, 3)] times= [0, 3600, 7200, 10800, 14400, 18000, 21600, 25200, 28800, 32400, 36000, 39600, 43200, 46800, 50400, 54000, 57600, 61200, 64800, 68400, 72000, 75600, 79200]
So I have a list of (what time, how many msgs) and a list of each hour of the day in seconds, So I could graph them as this many msgs happened at this time of day.
How would I plot them onto a single graph, because ax.plot (instances, times)
gives me the error. I have searched other answers, but none have helped me.
Advertisement
Answer
- In this case, the data is displayed better as a barplot.
- Extract seconds and values from
instances
to separate variable - Convert the secondes to a standard time format of
H:M:S
- It doesn’t seem like
times
is required.
import matplotlib.pyplot as plt import seaborn as sns from datetime import timedelta instances= [(6209, 10), (42906, 20), (70182, 23), (30422, 18), (70503, 21), (8426, 12), (78322, 22), (27038, 17), (1453, 2), (36138, 3)] # separate out x and convert from seconds to H:M:S x = [timedelta(seconds=v[0]) for v in instances] # separate out the y values y = [v[1] for v in instances] # sort x and y, based on time x, y = zip(*sorted(zip(x, y))) # convert from tuples to lists because barplot won't work with tuples x, y = list(x), list(y) # plot fig = plt.figure(figsize=(10, 5)) p = sns.barplot(x=x, y=y) p.set(xlabel='Observation Time', ylabel='Activity Count', title='Messages') # annotate p.bar_label(p.containers[0], label_type='edge', padding=1) # pad the spacing between the number and the edge of the figure p.margins(y=0.1)
- Plot as a line plot
import matplotlib.pyplot as plt import matplotlib.ticker as mticker from datetime import timedelta instances= [(6209, 10), (42906, 20), (70182, 23), (30422, 18), (70503, 21), (8426, 12), (78322, 22), (27038, 17), (1453, 2), (36138, 3)] # separate out the x values x = [v[0] for v in instances] # separate out the y values y = [v[1] for v in instances] # sort x and y, based on time x, y = zip(*sorted(zip(x, y))) fig, ax = plt.subplots(figsize=(10, 5)) ax.plot(x, y, marker='o') # fixing xticks with matplotlib.ticker "FixedLocator" xticks_loc = ax.get_xticks() ax.xaxis.set_major_locator(mticker.FixedLocator(xticks_loc)) _ = ax.set_xticklabels([timedelta(seconds=tm) for tm in xticks_loc])
- If you want more hours on the xaxis, instead of using
ax.get_xticks
, pass alist
of values, or userange
)xticks_loc = range(0, 86400, 3600)
and also addax.set_xlim(0, 86400)
- Probably increase the width of the figure
fig, ax = plt.subplots(figsize=(15, 5))
- Rotate the xaxis labels
_ = ax.set_xticklabels([timedelta(seconds=tm) for tm in xticks_loc], rotation=45)
# fixing xticks with matplotlib.ticker "FixedLocator" ax.set_xlim(0, 86400) xticks_loc = range(0, 86400, 3600) ax.xaxis.set_major_locator(mticker.FixedLocator(xticks_loc)) _ = ax.set_xticklabels([timedelta(seconds=tm) for tm in xticks_loc], rotation=45)