FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Support usetex in date Formatters by QuLogic · Pull Request #18558 · matplotlib/matplotlib · GitHub

Repository navigation

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .py  (2) .rst  (1) All 2 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
26 changes: 26 additions & 0 deletions doc/users/next_whats_new/date_usetex.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Date formatters now respect *usetex* rcParam
--------------------------------------------

The `.AutoDateFormatter` and `.ConciseDateFormatter` now respect
:rc:`text.usetex`, and will thus use fonts consistent with TeX rendering of the
default (non-date) formatter. TeX rendering may also be enabled/disabled by
passing the *usetex* parameter when creating the formatter instance.

In the following plot, both the x-axis (dates) and y-axis (numbers) now use the
same (TeX) font:

.. plot::

from datetime import datetime, timedelta
from matplotlib.dates import ConciseDateFormatter

plt.rc('text', usetex=True)

t0 = datetime(1968, 8, 1)
ts = [t0 + i * timedelta(days=1) for i in range(10)]

fig, ax = plt.subplots()
ax.plot(ts, range(10))
ax.xaxis.set_major_formatter(ConciseDateFormatter(ax.xaxis.get_major_locator()))
ax.set_xlabel('Date')
ax.set_ylabel('Value')
71 changes: 57 additions & 14 deletions lib/matplotlib/dates.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@
import dateutil.tz
import numpy as np

import matplotlib
import matplotlib as mpl
import matplotlib.units as units
import matplotlib.cbook as cbook
import matplotlib.ticker as ticker
Expand All @@ -187,7 +187,7 @@

def _get_rc_timezone():
"""Retrieve the preferred timezone from the rcParams dictionary."""
s = matplotlib.rcParams['timezone']
s = mpl.rcParams['timezone']
if s == 'UTC':
return UTC
return dateutil.tz.gettz(s)
Expand Down Expand Up @@ -281,7 +281,7 @@ def get_epoch():
global _epoch

if _epoch is None:
_epoch = matplotlib.rcParams['date.epoch']
_epoch = mpl.rcParams['date.epoch']
return _epoch


Expand Down Expand Up @@ -583,6 +583,12 @@ def drange(dstart, dend, delta):
f2 = date2num(dinterval_end) # new float-endpoint
return np.linspace(f1, f2, num + 1)


def _wrap_in_tex(text):
# Braces ensure dashes are not spaced like binary operators.
return '$\\mathdefault{' + text.replace('-', '{-}') + '}$'


## date tickers and formatters ###


Expand All @@ -597,22 +603,28 @@ class DateFormatter(ticker.Formatter):
def illegal_s(self):
return re.compile(r"((^|[^%])(%%)*%s)")

def __init__(self, fmt, tz=None):
def __init__(self, fmt, tz=None, *, usetex=None):
"""
Parameters
----------
fmt : str
`~datetime.datetime.strftime` format string
tz : `datetime.tzinfo`, default: :rc:`timezone`
Ticks timezone.
usetex : bool, default: :rc:`text.usetex`
To enable/disable the use of TeX's math mode for rendering the
results of the formatter.
"""
if tz is None:
tz = _get_rc_timezone()
self.fmt = fmt
self.tz = tz
self._usetex = (usetex if usetex is not None else
mpl.rcParams['text.usetex'])

def __call__(self, x, pos=0):
return num2date(x, self.tz).strftime(self.fmt)
result = num2date(x, self.tz).strftime(self.fmt)
return _wrap_in_tex(result) if self._usetex else result

def set_tzinfo(self, tz):
self.tz = tz
Expand Down Expand Up @@ -685,6 +697,10 @@ class ConciseDateFormatter(ticker.Formatter):
show_offset : bool, default: True
Whether to show the offset or not.

usetex : bool, default: :rc:`text.usetex`
To enable/disable the use of TeX's math mode for rendering the results
of the formatter.

Examples
--------
See :doc:`/gallery/ticks_and_spines/date_concise_formatter`
Expand Down Expand Up @@ -713,7 +729,7 @@ class ConciseDateFormatter(ticker.Formatter):
"""

def __init__(self, locator, tz=None, formats=None, offset_formats=None,
zero_formats=None, show_offset=True):
zero_formats=None, show_offset=True, *, usetex=None):
"""
Autoformat the date labels. The default format is used to form an
initial string, and then redundant elements are removed.
Expand Down Expand Up @@ -768,9 +784,12 @@ def __init__(self, locator, tz=None, formats=None, offset_formats=None,
'%Y-%b-%d %H:%M']
self.offset_string = ''
self.show_offset = show_offset
self._usetex = (usetex if usetex is not None else
mpl.rcParams['text.usetex'])

def __call__(self, x, pos=None):
formatter = DateFormatter(self.defaultfmt, self._tz)
formatter = DateFormatter(self.defaultfmt, self._tz,
usetex=self._usetex)
return formatter(x, pos=pos)

def format_ticks(self, values):
Expand Down Expand Up @@ -837,8 +856,13 @@ def format_ticks(self, values):
if self.show_offset:
# set the offset string:
self.offset_string = tickdatetime[-1].strftime(offsetfmts[level])
if self._usetex:
self.offset_string = _wrap_in_tex(self.offset_string)

return labels
if self._usetex:
return [_wrap_in_tex(l) for l in labels]
else:
return labels

def get_offset(self):
return self.offset_string
Expand Down Expand Up @@ -903,17 +927,36 @@ class AutoDateFormatter(ticker.Formatter):
# Or more simply, perhaps just a format string for each
# possibility...

def __init__(self, locator, tz=None, defaultfmt='%Y-%m-%d'):
def __init__(self, locator, tz=None, defaultfmt='%Y-%m-%d', *,
usetex=None):
"""
Autoformat the date labels. The default format is the one to use
if none of the values in ``self.scaled`` are greater than the unit
returned by ``locator._get_unit()``.
Autoformat the date labels.

Parameters
----------
locator : `.ticker.Locator`
Locator that this axis is using.

tz : str, optional
Passed to `.dates.date2num`.

defaultfmt : str
The default format to use if none of the values in ``self.scaled``
are greater than the unit returned by ``locator._get_unit()``.

usetex : bool, default: :rc:`text.usetex`
To enable/disable the use of TeX's math mode for rendering the
results of the formatter. If any entries in ``self.scaled`` are set
as functions, then it is up to the customized function to enable or
disable TeX's math mode itself.
"""
self._locator = locator
self._tz = tz
self.defaultfmt = defaultfmt
self._formatter = DateFormatter(self.defaultfmt, tz)
rcParams = matplotlib.rcParams
rcParams = mpl.rcParams
self._usetex = (usetex if usetex is not None else
mpl.rcParams['text.usetex'])
self.scaled = {
DAYS_PER_YEAR: rcParams['date.autoformatter.year'],
DAYS_PER_MONTH: rcParams['date.autoformatter.month'],
Expand All @@ -938,7 +981,7 @@ def __call__(self, x, pos=None):
self.defaultfmt)

if isinstance(fmt, str):
self._formatter = DateFormatter(fmt, self._tz)
self._formatter = DateFormatter(fmt, self._tz, usetex=self._usetex)
result = self._formatter(x, pos)
elif callable(fmt):
result = fmt(x, pos)
Expand Down
53 changes: 53 additions & 0 deletions lib/matplotlib/tests/test_dates.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,26 @@ def callable_formatting_function(dates, _):
assert formatter([datetime.datetime(2014, 12, 25)]) == ['25-12//2014']


@pytest.mark.parametrize('delta, expected', [
(datetime.timedelta(weeks=52 * 200),
[r'$\mathdefault{%d}$' % (year,) for year in range(1990, 2171, 20)]),
(datetime.timedelta(days=30),
[r'$\mathdefault{Jan %02d 1990}$' % (day,) for day in range(1, 32, 3)]),
(datetime.timedelta(hours=20),
[r'$\mathdefault{%02d:00:00}$' % (hour,) for hour in range(0, 21, 2)]),
])
def test_date_formatter_usetex(delta, expected):
d1 = datetime.datetime(1990, 1, 1)
d2 = d1 + delta

locator = mdates.AutoDateLocator(interval_multiples=False)
locator.create_dummy_axis()
locator.set_view_interval(mdates.date2num(d1), mdates.date2num(d2))

formatter = mdates.AutoDateFormatter(locator, usetex=True)
assert [formatter(loc) for loc in locator()] == expected


def test_drange():
"""
This test should check if drange works as expected, and if all the
Expand Down Expand Up @@ -503,6 +523,39 @@ def _create_auto_date_locator(date1, date2):
assert strings == expected


@pytest.mark.parametrize('t_delta, expected', [
(datetime.timedelta(weeks=52 * 200),
['$\\mathdefault{%d}$' % (t, ) for t in range(1980, 2201, 20)]),
(datetime.timedelta(days=40),
['$\\mathdefault{Jan}$', '$\\mathdefault{05}$', '$\\mathdefault{09}$',
'$\\mathdefault{13}$', '$\\mathdefault{17}$', '$\\mathdefault{21}$',
'$\\mathdefault{25}$', '$\\mathdefault{29}$', '$\\mathdefault{Feb}$',
'$\\mathdefault{05}$', '$\\mathdefault{09}$']),
(datetime.timedelta(hours=40),
['$\\mathdefault{Jan{-}01}$', '$\\mathdefault{04:00}$',
'$\\mathdefault{08:00}$', '$\\mathdefault{12:00}$',
'$\\mathdefault{16:00}$', '$\\mathdefault{20:00}$',
'$\\mathdefault{Jan{-}02}$', '$\\mathdefault{04:00}$',
'$\\mathdefault{08:00}$', '$\\mathdefault{12:00}$',
'$\\mathdefault{16:00}$']),
(datetime.timedelta(seconds=2),
['$\\mathdefault{59.5}$', '$\\mathdefault{00:00}$',
'$\\mathdefault{00.5}$', '$\\mathdefault{01.0}$',
'$\\mathdefault{01.5}$', '$\\mathdefault{02.0}$',
'$\\mathdefault{02.5}$']),
])
def test_concise_formatter_usetex(t_delta, expected):
d1 = datetime.datetime(1997, 1, 1)
d2 = d1 + t_delta

locator = mdates.AutoDateLocator(interval_multiples=True)
locator.create_dummy_axis()
locator.set_view_interval(mdates.date2num(d1), mdates.date2num(d2))

formatter = mdates.ConciseDateFormatter(locator, usetex=True)
assert formatter.format_ticks(locator()) == expected


def test_concise_formatter_formats():
formats = ['%Y', '%m/%Y', 'day: %d',
'%H hr %M min', '%H hr %M min', '%S.%f sec']
Expand Down

Back | FazBrowse Home | New Git URL