DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run Scan×
Skip to content
World desk6 min

Create a Matplotlib Boxplot for Time Series Data in Python

To make a Matplotlib boxplot for time series data, group the raw observations into one array per time period with pandas, then pass that list to ax.boxplot. Here is the full method, the aggregation mistake to avoid, and how to use a true date axis.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To draw a boxplot for time series data in Matplotlib, you need one numeric sample for each time period, such as every observation recorded in January, then February, and so on. Matplotlib draws one box per sample. The chart compares how values are spread within each period. It does not show the order of readings inside a period or the overall direction of change, so if trend is your main question, pair the boxes with a line plot.

What each box shows

The box runs from the first quartile (Q1) to the third quartile (Q3) of the data, with a line at the median. By default, whiskers extend to the most distant observations that lie within 1.5 times the interquartile range (IQR) of the box. Points beyond the whiskers are drawn as individual fliers. The whisker ends are therefore not necessarily the minimum and maximum of the period. These rules come from the Matplotlib boxplot API documentation.

As an Amazon Associate I earn from qualifying purchases.

Every box describes whatever you put into its sample. That makes the grouping step the most important decision in the whole chart.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Step-by-step: one boxplot per month

  1. Confirm the data types. Your DataFrame needs a datetime-like timestamp column and a numeric value column. Convert the timestamps with pd.to_datetime so that pandas can group them by calendar period.

  2. Drop unusable rows and set a sorted index. Missing timestamps or values cannot be placed in a period, so remove them before grouping:

    import matplotlib.pyplot as plt
    import pandas as pd
    
    work = df.assign(timestamp=pd.to_datetime(df["timestamp"]))
    work = work.dropna(subset=["timestamp", "value"])
    work = work.set_index("timestamp").sort_index()
  3. Group the raw values by period. DataFrame.resample performs a time-based groupby on a datetime index, and it can be followed by a reduction. For a boxplot, you skip the reduction and keep the values. The "MS" alias groups by month start. Empty months are removed in the same step:

    periods = [
        (period.strftime("%Y-%m"), group.to_numpy())
        for period, group in work["value"].resample("MS")
        if len(group) > 0
    ]
    labels, samples = zip(*periods)
  4. Draw the boxes. ax.boxplot accepts a sequence of one-dimensional arrays and draws one box per array. Pass the labels through tick_labels, which is the current name for this argument:

    Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
    fig, ax = plt.subplots(figsize=(10, 5))
    ax.boxplot(samples, tick_labels=labels, showfliers=True)
    ax.set_xlabel("Month")
    ax.set_ylabel("Value")
    ax.set_title("Distribution of observations by month")
    ax.tick_params(axis="x", labelrotation=45)
    fig.tight_layout()
    plt.show()

    If you are working with an older Matplotlib release, check the installed version before using tick_labels. Earlier code often used labels instead, so an error on that argument usually points to a version mismatch.

The result is one box per month, with each box built from every raw measurement recorded in that month.

The aggregation trap: do not average first

A common shortcut is to write work["value"].resample("MS").mean() and plot the result. That produces one number per month, so the boxes would summarise the spread of monthly averages across months, not the variation of readings within each month. The chart would look like a distribution, but it would answer a different question.

Decide the question first, then choose the grouping to match it:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Question What to group What each box shows
How variable are readings within each month? Raw observations per month Spread of individual readings in that month
How do monthly averages vary from month to month? Monthly means, pooled across a larger set of groups Spread of those means, which needs enough groups to be meaningful
How does one month compare with the same month in other years? Raw observations grouped by calendar month across years Pooled readings for that calendar month

The pandas resample documentation describes the grouping and reduction process, and the pandas resample API reference lists the options for each bin. The closed argument controls which bin edge belongs to a bin, and label controls how each bin is named. Check both when your timestamps fall exactly on period boundaries, because a reading recorded at midnight on the first day of a month may land in the previous bin depending on those settings. The pandas time-series user guide covers the general behaviour.

Handling unequal and missing periods

Real series rarely have the same number of readings in every period. Before you draw, count the observations per period so you can judge whether a box is trustworthy:

  • A box built from very few values can look precise when it is not. Consider a minimum sample size and drop or flag periods below it.
  • An empty period should be left out, not drawn as a zero-valued box. The code above removes empty months for this reason.
  • When sample sizes differ widely, say so in the caption or axis title, because the visual weight of each box does not reflect its count.
  • Keep the same bin definition across every comparison. If you compare two sensors or two sites, use identical period edges and, where it helps, the same y-axis limits.

Using a continuous date axis

Text labels work well when the periods are discrete, such as months, weekdays, or seasons. If real elapsed time matters, or your bins are unevenly spaced, place each box at its date instead.

Matplotlib represents dates as floating-point day counts from the default 1970-01-01 UTC epoch, and matplotlib.dates.date2num performs the conversion. Each box then takes a numeric position. Because the widths argument is measured in data units, a width of 1 would be one day, so set it to a value close to the bin size. For monthly boxes, a width around 20 days is a reasonable start:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import matplotlib.dates as mdates
import matplotlib.pyplot as plt

periods = [
    (period.to_pydatetime(), group.to_numpy())
    for period, group in work["value"].resample("MS")
    if len(group) > 0
]
positions = [mdates.date2num(start) for start, _ in periods]
samples = [values for _, values in periods]

fig, ax = plt.subplots(figsize=(10, 5))
ax.boxplot(samples, positions=positions, widths=20)
ax.xaxis.set_major_locator(mdates.AutoDateLocator())
ax.xaxis.set_major_formatter(mdates.ConciseDateFormatter(ax.xaxis.get_major_locator()))
ax.set_xlabel("Month")
ax.set_ylabel("Value")
fig.tight_layout()
plt.show()

Do not supply strings as positions and expect them to act as axis labels. The positions are numeric coordinates, and the text labels belong in tick_labels or in the date formatter. The Matplotlib dates API documentation describes the automatic locators and formatters, and it notes that Matplotlib converts datetime.datetime and numpy.datetime64 objects when they are plotted on an axis.

Precision also depends on the date range. The same documentation says that microsecond precision holds for dates roughly 70 years on either side of the epoch and degrades farther away. Ordinary daily or monthly charts are unaffected. Plots that need sub-microsecond resolution should use floating-point seconds instead, and any change to the epoch must happen before dates are converted.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

When a boxplot is not enough

A boxplot answers the question of distribution by period. It cannot show whether a series is rising, falling, or cycling within a period, because the order of observations is discarded. If trend is part of your question, draw the raw series as a line and add the boxplot in a second panel, sharing the x-axis. That layout lets a reader see the change over time and the spread in each period together.

For multi-column data, pandas can also draw grouped boxplots through DataFrameGroupBy.boxplot, documented in the pandas grouped boxplot API reference. Use it when pandas already holds the grouping you need. The Matplotlib approach above gives you more control over tick labels, date positions, and styling.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Quick checklist before you publish the chart

  • Each box is built from raw values, unless you deliberately want a distribution of summaries.
  • Empty periods are removed rather than drawn as zero.
  • Sample sizes per period are known and, where they are small, flagged.
  • Labels use tick_labels for discrete periods, or numeric positions with a date formatter for true time spacing.
  • The axis titles name the period and the measured quantity, so a reader can tell what each box represents.

”

The Bottom Line

“”

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.