Search code examples
matplotlibaxisaxis-labels

plot the x axis as MM:SS instead of integer in a histogram


I have ambulance response time data as seconds. For example (32, 158, 36, 459, 830, 396). I am able to make a Matplotlib histogram binning the data into 60 second increments. On the x axis label the data is labelled as 0 - 60 - 120 - 180 etc. I would like the x axis label to show 00:00 - 01:00 - 02:00 - 03:00 etc. In other words, instead of seconds as integer values, it should show seconds formatted as mm:ss. The code below comes close but I am not able to make it work. The code below only returns 00:00 for all bins. How can I label the x axis of a histogram as mm:ss instead of integers?

# import the libraries
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
# generate a dataframe of values from 0 to 1800 (zero seconds to 1800 seconds which is 30 minutes)
df = pd.DataFrame(np.random.randint(0,1800, size=(1000, 1)), columns=list('A'))

start_value = 0 # the start value is zero seconds
end_value = 1800 # the end value is 1800 seconds (30 minutes)
increment_by_value = 60 # increment by one minute

# set up the nuts and bolts of the histogram
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(8, 6.5)
ax = fig.add_subplot(111)

# generate a histogram
plt.hist(df.A, bins=np.arange(start_value, end_value, increment_by_value), color='Purple', label='Response Time', edgecolor = 'Gray', linewidth = 1.0)

# not sure how this works. I would hope that it formats 75 seconds to 01:15
myFmt = mdates.DateFormatter('%M:%S')
ax.xaxis.set_major_formatter(myFmt)

# the x ticks line up with the bars. In other words, every 60 seconds
plt.xticks(np.arange(start_value, end_value, increment_by_value), rotation='vertical')

# set up the title and the labels
plt.title("Cardiac Arrest Response Time" + '\n' + '(Interval in Seconds)')
plt.xlabel("Bins of 1 minute (in seconds)")
plt.ylabel("Calls")
plt.legend()
plt.show()

Solution

  • I suspect the issue is because DateFormatter expects input in days since the standard epoch.

    A quick way to get around this is to remove mdates altogether, and just define a simple FuncFormatter from the matplotlib.ticker module. For example, replace these two lines:

    myFmt = mdates.DateFormatter('%M:%S')
    ax.xaxis.set_major_formatter(myFmt)
    

    with

    import matplotlib.ticker as ticker
    
    # Formatter function to convert seconds to MM:SS format
    def seconds_to_minutes(seconds, pos):
        m = int(seconds // 60)
        s = int(seconds % 60)
        return f'{m:02d}:{s:02d}'
    
    ax.xaxis.set_major_formatter(ticker.FuncFormatter(seconds_to_minutes))
    

    Image showing plot with x-tick labels formatter as %M:%S