Skip to content

[ENH]: ConciseDateFormatter option to control location of offset label #30500

@simonradford

Description

@simonradford

Problem

Feature request

Please add an option to matplotlib.dates.ConciseDateFormatter option to control the location of the offset label. Options could be the ‘right’/‘top’ [default], ‘left’/‘bottom’, or ‘both’ ends of a time axis.

Issue

Often, I plot time series data for one day (or one month). The ConciseDateFormatter is super convenient for labeling. Here’s an example with points every hour for one day:

"""Demonstrate behavior of ConciseDateFormatter offset."""

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import datetime
import numpy as np

fig, ax = plt.subplots()

N = 24
d0 = datetime.datetime(1997, 12, 31)
days = [d0 + datetime.timedelta(hours=i) for i in range(N)]
np.random.seed(19680801)
signal = np.cumsum(np.random.randn(N))

ax.set_title("ConciseDateFormatter behavior")
locator = mdates.AutoDateLocator()
formatter = mdates.ConciseDateFormatter(locator)
ax.xaxis.set_major_locator(locator)
ax.xaxis.set_major_formatter(formatter)
ax.plot(days, signal)

plt.show()
Image

Note the prominent offset label on the right end of the axis, 1998-Jan-01. At a quick glance, a viewer may (reasonably) assume the data correspond to that day, 1998-Jan-01. In fact, however, all the data are for the previous day, 1997-Dec-31. In this example, the offset label indicates the year, month, and day following the data. (I admit the example is contrived for maximum effect!)

The axis labels and offset are not incorrect, per se, but they require the viewer to expend mental effort to figure out the date range of the data. This is a disservice to the viewer.

Workaround

There’s a pretty simple workaround: suppress the ConciseDateFormatter offset label (show_offset = False) and insert an alternate label.

"""Workaround for ConciseDateFormatter offset label."""

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import datetime
import numpy as np

fig, ax = plt.subplots()

N = 24
d0 = datetime.datetime(1997, 12, 31)
days = [d0 + datetime.timedelta(hours=i) for i in range(N)]
np.random.seed(19680801)
signal = np.cumsum(np.random.randn(N))

ax.set_title("Desired behavior")
locator = mdates.AutoDateLocator()
formatter = mdates.ConciseDateFormatter(locator, show_offset=False)
ax.xaxis.set_major_locator(locator)
ax.xaxis.set_major_formatter(formatter)
ax.plot(days, signal)

dlab = mdates.num2date(ax.xaxis.get_ticklocs()[0]).strftime ( "%Y-%b-%d")
ax.text(0, -0.11, dlab, ha="left", color="r", transform=ax.transAxes)

plt.show()
Image

This requires, however, extra code and fiddling with the label position. And, of course, the extra code will be prone to bugs, etc., especially when handling edge cases.

Because ConciseDateFormatter already contains the machinery to generate offset labels, it would be nice to access that machinery to avoid code duplication.

To some extent, the position of the offset label is a matter of taste. Not every situation is the same and not everyone will agree with my preference. It would be nice, however, to have an option available to change the default behavior.

Proposed solution

Please add an 'offset_loc' parameter to matplotlib.dates.ConciseDateFormatter. The options could be ‘right’/‘top’ [default], ‘left’/‘bottom’, or ‘both’.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions