diff --git a/galleries/examples/scales/custom_scale.py b/galleries/examples/scales/custom_scale.py index 3a7f34fd22f0..0023bbcfbcae 100644 --- a/galleries/examples/scales/custom_scale.py +++ b/galleries/examples/scales/custom_scale.py @@ -1,4 +1,6 @@ """ +.. _custom_scale: + ============ Custom scale ============ diff --git a/galleries/users_explain/artists/artist_intro.rst b/galleries/users_explain/artists/artist_intro.rst index 5f82c972ca00..213a945f44b8 100644 --- a/galleries/users_explain/artists/artist_intro.rst +++ b/galleries/users_explain/artists/artist_intro.rst @@ -5,9 +5,8 @@ Introduction to Artists Almost all objects you interact with on a Matplotlib plot are called "Artist" (and are subclasses of the `.Artist` class). :doc:`Figure <../figure/index>` -and :doc:`Axes <../axes/index>` are Artists, and generally contain :doc:`Axis -<../axis/index>` Artists and Artists that contain data or annotation -information. +and :doc:`Axes <../axes/index>` are Artists, and generally contain +`~.axis.Axis` Artists and Artists that contain data or annotation information. Creating Artists diff --git a/galleries/users_explain/artists/index.rst b/galleries/users_explain/artists/index.rst index 26164d51f3a3..d3f2918c9a91 100644 --- a/galleries/users_explain/artists/index.rst +++ b/galleries/users_explain/artists/index.rst @@ -4,9 +4,8 @@ Artists Almost all objects you interact with on a Matplotlib plot are called "Artist" (and are subclasses of the `.Artist` class). :doc:`Figure <../figure/index>` -and :doc:`Axes <../axes/index>` are Artists, and generally contain :doc:`Axis -<../axis/index>` Artists and Artists that contain data or annotation -information. +and :doc:`Axes <../axes/index>` are Artists, and generally contain +`~.axis.Axis` Artists and Artists that contain data or annotation information. .. toctree:: :maxdepth: 2 diff --git a/galleries/users_explain/axes/axes_intro.rst b/galleries/users_explain/axes/axes_intro.rst index 17f9059b80af..948dd51c8b1e 100644 --- a/galleries/users_explain/axes/axes_intro.rst +++ b/galleries/users_explain/axes/axes_intro.rst @@ -5,7 +5,7 @@ Introduction to Axes (or Subplots) Matplotlib `~.axes.Axes` are the gateway to creating your data visualizations. Once an Axes is placed on a figure there are many methods that can be used to -add data to the Axes. An Axes typically has a pair of :doc:`Axis <../axis/index>` +add data to the Axes. An Axes typically has a pair of `~.axis.Axis` Artists that define the data coordinate system, and include methods to add annotations like x- and y-labels, titles, and legends. @@ -130,7 +130,7 @@ Note that text can also be added to axes using `~.axes.Axes.text`, and `~.axes.A Axes limits, scales, and ticking -------------------------------- -Each Axes has two (or more) `~.axis.Axis` objects, that can be accessed via :attr:`~matplotlib.axes.Axes.xaxis` and :attr:`~matplotlib.axes.Axes.yaxis` properties. These have substantial number of methods on them, and for highly customizable Axis-es it is useful to read more about that API (:doc:`../axis/index`). However, the Axes class offers a number of helpers for the most common of these methods. Indeed, the `~.axes.Axes.set_xlabel`, discussed above, is a helper for the `~.Axis.set_label_text`. +Each Axes has two (or more) `~.axis.Axis` objects, that can be accessed via :attr:`~matplotlib.axes.Axes.xaxis` and :attr:`~matplotlib.axes.Axes.yaxis` properties. These have substantial number of methods on them, and for highly customizable Axis-es it is useful to read the API at `~.axis.Axis`. However, the Axes class offers a number of helpers for the most common of these methods. Indeed, the `~.axes.Axes.set_xlabel`, discussed above, is a helper for the `~.Axis.set_label_text`. Other important methods set the extent on the axes (`~.axes.Axes.set_xlim`, `~.axes.Axes.set_ylim`), or more fundamentally the scale of the axes. So for instance, we can make an Axis have a logarithmic scale, and zoom in on a sub-portion of the data: @@ -158,7 +158,7 @@ Many aspects of Axes ticks and tick labeling can be adjusted using `~.axes.Axes. labelcolor='green') -More fine-grained control on ticks, setting scales, and controlling the Axis can be highly customized beyond these Axes-level helpers. An introduction to these methods can be found in :ref:`users_axis`, or the API reference for `.axis.Axis`. +More fine-grained control on ticks, setting scales, and controlling the Axis can be highly customized beyond these Axes-level helpers. Axes layout ----------- diff --git a/galleries/users_explain/axes/axes_scales.py b/galleries/users_explain/axes/axes_scales.py new file mode 100644 index 000000000000..567f3c5762ed --- /dev/null +++ b/galleries/users_explain/axes/axes_scales.py @@ -0,0 +1,223 @@ +""" +.. _user_axes_scales: + +=========== +Axis scales +=========== + +By default Matplotlib displays data on the axis using a linear scale. +Matplotlib also supports `logarithmic scales +`_, and other less common +scales as well. Usually this can be done directly by using the +`~.axes.Axes.set_xscale` or `~.axes.Axes.set_yscale` methods. + +""" +import matplotlib.pyplot as plt +import numpy as np + +import matplotlib.scale as mscale +from matplotlib.ticker import FixedLocator, NullFormatter + +fig, axs = plt.subplot_mosaic([['linear', 'linear-log'], + ['log-linear', 'log-log']], layout='constrained') + +x = np.arange(0, 3*np.pi, 0.1) +y = 2 * np.sin(x) + 3 + +ax = axs['linear'] +ax.plot(x, y) +ax.set_xlabel('linear') +ax.set_ylabel('linear') + +ax = axs['linear-log'] +ax.plot(x, y) +ax.set_yscale('log') +ax.set_xlabel('linear') +ax.set_ylabel('log') + +ax = axs['log-linear'] +ax.plot(x, y) +ax.set_xscale('log') +ax.set_xlabel('log') +ax.set_ylabel('linear') + +ax = axs['log-log'] +ax.plot(x, y) +ax.set_xscale('log') +ax.set_yscale('log') +ax.set_xlabel('log') +ax.set_ylabel('log') + +# %% +# loglog and semilogx/y +# ===================== +# +# The logarithmic axis is used so often that there are a set +# helper functions, that do the same thing: `~.axes.Axes.semilogy`, +# `~.axes.Axes.semilogx`, and `~.axes.Axes.loglog`. + +fig, axs = plt.subplot_mosaic([['linear', 'linear-log'], + ['log-linear', 'log-log']], layout='constrained') + +x = np.arange(0, 3*np.pi, 0.1) +y = 2 * np.sin(x) + 3 + +ax = axs['linear'] +ax.plot(x, y) +ax.set_xlabel('linear') +ax.set_ylabel('linear') +ax.set_title('plot(x, y)') + +ax = axs['linear-log'] +ax.semilogy(x, y) +ax.set_xlabel('linear') +ax.set_ylabel('log') +ax.set_title('semilogy(x, y)') + +ax = axs['log-linear'] +ax.semilogx(x, y) +ax.set_xlabel('log') +ax.set_ylabel('linear') +ax.set_title('semilogx(x, y)') + +ax = axs['log-log'] +ax.loglog(x, y) +ax.set_xlabel('log') +ax.set_ylabel('log') +ax.set_title('loglog(x, y)') + +# %% +# Other built-in scales +# ===================== +# +# There are other scales that can be used. The list of registered +# scales can be returned from `.scale.get_scale_names`: + +print(mscale.get_scale_names()) + +# %% +# + +todo = ['asinh', 'symlog', 'log', 'logit', ] +fig, axs = plt.subplot_mosaic([['asinh', 'symlog'], + ['log', 'logit']], layout='constrained') + +x = np.arange(0, 1000) + +for td in todo: + ax = axs[td] + if td in ['asinh', 'symlog']: + yy = x - np.mean(x) + elif td in ['logit']: + yy = (x-np.min(x)) + yy = yy / np.max(np.abs(yy)) + else: + yy = x + + ax.plot(yy, yy) + ax.set_yscale(td) + ax.set_title(td) + +# %% +# Optional arguments for scales +# ============================= +# +# Some of the default scales have optional arguments. These are +# documented in the API reference for the respective scales at +# `~.matplotlib.scale`. One can change the base of the logarithm +# being plotted (eg 2 below) or the linear threshold range +# for ``'symlog'``. + +fig, axs = plt.subplot_mosaic([['log', 'symlog']], layout='constrained', + figsize=(6.4, 3)) + +for td in axs: + ax = axs[td] + if td in ['log']: + ax.plot(x, x) + ax.set_yscale('log', base=2) + ax.set_title('log base=2') + else: + ax.plot(x - np.mean(x), x - np.mean(x)) + ax.set_yscale('symlog', linthresh=100) + ax.set_title('symlog linthresh=100') + + +# %% +# +# Arbitrary function scales +# ============================ +# +# Users can define a full scale class and pass that to `~.axes.Axes.set_xscale` +# and `~.axes.Axes.set_yscale` (see :ref:`custom_scale`). A short cut for this +# is to use the 'function' scale, and pass as extra arguments a ``forward`` and +# an ``inverse`` function. The following performs a `Mercator transform +# `_ to the y-axis. + +# Function Mercator transform +def forward(a): + a = np.deg2rad(a) + return np.rad2deg(np.log(np.abs(np.tan(a) + 1.0 / np.cos(a)))) + + +def inverse(a): + a = np.deg2rad(a) + return np.rad2deg(np.arctan(np.sinh(a))) + + +t = np.arange(0, 170.0, 0.1) +s = t / 2. + +fig, ax = plt.subplots(layout='constrained') +ax.plot(t, s, '-', lw=2) + +ax.set_yscale('function', functions=(forward, inverse)) +ax.set_title('function: Mercator') +ax.grid(True) +ax.set_xlim([0, 180]) +ax.yaxis.set_minor_formatter(NullFormatter()) +ax.yaxis.set_major_locator(FixedLocator(np.arange(0, 90, 10))) + + +# %% +# +# What is a "scale"? +# ================== +# +# A scale is an object that gets attached to an axis. The class documentation +# is at `~matplotlib.scale`. `~.axes.Axes.set_xscale` and `~.axes.Axes.set_yscale` +# set the scale on the respective Axis objects. You can determine the scale +# on an axis with `~.axis.Axis.get_scale`: + +fig, ax = plt.subplots(layout='constrained', + figsize=(3.2, 3)) +ax.semilogy(x, x) + +print(ax.xaxis.get_scale()) +print(ax.yaxis.get_scale()) + +# %% +# +# Setting a scale does three things. First it defines a transform on the axis +# that maps between data values to position along the axis. This transform can +# be accessed via ``get_transform``: + +print(ax.yaxis.get_transform()) + +# %% +# +# Transforms on the axis are a relatively low-level concept, but is one of the +# important roles played by ``set_scale``. +# +# Setting the scale also sets default tick locators (`~.ticker`) and tick +# formatters appropriate for the scale. An axis with a 'log' scale has a +# `~.ticker.LogLocator` to pick ticks at decade intervals, and a +# `~.ticker.LogFormatter` to use scientific notation on the decades. + +print('X axis') +print(ax.xaxis.get_major_locator()) +print(ax.xaxis.get_major_formatter()) + +print('Y axis') +print(ax.yaxis.get_major_locator()) +print(ax.yaxis.get_major_formatter()) diff --git a/galleries/users_explain/axes/axes_ticks.py b/galleries/users_explain/axes/axes_ticks.py new file mode 100644 index 000000000000..aaec87c6a239 --- /dev/null +++ b/galleries/users_explain/axes/axes_ticks.py @@ -0,0 +1,275 @@ +""" +.. _user_axes_ticks: + +========== +Axis Ticks +========== + +The x and y Axis on each Axes have default tick "locators" and "formatters" +that depend on the scale being used (see :ref:`user_axes_scales`). It is +possible to customize the ticks and tick labels with either high-level methods +like `~.axes.Axes.set_xticks` or set the locators and formatters directly on +the axis. + +Manual location and formats +=========================== + +The simplest method to customize the tick locations and formats is to use +`~.axes.Axes.set_xticks` and `~.axes.Axes.set_yticks`. These can be used on +either the major or the minor ticks. +""" +import numpy as np +import matplotlib.pyplot as plt + +import matplotlib.ticker as ticker + + +fig, axs = plt.subplots(2, 1, figsize=(5.4, 5.4), layout='constrained') +x = np.arange(100) +for nn, ax in enumerate(axs): + ax.plot(x, x) + if nn == 1: + ax.set_title('Manual ticks') + ax.set_yticks(np.arange(0, 100.1, 100/3)) + xticks = np.arange(0.50, 101, 20) + xlabels = [f'\\${x:1.2f}' for x in xticks] + ax.set_xticks(xticks, labels=xlabels) + else: + ax.set_title('Automatic ticks') + +# %% +# +# Note that the length of the ``labels`` argument must have the same length as +# the array used to specify the ticks. +# +# By default `~.axes.Axes.set_xticks` and `~.axes.Axes.set_yticks` act on the +# major ticks of an Axis, however it is possible to add minor ticks: + +fig, axs = plt.subplots(2, 1, figsize=(5.4, 5.4), layout='constrained') +x = np.arange(100) +for nn, ax in enumerate(axs): + ax.plot(x, x) + if nn == 1: + ax.set_title('Manual ticks') + ax.set_yticks(np.arange(0, 100.1, 100/3)) + ax.set_yticks(np.arange(0, 100.1, 100/30), minor=True) + else: + ax.set_title('Automatic ticks') + + +# %% +# +# Locators and Formatters +# ======================= +# +# Manually setting the ticks as above works well for specific final plots, but +# does not adapt as the user interacts with the axes. At a lower level, +# Matplotlib has ``Locators`` that are meant to automatically choose ticks +# depending on the current view limits of the axis, and ``Formatters`` that are +# meant to format the tick labels automatically. +# +# The full list of locators provided by Matplotlib are listed at +# :ref:`locators`, and the formatters at :ref:`formatters`. + + +# %% + +def setup(ax, title): + """Set up common parameters for the Axes in the example.""" + # only show the bottom spine + ax.yaxis.set_major_locator(ticker.NullLocator()) + ax.spines[['left', 'right', 'top']].set_visible(False) + + ax.xaxis.set_ticks_position('bottom') + ax.tick_params(which='major', width=1.00, length=5) + ax.tick_params(which='minor', width=0.75, length=2.5) + ax.set_xlim(0, 5) + ax.set_ylim(0, 1) + ax.text(0.0, 0.2, title, transform=ax.transAxes, + fontsize=14, fontname='Monospace', color='tab:blue') + + +fig, axs = plt.subplots(8, 1, layout='constrained') + +# Null Locator +setup(axs[0], title="NullLocator()") +axs[0].xaxis.set_major_locator(ticker.NullLocator()) +axs[0].xaxis.set_minor_locator(ticker.NullLocator()) + +# Multiple Locator +setup(axs[1], title="MultipleLocator(0.5)") +axs[1].xaxis.set_major_locator(ticker.MultipleLocator(0.5)) +axs[1].xaxis.set_minor_locator(ticker.MultipleLocator(0.1)) + +# Fixed Locator +setup(axs[2], title="FixedLocator([0, 1, 5])") +axs[2].xaxis.set_major_locator(ticker.FixedLocator([0, 1, 5])) +axs[2].xaxis.set_minor_locator(ticker.FixedLocator(np.linspace(0.2, 0.8, 4))) + +# Linear Locator +setup(axs[3], title="LinearLocator(numticks=3)") +axs[3].xaxis.set_major_locator(ticker.LinearLocator(3)) +axs[3].xaxis.set_minor_locator(ticker.LinearLocator(31)) + +# Index Locator +setup(axs[4], title="IndexLocator(base=0.5, offset=0.25)") +axs[4].plot(range(0, 5), [0]*5, color='white') +axs[4].xaxis.set_major_locator(ticker.IndexLocator(base=0.5, offset=0.25)) + +# Auto Locator +setup(axs[5], title="AutoLocator()") +axs[5].xaxis.set_major_locator(ticker.AutoLocator()) +axs[5].xaxis.set_minor_locator(ticker.AutoMinorLocator()) + +# MaxN Locator +setup(axs[6], title="MaxNLocator(n=4)") +axs[6].xaxis.set_major_locator(ticker.MaxNLocator(4)) +axs[6].xaxis.set_minor_locator(ticker.MaxNLocator(40)) + +# Log Locator +setup(axs[7], title="LogLocator(base=10, numticks=15)") +axs[7].set_xlim(10**3, 10**10) +axs[7].set_xscale('log') +axs[7].xaxis.set_major_locator(ticker.LogLocator(base=10, numticks=15)) +plt.show() + +# %% +# +# Similarly, we can specify "Formatters" for the major and minor ticks on each +# axis. +# +# The tick format is configured via the function `~.Axis.set_major_formatter` +# or `~.Axis.set_minor_formatter`. It accepts: +# +# - a format string, which implicitly creates a `.StrMethodFormatter`. +# - a function, implicitly creates a `.FuncFormatter`. +# - an instance of a `.Formatter` subclass. The most common are +# +# - `.NullFormatter`: No labels on the ticks. +# - `.StrMethodFormatter`: Use string `str.format` method. +# - `.FormatStrFormatter`: Use %-style formatting. +# - `.FuncFormatter`: Define labels through a function. +# - `.FixedFormatter`: Set the label strings explicitly. +# - `.ScalarFormatter`: Default formatter for scalars: auto-pick the format string. +# - `.PercentFormatter`: Format labels as a percentage. +# +# See :ref:`formatters` for the complete list. + + +def setup(ax, title): + """Set up common parameters for the Axes in the example.""" + # only show the bottom spine + ax.yaxis.set_major_locator(ticker.NullLocator()) + ax.spines[['left', 'right', 'top']].set_visible(False) + + # define tick positions + ax.xaxis.set_major_locator(ticker.MultipleLocator(1.00)) + ax.xaxis.set_minor_locator(ticker.MultipleLocator(0.25)) + + ax.xaxis.set_ticks_position('bottom') + ax.tick_params(which='major', width=1.00, length=5) + ax.tick_params(which='minor', width=0.75, length=2.5, labelsize=10) + ax.set_xlim(0, 5) + ax.set_ylim(0, 1) + ax.text(0.0, 0.2, title, transform=ax.transAxes, + fontsize=14, fontname='Monospace', color='tab:blue') + + +fig = plt.figure(figsize=(8, 8), layout='constrained') +fig0, fig1, fig2 = fig.subfigures(3, height_ratios=[1.5, 1.5, 7.5]) + +fig0.suptitle('String Formatting', fontsize=16, x=0, ha='left') +ax0 = fig0.subplots() + +setup(ax0, title="'{x} km'") +ax0.xaxis.set_major_formatter('{x} km') + +fig1.suptitle('Function Formatting', fontsize=16, x=0, ha='left') +ax1 = fig1.subplots() + +setup(ax1, title="def(x, pos): return str(x-5)") +ax1.xaxis.set_major_formatter(lambda x, pos: str(x-5)) + +fig2.suptitle('Formatter Object Formatting', fontsize=16, x=0, ha='left') +axs2 = fig2.subplots(7, 1) + +setup(axs2[0], title="NullFormatter()") +axs2[0].xaxis.set_major_formatter(ticker.NullFormatter()) + +setup(axs2[1], title="StrMethodFormatter('{x:.3f}')") +axs2[1].xaxis.set_major_formatter(ticker.StrMethodFormatter("{x:.3f}")) + +setup(axs2[2], title="FormatStrFormatter('#%d')") +axs2[2].xaxis.set_major_formatter(ticker.FormatStrFormatter("#%d")) + + +def fmt_two_digits(x, pos): + return f'[{x:.2f}]' + + +setup(axs2[3], title='FuncFormatter("[{:.2f}]".format)') +axs2[3].xaxis.set_major_formatter(ticker.FuncFormatter(fmt_two_digits)) + +setup(axs2[4], title="FixedFormatter(['A', 'B', 'C', 'D', 'E', 'F'])") +# FixedFormatter should only be used together with FixedLocator. +# Otherwise, one cannot be sure where the labels will end up. +positions = [0, 1, 2, 3, 4, 5] +labels = ['A', 'B', 'C', 'D', 'E', 'F'] +axs2[4].xaxis.set_major_locator(ticker.FixedLocator(positions)) +axs2[4].xaxis.set_major_formatter(ticker.FixedFormatter(labels)) + +setup(axs2[5], title="ScalarFormatter()") +axs2[5].xaxis.set_major_formatter(ticker.ScalarFormatter(useMathText=True)) + +setup(axs2[6], title="PercentFormatter(xmax=5)") +axs2[6].xaxis.set_major_formatter(ticker.PercentFormatter(xmax=5)) + + +# %% +# +# Styling ticks (tick parameters) +# =============================== +# +# The appearance of ticks can be controlled at a low level by finding the +# individual `~.axis.Tick` on the axis. However, usually it is simplest to +# use `~.axes.Axes.tick_params` to change all the objects at once. +# +# The ``tick_params`` method can change the properties of ticks: +# +# - length +# - direction (in or out of the frame) +# - colors +# - width and length +# - and whether the ticks are drawn at the bottom, top, left, or right of the +# Axes. +# +# It also can control the tick labels: +# +# - labelsize (fontsize) +# - labelcolor (color of the label) +# - labelrotation +# - labelbottom, labeltop, labelleft, labelright +# +# In addition there is a *pad* keyword argument that specifies how far the tick +# label is from the tick. +# +# Finally, the grid linestyles can be set: +# +# - grid_color +# - grid_alpha +# - grid_linewidth +# - grid_linestyle +# +# All these properties can be restricted to one axis, and can be applied to +# just the major or minor ticks + +fig, axs = plt.subplots(1, 2, figsize=(6.4, 3.2), layout='constrained') + +for nn, ax in enumerate(axs): + ax.plot(np.arange(100)) + if nn == 1: + ax.grid('on') + ax.tick_params(right=True, left=False, axis='y', color='r', length=16, + grid_color='none') + ax.tick_params(axis='x', color='m', length=4, direction='in', width=4, + labelcolor='g', grid_color='b') diff --git a/galleries/users_explain/axes/index.rst b/galleries/users_explain/axes/index.rst index a4df627c0671..3d0a67ca14e7 100644 --- a/galleries/users_explain/axes/index.rst +++ b/galleries/users_explain/axes/index.rst @@ -4,7 +4,7 @@ Axes and subplots Matplotlib `~.axes.Axes` are the gateway to creating your data visualizations. Once an Axes is placed on a figure there are many methods that can be used to -add data to the Axes. An Axes typically has a pair of :doc:`Axis <../axis/index>` +add data to the Axes. An Axes typically has a pair of `~.axis.Axis` Artists that define the data coordinate system, and include methods to add annotations like x- and y-labels, titles, and legends. @@ -36,7 +36,19 @@ annotations like x- and y-labels, titles, and legends. arranging_axes colorbar_placement Autoscaling axes + +.. toctree:: + :maxdepth: 2 + :includehidden: + + axes_scales + axes_ticks Legends Subplot mosaic + +.. toctree:: + :maxdepth: 1 + :includehidden: + Constrained layout guide Tight layout guide (mildly discouraged) diff --git a/galleries/users_explain/axis/index.rst b/galleries/users_explain/axis/index.rst deleted file mode 100644 index e6b8b81c8018..000000000000 --- a/galleries/users_explain/axis/index.rst +++ /dev/null @@ -1,6 +0,0 @@ -.. _users_axis: - -Controlling and labelling Axis objects --------------------------------------- - -Some good material in artist tutorial that should be cribbed from or used here. diff --git a/galleries/users_explain/index.rst b/galleries/users_explain/index.rst index 16ac05f06671..8ed30a9aad8d 100644 --- a/galleries/users_explain/index.rst +++ b/galleries/users_explain/index.rst @@ -53,15 +53,6 @@ Using Matplotlib customizing - .. grid-item-card:: - :padding: 2 - - .. toctree:: - :maxdepth: 2 - :includehidden: - - axis/index - .. grid-item-card:: :padding: 2 diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 3e0b5c926208..ca6923d92a38 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -774,6 +774,7 @@ def set_label_coords(self, x, y, transform=None): self.stale = True def get_transform(self): + """Return the transform used in the Axis' scale""" return self._scale.get_transform() def get_scale(self): diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 3c49f3a07700..b4793929de9b 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -9,6 +9,9 @@ Although the locators know nothing about major or minor ticks, they are used by the Axis class to support major and minor tick locating and formatting. +.. _tick_locating: +.. _locators: + Tick locating ------------- pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy