Automatically create tick formatters for str and callable inputs. · matplotlib/matplotlib@e07c5df · GitHub
Skip to content

Commit e07c5df

Browse files
committed
Automatically create tick formatters for str and callable inputs.
1 parent 32d3306 commit e07c5df

6 files changed

Lines changed: 112 additions & 34 deletions

File tree

Lines changed: 7 additions & 0 deletions

examples/ticks_and_spines/tick-formatters.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def setup(ax, title):
3434
fontsize=14, fontname='Monospace', color='tab:blue')
3535

3636

37-
fig, axs = plt.subplots(7, 1, figsize=(8, 6))
37+
fig, axs = plt.subplots(9, 1, figsize=(8, 8))
3838

3939
# Null formatter
4040
setup(axs[0], title="NullFormatter()")
@@ -59,21 +59,30 @@ def major_formatter(x, pos):
5959
setup(axs[2], title='FuncFormatter(lambda x, pos: "[%.2f]" % x)')
6060
axs[2].xaxis.set_major_formatter(major_formatter)
6161

62-
# FormatStr formatter
63-
setup(axs[3], title="FormatStrFormatter('#%d')")
64-
axs[3].xaxis.set_major_formatter(ticker.FormatStrFormatter("#%d"))
62+
# FuncFormatter can be automatically created directly with a function input
63+
# without needing to manually create the formatter
64+
setup(axs[3], title="lambda x, pos: str(x-5)")
65+
axs[3].xaxis.set_major_formatter(lambda x, pos: str(x-5))
66+
67+
# StrMethod formatter
68+
setup(axs[4], title="StrMethodFormatter('{x:.3f}')")
69+
axs[4].xaxis.set_major_formatter(ticker.StrMethodFormatter("{x:.3f}"))
70+
71+
# StrMethodFormatter can also be created directly with a string input.
72+
setup(axs[5], title="'{x} km'")
73+
axs[5].xaxis.set_major_formatter('{x} km')
6574

6675
# Scalar formatter
67-
setup(axs[4], title="ScalarFormatter()")
68-
axs[4].xaxis.set_major_formatter(ticker.ScalarFormatter(useMathText=True))
76+
setup(axs[6], title="ScalarFormatter()")
77+
axs[6].xaxis.set_major_formatter(ticker.ScalarFormatter(useMathText=True))
6978

70-
# StrMethod formatter
71-
setup(axs[5], title="StrMethodFormatter('{x:.3f}')")
72-
axs[5].xaxis.set_major_formatter(ticker.StrMethodFormatter("{x:.3f}"))
79+
# FormatStr formatter
80+
setup(axs[7], title="FormatStrFormatter('#%d')")
81+
axs[7].xaxis.set_major_formatter(ticker.FormatStrFormatter("#%d"))
7382

7483
# Percent formatter
75-
setup(axs[6], title="PercentFormatter(xmax=5)")
76-
axs[6].xaxis.set_major_formatter(ticker.PercentFormatter(xmax=5))
84+
setup(axs[8], title="PercentFormatter(xmax=5)")
85+
axs[8].xaxis.set_major_formatter(ticker.PercentFormatter(xmax=5))
7786

7887
plt.tight_layout()
7988
plt.show()

lib/matplotlib/axis.py

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,37 +1529,68 @@ def set_major_formatter(self, formatter):
15291529
"""
15301530
Set the formatter of the major ticker.
15311531
1532+
In addition to a `~matplotlib.ticker.Formatter` instance,
1533+
this also accepts a `str` or function.
1534+
For a `str` a `~matplotlib.ticker.StrMethodFormatter` is used.
1535+
For a function a `~matplotlib.ticker.FuncFormatter` is used.
1536+
15321537
Parameters
15331538
----------
1534-
formatter : `~matplotlib.ticker.Formatter`
1539+
formatter : `~matplotlib.ticker.Formatter`, str, or function
15351540
"""
1536-
cbook._check_isinstance(mticker.Formatter, formatter=formatter)
1537-
if (isinstance(formatter, mticker.FixedFormatter)
1538-
and len(formatter.seq) > 0
1539-
and not isinstance(self.major.locator, mticker.FixedLocator)):
1540-
cbook._warn_external('FixedFormatter should only be used together '
1541-
'with FixedLocator')
1542-
self.isDefault_majfmt = False
1543-
self.major.formatter = formatter
1544-
formatter.set_axis(self)
1545-
self.stale = True
1541+
self._set_formatter(formatter, self.major)
15461542

