Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6b6f120

Browse files
committed
ENH: add rcParam for ConciseDate and interval_multiples
1 parent 09d8da2 commit 6b6f120

File tree

5 files changed

+134
-9
lines changed

5 files changed

+134
-9
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
New rcParams for dates: set converter and whether to use interval_multiples
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
The new :rc:`dates.converter` allows toggling between
5+
`matplotlib.dates.DateConverter` and `matplotlib.dates.ConciseDateConverter`
6+
using the strings 'auto' and 'concise' respectively.
7+
8+
The new :rc:`dates.interval_multiples` allows toggling between the dates
9+
locator trying to pick ticks at set intervals (i.e. day 1 and 15 of the
10+
month), versus evenly spaced ticks that start where ever the
11+
timeseries starts.

lib/matplotlib/dates.py

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,8 +1832,11 @@ class DateConverter(units.ConversionInterface):
18321832
The 'unit' tag for such data is None or a tzinfo instance.
18331833
"""
18341834

1835-
@staticmethod
1836-
def axisinfo(unit, axis):
1835+
def __init__(self, interval_multiples=True):
1836+
self._interval_multiples = interval_multiples
1837+
super().__init__()
1838+
1839+
def axisinfo(self, unit, axis):
18371840
"""
18381841
Return the `~matplotlib.units.AxisInfo` for *unit*.
18391842
@@ -1842,7 +1845,8 @@ def axisinfo(unit, axis):
18421845
"""
18431846
tz = unit
18441847

1845-
majloc = AutoDateLocator(tz=tz)
1848+
majloc = AutoDateLocator(tz=tz,
1849+
interval_multiples=self._interval_multiples)
18461850
majfmt = AutoDateFormatter(majloc, tz=tz)
18471851
datemin = datetime.date(2000, 1, 1)
18481852
datemax = datetime.date(2010, 1, 1)
@@ -1884,17 +1888,19 @@ class ConciseDateConverter(DateConverter):
18841888
# docstring inherited
18851889

18861890
def __init__(self, formats=None, zero_formats=None, offset_formats=None,
1887-
show_offset=True):
1891+
show_offset=True, interval_multiples=True):
18881892
self._formats = formats
18891893
self._zero_formats = zero_formats
18901894
self._offset_formats = offset_formats
18911895
self._show_offset = show_offset
1896+
self._interval_multiples = interval_multiples
18921897
super().__init__()
18931898

18941899
def axisinfo(self, unit, axis):
18951900
# docstring inherited
18961901
tz = unit
1897-
majloc = AutoDateLocator(tz=tz)
1902+
majloc = AutoDateLocator(tz=tz,
1903+
interval_multiples=self._interval_multiples)
18981904
majfmt = ConciseDateFormatter(majloc, tz=tz, formats=self._formats,
18991905
zero_formats=self._zero_formats,
19001906
offset_formats=self._offset_formats,
@@ -1905,6 +1911,44 @@ def axisinfo(self, unit, axis):
19051911
default_limits=(datemin, datemax))
19061912

19071913

1908-
units.registry[np.datetime64] = DateConverter()
1909-
units.registry[datetime.date] = DateConverter()
1910-
units.registry[datetime.datetime] = DateConverter()
1914+
1915+
1916+
class _rcParam_helper:
1917+
"""
1918+
This helper class is so that we can set the converter for dates
1919+
via the validator for the rcParams `date.converter` and
1920+
`date.interval_multiples`. Never instatiated.
1921+
"""
1922+
1923+
conv_st = 'auto'
1924+
int_mult = True
1925+
1926+
@classmethod
1927+
def set_converter(cls, s):
1928+
"""Called by validator for rcParams date.converter"""
1929+
cls.conv_st = s
1930+
cls.register_converters()
1931+
1932+
@classmethod
1933+
def set_int_mult(cls, b):
1934+
"""Called by validator for rcParams date.interval_multiples"""
1935+
cls.int_mult = b
1936+
cls.register_converters()
1937+
1938+
@classmethod
1939+
def register_converters(cls):
1940+
"""
1941+
Helper to register the date converters when rcParams `date.converter`
1942+
and `date.interval_multiples` are changed. Called by the helpers
1943+
above.
1944+
"""
1945+
if cls.conv_st == 'concise':
1946+
converter = ConciseDateConverter
1947+
else:
1948+
converter = DateConverter
1949+
1950+
interval_multiples = cls.int_mult
1951+
convert = converter(interval_multiples=interval_multiples)
1952+
units.registry[np.datetime64] = convert
1953+
units.registry[datetime.date] = convert
1954+
units.registry[datetime.datetime] = convert

lib/matplotlib/rcsetup.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,27 @@ def validate_bool_maybe_none(b):
174174
raise ValueError('Could not convert "%s" to bool' % b)
175175

176176

177+
def _validate_date_converter(s):
178+
s = validate_string(s)
179+
try:
180+
import matplotlib.dates as mdates
181+
mdates._rcParam_helper.set_converter(s)
182+
except Exception as e:
183+
pass
184+
185+
186+
def _validate_date_int_mult(s):
187+
if s is None:
188+
return
189+
s = validate_bool(s)
190+
try:
191+
import matplotlib.dates as mdates
192+
mdates._rcParam_helper.set_int_mult(s)
193+
except Exception:
194+
# this can fail at import because mdates ends up as a circular import.
195+
pass
196+
197+
177198
def _validate_tex_preamble(s):
178199
if s is None or s == 'None':
179200
cbook.warn_deprecated(
@@ -1271,13 +1292,19 @@ def _convert_validator_spec(key, conv):
12711292
"date.autoformatter.second": validate_string,
12721293
"date.autoformatter.microsecond": validate_string,
12731294

1295+
# 'auto', 'concise', 'auto-noninterval'
1296+
'date.converter': _validate_date_converter,
1297+
# for auto date locator, choose interval_multiples
1298+
'date.interval_multiples': _validate_date_int_mult,
1299+
12741300
# legend properties
12751301
"legend.fancybox": validate_bool,
12761302
"legend.loc": _ignorecase([
12771303
"best",
12781304
"upper right", "upper left", "lower left", "lower right", "right",
12791305
"center left", "center right", "lower center", "upper center",
12801306
"center"]),
1307+
12811308
# the number of points in the legend line
12821309
"legend.numpoints": validate_int,
12831310
# the number of points in the legend line for scatter

lib/matplotlib/tests/test_dates.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,3 +947,43 @@ def test_change_epoch():
947947
np.testing.assert_allclose(
948948
mdates.date2num(np.datetime64('1970-01-01T12:00:00')),
949949
0.5)
950+
951+
952+
def test_change_converter():
953+
954+
plt.rcParams['date.converter'] = 'concise'
955+
dates = np.arange('2020-01-01', '2020-05-01', dtype='datetime64[D]')
956+
fig, ax = plt.subplots()
957+
958+
ax.plot(dates, np.arange(len(dates)))
959+
fig.canvas.draw()
960+
assert ax.get_xticklabels()[0].get_text() == 'Jan'
961+
assert ax.get_xticklabels()[1].get_text() == '15'
962+
963+
plt.rcParams['date.converter'] = 'auto'
964+
fig, ax = plt.subplots()
965+
966+
ax.plot(dates, np.arange(len(dates)))
967+
fig.canvas.draw()
968+
assert ax.get_xticklabels()[0].get_text() == 'Jan 01 2020'
969+
assert ax.get_xticklabels()[1].get_text() == 'Jan 15 2020'
970+
971+
972+
def test_change_interval_multiples():
973+
974+
plt.rcParams['date.interval_multiples'] = False
975+
dates = np.arange('2020-01-10', '2020-05-01', dtype='datetime64[D]')
976+
fig, ax = plt.subplots()
977+
978+
ax.plot(dates, np.arange(len(dates)))
979+
fig.canvas.draw()
980+
assert ax.get_xticklabels()[0].get_text() == 'Jan 10 2020'
981+
assert ax.get_xticklabels()[1].get_text() == 'Jan 24 2020'
982+
983+
plt.rcParams['date.interval_multiples'] = 'True'
984+
fig, ax = plt.subplots()
985+
986+
ax.plot(dates, np.arange(len(dates)))
987+
fig.canvas.draw()
988+
assert ax.get_xticklabels()[0].get_text() == 'Jan 15 2020'
989+
assert ax.get_xticklabels()[1].get_text() == 'Feb 01 2020'

matplotlibrc.template

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,10 +442,13 @@
442442
#date.autoformatter.minute: %d %H:%M
443443
#date.autoformatter.second: %H:%M:%S
444444
#date.autoformatter.microsecond: %M:%S.%f
445-
446445
## The reference date for Matplotlib's internal date representation
447446
## See https://matplotlib.org/examples/ticks_and_spines/date_precision_and_epochs.py
448447
#date.epoch: 1970-01-01T00:00:00
448+
## 'auto', 'concise':
449+
#date.converter: auto
450+
## For auto converter whether to use interval_multiples:
451+
#date.interval_multiples: True
449452

450453
## ***************************************************************************
451454
## * TICKS *

0 commit comments

Comments
 (0)