|
| 1 | +""" |
| 2 | +================================================ |
| 3 | +Formatting date ticks using ConciseDateFormatter |
| 4 | +================================================ |
| 5 | +
|
| 6 | +Finding good tick values and formatting the ticks for an axis that |
| 7 | +has date data is often a challenge. `~.dates.ConciseDateFormatter` is |
| 8 | +meant to improve the strings chosen for the ticklabels, and to minimize |
| 9 | +the strings used in those tick labels as much as possible. |
| 10 | +
|
| 11 | +.. note:: |
| 12 | +
|
| 13 | + This formatter is a candidate to become the default date tick formatter |
| 14 | + in future versions of Matplotlib. Please report any issues or |
| 15 | + suggestions for improvement to the github repository or mailing list. |
| 16 | +
|
| 17 | +""" |
| 18 | +import datetime |
| 19 | +import matplotlib.pyplot as plt |
| 20 | +import matplotlib.dates as mdates |
| 21 | +import numpy as np |
| 22 | + |
| 23 | +############################################################################# |
| 24 | +# First, the default formatter. |
| 25 | + |
| 26 | +base = datetime.datetime(2005, 2, 1) |
| 27 | +dates = np.array([base + datetime.timedelta(hours=(2 * i)) |
| 28 | + for i in range(732)]) |
| 29 | +N = len(dates) |
| 30 | +np.random.seed(19680801) |
| 31 | +y = np.cumsum(np.random.randn(N)) |
| 32 | + |
| 33 | +fig, axs = plt.subplots(3, 1, constrained_layout=True, figsize=(6, 6)) |
| 34 | +lims = [(np.datetime64('2005-02'), np.datetime64('2005-04')), |
| 35 | + (np.datetime64('2005-02-03'), np.datetime64('2005-02-15')), |
| 36 | + (np.datetime64('2005-02-03 11:00'), np.datetime64('2005-02-04 13:20'))] |
| 37 | +for nn, ax in enumerate(axs): |
| 38 | + ax.plot(dates, y) |
| 39 | + ax.set_xlim(lims[nn]) |
| 40 | + # rotate_labels... |
| 41 | + for label in ax.get_xticklabels(): |
| 42 | + label.set_rotation(40) |
| 43 | + label.set_horizontalalignment('right') |
| 44 | +axs[0].set_title('Default Date Formatter') |
| 45 | +plt.show() |
| 46 | + |
| 47 | +############################################################################# |
| 48 | +# The default date formater is quite verbose, so we have the option of |
| 49 | +# using `~.dates.ConciseDateFormatter`, as shown below. Note that |
| 50 | +# for this example the labels do not need to be rotated as they do for the |
| 51 | +# default formatter because the labels are as small as possible. |
| 52 | + |
| 53 | +fig, axs = plt.subplots(3, 1, constrained_layout=True, figsize=(6, 6)) |
| 54 | +for nn, ax in enumerate(axs): |
| 55 | + locator = mdates.AutoDateLocator(minticks=3, maxticks=7) |
| 56 | + formatter = mdates.ConciseDateFormatter(locator) |
| 57 | + ax.xaxis.set_major_locator(locator) |
| 58 | + ax.xaxis.set_major_formatter(formatter) |
| 59 | + |
| 60 | + ax.plot(dates, y) |
| 61 | + ax.set_xlim(lims[nn]) |
| 62 | +axs[0].set_title('Concise Date Formatter') |
| 63 | + |
| 64 | +plt.show() |
| 65 | + |
| 66 | +############################################################################# |
| 67 | +# If all calls to axes that have dates are to be made using this converter, |
| 68 | +# it is probably most convenient to use the units registry where you do |
| 69 | +# imports: |
| 70 | + |
| 71 | +import matplotlib.units as munits |
| 72 | +converter = mdates.ConciseDateConverter() |
| 73 | +munits.registry[np.datetime64] = converter |
| 74 | +munits.registry[datetime.date] = converter |
| 75 | +munits.registry[datetime.datetime] = converter |
| 76 | + |
| 77 | +fig, axs = plt.subplots(3, 1, figsize=(6, 6), constrained_layout=True) |
| 78 | +for nn, ax in enumerate(axs): |
| 79 | + ax.plot(dates, y) |
| 80 | + ax.set_xlim(lims[nn]) |
| 81 | +axs[0].set_title('Concise Date Formatter') |
| 82 | + |
| 83 | +plt.show() |
| 84 | + |
| 85 | +############################################################################# |
| 86 | +# Localization of date formats |
| 87 | +# ============================ |
| 88 | +# |
| 89 | +# Dates formats can be localized if the default formats are not desirable by |
| 90 | +# manipulating one of three lists of strings. |
| 91 | +# |
| 92 | +# The ``formatter.formats`` list of formats is for the normal tick labels, |
| 93 | +# There are six levels: years, months, days, hours, minutes, seconds. |
| 94 | +# The ``formatter.offset_formats`` is how the "offset" string on the right |
| 95 | +# of the axis is formatted. This is usually much more verbose than the tick |
| 96 | +# labels. Finally, the ``formatter.zero_formats`` are the formats of the |
| 97 | +# ticks that are "zeros". These are tick values that are either the first of |
| 98 | +# the year, month, or day of month, or the zeroth hour, minute, or second. |
| 99 | +# These are usually the same as the format of |
| 100 | +# the ticks a level above. For example if the axis limts mean the ticks are |
| 101 | +# mostly days, then we label 1 Mar 2005 simply with a "Mar". If the axis |
| 102 | +# limits are mostly hours, we label Feb 4 00:00 as simply "Feb-4". |
| 103 | +# |
| 104 | +# Note that these format lists can also be passed to `.ConciseDateFormatter` |
| 105 | +# as optional kwargs. |
| 106 | +# |
| 107 | +# Here we modify the labels to be "day month year", instead of the ISO |
| 108 | +# "year month day": |
| 109 | + |
| 110 | +fig, axs = plt.subplots(3, 1, constrained_layout=True, figsize=(6, 6)) |
| 111 | + |
| 112 | +for nn, ax in enumerate(axs): |
| 113 | + locator = mdates.AutoDateLocator() |
| 114 | + formatter = mdates.ConciseDateFormatter(locator) |
| 115 | + formatter.formats = ['%y', # ticks are mostly years |
| 116 | + '%b', # ticks are mostly months |
| 117 | + '%d', # ticks are mostly days |
| 118 | + '%H:%M', # hrs |
| 119 | + '%H:%M', # min |
| 120 | + '%S.%f', ] # secs |
| 121 | + # these are mostly just the level above... |
| 122 | + formatter.zero_formats = [''] + formatter.formats[:-1] |
| 123 | + # ...except for ticks that are mostly hours, then it is nice to have |
| 124 | + # month-day: |
| 125 | + formatter.zero_formats[3] = '%d-%b' |
| 126 | + |
| 127 | + formatter.offset_formats = ['', |
| 128 | + '%Y', |
| 129 | + '%b %Y', |
| 130 | + '%d %b %Y', |
| 131 | + '%d %b %Y', |
| 132 | + '%d %b %Y %H:%M', ] |
| 133 | + ax.xaxis.set_major_locator(locator) |
| 134 | + ax.xaxis.set_major_formatter(formatter) |
| 135 | + |
| 136 | + ax.plot(dates, y) |
| 137 | + ax.set_xlim(lims[nn]) |
| 138 | +axs[0].set_title('Concise Date Formatter') |
| 139 | + |
| 140 | +plt.show() |
| 141 | + |
| 142 | +############################################################################# |
| 143 | +# Registering a converter with localization |
| 144 | +# ========================================= |
| 145 | +# |
| 146 | +# `.ConciseDateFormatter` doesn't have rcParams entries, but localization |
| 147 | +# can be accomplished by passing kwargs to `~.ConciseDateConverter` and |
| 148 | +# registering the datatypes you will use with the units registry: |
| 149 | + |
| 150 | +import datetime |
| 151 | + |
| 152 | +formats = ['%y', # ticks are mostly years |
| 153 | + '%b', # ticks are mostly months |
| 154 | + '%d', # ticks are mostly days |
| 155 | + '%H:%M', # hrs |
| 156 | + '%H:%M', # min |
| 157 | + '%S.%f', ] # secs |
| 158 | +# these can be the same, except offset by one level.... |
| 159 | +zero_formats = [''] + formats[:-1] |
| 160 | +# ...except for ticks that are mostly hours, then its nice to have month-day |
| 161 | +zero_formats[3] = '%d-%b' |
| 162 | +offset_formats = ['', |
| 163 | + '%Y', |
| 164 | + '%b %Y', |
| 165 | + '%d %b %Y', |
| 166 | + '%d %b %Y', |
| 167 | + '%d %b %Y %H:%M', ] |
| 168 | + |
| 169 | +converter = mdates.ConciseDateConverter(formats=formats, |
| 170 | + zero_formats=zero_formats, |
| 171 | + offset_formats=offset_formats) |
| 172 | + |
| 173 | +munits.registry[np.datetime64] = converter |
| 174 | +munits.registry[datetime.date] = converter |
| 175 | +munits.registry[datetime.datetime] = converter |
| 176 | + |
| 177 | +fig, axs = plt.subplots(3, 1, constrained_layout=True, figsize=(6, 6)) |
| 178 | +for nn, ax in enumerate(axs): |
| 179 | + ax.plot(dates, y) |
| 180 | + ax.set_xlim(lims[nn]) |
| 181 | +axs[0].set_title('Concise Date Formatter registered non-default') |
| 182 | + |
| 183 | +plt.show() |
0 commit comments