15471543
def set_minor_formatter(self, formatter):
15481544
"""
15491545
Set the formatter of the minor ticker.
15501546
1547+
In addition to a `~matplotlib.ticker.Formatter` instance,
1548+
this also accepts a `str` or function.
1549+
For a `str` a `~matplotlib.ticker.StrMethodFormatter` is used.
1550+
For a function a `~matplotlib.ticker.FuncFormatter` is used.
1551+
15511552
Parameters
15521553
----------
1553-
formatter : `~matplotlib.ticker.Formatter`
1554+
formatter : `~matplotlib.ticker.Formatter`, str, or function
1555+
"""
1556+
self._set_formatter(formatter, self.minor)
1557+
1558+
def _set_formatter(self, formatter, level):
15541559
"""
1555-
cbook._check_isinstance(mticker.Formatter, formatter=formatter)
1560+
Set the formatter of the major or minor ticker.
1561+
1562+
In addition to a `~matplotlib.ticker.Formatter` instance,
1563+
this also accepts a `str` or function.
1564+
For a `str` a `~matplotlib.ticker.StrMethodFormatter` is used.
1565+
For a function a `~matplotlib.ticker.FuncFormatter` is used.
1566+
1567+
Parameters
1568+
----------
1569+
formatter : `~matplotlib.ticker.Formatter`, str, or function
1570+
level : `self.major` or `self.minor`
1571+
"""
1572+
if isinstance(formatter, str):
1573+
formatter = mticker.StrMethodFormatter(formatter)
1574+
# Don't allow any other TickHelper to avoid easy-to-make errors,
1575+
# like using a Locator instead of a Formatter.
1576+
elif (callable(formatter) and
1577+
not isinstance(formatter, mticker.TickHelper)):
1578+
formatter = mticker.FuncFormatter(formatter)
1579+
else:
1580+
cbook._check_isinstance(mticker.Formatter, formatter=formatter)
1581+
15561582
if (isinstance(formatter, mticker.FixedFormatter)
15571583
and len(formatter.seq) > 0
1558-
and not isinstance(self.minor.locator, mticker.FixedLocator)):
1584+
and not isinstance(level.locator, mticker.FixedLocator)):
15591585
cbook._warn_external('FixedFormatter should only be used together '
15601586
'with FixedLocator')
1561-
self.isDefault_minfmt = False
1562-
self.minor.formatter = formatter
1587+
1588+
if level == self.major:
1589+
self.isDefault_majfmt = False
1590+
else:
1591+
self.isDefault_minfmt = False
1592+
1593+
level.formatter = formatter
15631594
formatter.set_axis(self)
15641595
self.stale = True
15651596

lib/matplotlib/tests/test_axes.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,28 @@ def test_formatter_ticker():
203203
ax.autoscale_view()
204204

205205

206+
def test_auto_formatter():
207+
def _formfunc(x, pos):
208+
return ''
209+
210+
formstr = '{x}_{pos}'
211+
212+
ax = plt.figure().subplots()
213+
ax.xaxis.set_major_formatter(_formfunc)
214+
ax.yaxis.set_minor_formatter(formstr)
215+
216+
targ_funcformatter = mticker.FuncFormatter(_formfunc)
217+
targ_strformatter = mticker.StrMethodFormatter(formstr)
218+
219+
assert isinstance(ax.xaxis.get_major_formatter(),
220+
mticker.FuncFormatter)
221+
assert isinstance(ax.yaxis.get_minor_formatter(),
222+
mticker.StrMethodFormatter)
223+
224+
assert ax.xaxis.get_major_formatter().func == targ_funcformatter.func
225+
assert ax.yaxis.get_minor_formatter().fmt == targ_strformatter.fmt
226+
227+
206228
@image_comparison(["twin_axis_locators_formatters"])
207229
def test_twin_axis_locators_formatters():
208230
vals = np.linspace(0, 1, num=5, endpoint=True)

lib/matplotlib/ticker.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,12 @@
159159
ax.yaxis.set_major_formatter(ymajor_formatter)
160160
ax.yaxis.set_minor_formatter(yminor_formatter)
161161
162+
For `.StrMethodFormatter`, `~.Axis.set_major_formatter` and
163+
`~.Axis.set_minor_formatter` accept a ``str``. In that case a
164+
`.StrMethodFormatter` will be automatically created and applied based on
165+
the given ``str``. Similalry, a `.FuncFormatter` will be automatically
166+
created and applied if a function is provided.
167+
162168
See :doc:`/gallery/ticks_and_spines/major_minor_demo` for an
163169
example of setting major and minor ticks. See the :mod:`matplotlib.dates`
164170
module for more information and examples of using date locators and formatters.

tutorials/text/text_intro.py

Lines changed: 10 additions & 7 deletions

0 commit comments

Comments
 (0)