Skip to content

Cleanup of docstrings of scales #14654

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 66 additions & 70 deletions lib/matplotlib/scale.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
"""
Scales define the distribution of data values on an axis, e.g. a log scaling.

They are attached to an `~.axis.Axis` and hold a `.Transform`, which is
responsible for the actual data transformation.

See also `.axes.Axes.set_xscale` and the scales examples in the documentation.
"""

import inspect
import textwrap

Expand All @@ -20,12 +29,14 @@ class ScaleBase:

Any subclasses will want to override:

- :attr:`name`
- :meth:`get_transform`
- :meth:`set_default_locators_and_formatters`
- :attr:`name`
- :meth:`get_transform`
- :meth:`set_default_locators_and_formatters`

And optionally:
- :meth:`limit_range_for_scale`

- :meth:`limit_range_for_scale`

"""

def __init__(self, axis, **kwargs):
Expand All @@ -51,9 +62,8 @@ def get_transform(self):

def set_default_locators_and_formatters(self, axis):
"""
Set the :class:`~matplotlib.ticker.Locator` and
:class:`~matplotlib.ticker.Formatter` objects on the given
axis to match this scale.
Set the locators and formatters of *axis* to instances suitable for
this scale.
"""
raise NotImplementedError()

Expand All @@ -63,7 +73,7 @@ def limit_range_for_scale(self, vmin, vmax, minpos):
domain supported by this scale.

*minpos* should be the minimum positive value in the data.
This is used by log scales to determine a minimum value.
This is used by log scales to determine a minimum value.
"""
return vmin, vmax

Expand All @@ -84,10 +94,7 @@ def __init__(self, axis, **kwargs):
super().__init__(axis, **kwargs)

def set_default_locators_and_formatters(self, axis):
"""
Set the locators and formatters to reasonable defaults for
linear scaling.
"""
# docstring inherited
axis.set_major_locator(AutoLocator())
axis.set_major_formatter(ScalarFormatter())
axis.set_minor_formatter(NullFormatter())
Expand All @@ -100,8 +107,8 @@ def set_default_locators_and_formatters(self, axis):

def get_transform(self):
"""
The transform for linear scaling is just the
:class:`~matplotlib.transforms.IdentityTransform`.
Return the transform for linear scaling, which is just the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just inherit all these docstrings? not sure per-scale documentation of get_transform is really useful.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, I'd leave it. There's a bit of value to have the link to the respective transform in the subclasses. Alternatively, one could document these relations for the builtin scales in a common place. and eliminate most of the get_transforms. Almost all are just returning self._transform. But that's for another time. You are welcome to make a PR (after this is merged 😉).

`~matplotlib.transforms.IdentityTransform`.
"""
return IdentityTransform()

Expand Down Expand Up @@ -157,8 +164,8 @@ def __init__(self, axis, functions):
"""
Parameters
----------
axis: the axis for the scale

axis : `~matplotlib.axis.Axis`
The axis for the scale.
functions : (callable, callable)
two-tuple of the forward and inverse functions for the scale.
The forward function must be monotonic.
Expand All @@ -172,16 +179,11 @@ def forward(values: array-like) -> array-like
self._transform = transform

def get_transform(self):
"""
The transform for arbitrary scaling
"""
"""Return the `.FuncTransform` associated with this scale."""
return self._transform

def set_default_locators_and_formatters(self, axis):
"""
Set the locators and formatters to the same defaults as the
linear scale.
"""
# docstring inherited
axis.set_major_locator(AutoLocator())
axis.set_major_formatter(ScalarFormatter())
axis.set_minor_formatter(NullFormatter())
Expand Down Expand Up @@ -293,7 +295,7 @@ def transform_non_affine(self, a):
# Ignore invalid values due to nans being passed to the transform.
with np.errstate(divide="ignore", invalid="ignore"):
log = {np.e: np.log, 2: np.log2, 10: np.log10}.get(self.base)
if log: # If possible, do everything in a single call to Numpy.
if log: # If possible, do everything in a single call to NumPy.
out = log(a)
else:
out = np.log(a)
Expand Down Expand Up @@ -354,20 +356,20 @@ class LogScale(ScaleBase):

def __init__(self, axis, **kwargs):
"""
*basex*/*basey*:
The base of the logarithm

*nonposx*/*nonposy*: {'mask', 'clip'}
non-positive values in *x* or *y* can be masked as
invalid, or clipped to a very small positive number

*subsx*/*subsy*:
Where to place the subticks between each major tick.
Should be a sequence of integers. For example, in a log10
scale: ``[2, 3, 4, 5, 6, 7, 8, 9]``

will place 8 logarithmically spaced minor ticks between
each major tick.
Parameters
----------
axis : `~matplotlib.axis.Axis`
The axis for the scale.
basex, basey : float, default: 10
The base of the logarithm.
nonposx, nonposy : {'clip', 'mask'}, default: 'clip'
Determines the behavior for non-positive values. They can either
be masked as invalid, or clipped to a very small positive number.
subsx, subsy : sequence of int, default: None
Where to place the subticks between each major tick.
For example, in a log10 scale: ``[2, 3, 4, 5, 6, 7, 8, 9]``
will place 8 logarithmically spaced minor ticks between
each major tick.
"""
if axis.axis_name == 'x':
base = kwargs.pop('basex', 10.0)
Expand Down Expand Up @@ -397,10 +399,7 @@ def base(self):
return self._transform.base

def set_default_locators_and_formatters(self, axis):
"""
Set the locators and formatters to specialized versions for
log scaling.
"""
# docstring inherited
axis.set_major_locator(LogLocator(self.base))
axis.set_major_formatter(LogFormatterSciNotation(self.base))
axis.set_minor_locator(LogLocator(self.base, self.subs))
Expand All @@ -409,16 +408,11 @@ def set_default_locators_and_formatters(self, axis):
labelOnlyBase=(self.subs is not None)))

def get_transform(self):
"""
Return a :class:`~matplotlib.transforms.Transform` instance
appropriate for the given logarithm base.
"""
"""Return the `.LogTransform` associated with this scale."""
return self._transform

def limit_range_for_scale(self, vmin, vmax, minpos):
"""
Limit the domain to positive values.
"""
"""Limit the domain to positive values."""
if not np.isfinite(minpos):
minpos = 1e-300 # Should rarely (if ever) have a visible effect.

Expand All @@ -438,8 +432,8 @@ def __init__(self, axis, functions, base=10):
"""
Parameters
----------
axis: the axis for the scale

axis : `matplotlib.axis.Axis`
The axis for the scale.
functions : (callable, callable)
two-tuple of the forward and inverse functions for the scale.
The forward function must be monotonic.
Expand All @@ -461,9 +455,7 @@ def base(self):
return self._transform._b.base # Base of the LogTransform.

def get_transform(self):
"""
The transform for arbitrary scaling
"""
"""Return the `.Transform` associated with this scale."""
return self._transform


Expand Down Expand Up @@ -592,20 +584,15 @@ def __init__(self, axis, **kwargs):
self.subs = subs

def set_default_locators_and_formatters(self, axis):
"""
Set the locators and formatters to specialized versions for
symmetrical log scaling.
"""
# docstring inherited
axis.set_major_locator(SymmetricalLogLocator(self.get_transform()))
axis.set_major_formatter(LogFormatterSciNotation(self.base))
axis.set_minor_locator(SymmetricalLogLocator(self.get_transform(),
self.subs))
axis.set_minor_formatter(NullFormatter())

def get_transform(self):
"""
Return a :class:`SymmetricalLogTransform` instance.
"""
"""Return the `.SymmetricalLogTransform` associated with this scale."""
return self._transform


Expand Down Expand Up @@ -669,19 +656,23 @@ class LogitScale(ScaleBase):

def __init__(self, axis, nonpos='mask'):
"""
*nonpos*: {'mask', 'clip'}
values beyond ]0, 1[ can be masked as invalid, or clipped to a number
very close to 0 or 1
Parameters
----------
axis : `matplotlib.axis.Axis`
Currently unused.
nonpos : {'mask', 'clip'}
Determines the behavior for values beyond the open interval ]0, 1[.
They can either be masked as invalid, or clipped to a number very
close to 0 or 1.
"""
self._transform = LogitTransform(nonpos)

def get_transform(self):
"""
Return a :class:`LogitTransform` instance.
"""
"""Return the `.LogitTransform` associated with this scale."""
return self._transform

def set_default_locators_and_formatters(self, axis):
# docstring inherited
# ..., 0.01, 0.1, 0.5, 0.9, 0.99, ...
axis.set_major_locator(LogitLocator())
axis.set_major_formatter(LogitFormatter())
Expand Down Expand Up @@ -709,6 +700,7 @@ def limit_range_for_scale(self, vmin, vmax, minpos):


def get_scale_names():
"""Return the names of the available scales."""
return sorted(_scale_mapping)


Expand All @@ -719,22 +711,26 @@ def scale_factory(scale, axis, **kwargs):
Parameters
----------
scale : {%(names)s}
axis : Axis
axis : `matplotlib.axis.Axis`
"""
scale = scale.lower()
cbook._check_in_list(_scale_mapping, scale=scale)
return _scale_mapping[scale](axis, **kwargs)


if scale_factory.__doc__:
scale_factory.__doc__ = scale_factory.__doc__ % {
"names": ", ".join(get_scale_names())}
"names": ", ".join(map(repr, get_scale_names()))}


def register_scale(scale_class):
"""
Register a new kind of scale.

*scale_class* must be a subclass of :class:`ScaleBase`.
Parameters
----------
scale_class : subclass of `ScaleBase`
The scale to register.
"""
_scale_mapping[scale_class.name] = scale_class

Expand Down
46 changes: 29 additions & 17 deletions lib/matplotlib/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -1188,18 +1188,18 @@ class Transform(TransformNode):
Subclasses of this class should override the following members (at
minimum):

- :attr:`input_dims`
- :attr:`output_dims`
- :meth:`transform`
- :attr:`is_separable`
- :attr:`has_inverse`
- :meth:`inverted` (if :attr:`has_inverse` is True)
- :attr:`input_dims`
- :attr:`output_dims`
- :meth:`transform`
- :attr:`is_separable`
- :attr:`has_inverse`
- :meth:`inverted` (if :attr:`has_inverse` is True)

If the transform needs to do something non-standard with
:class:`matplotlib.path.Path` objects, such as adding curves
where there were once line segments, it should override:

- :meth:`transform_path`
- :meth:`transform_path`
"""
input_dims = None
"""
Expand Down Expand Up @@ -1403,11 +1403,17 @@ def transform_affine(self, values):
affine transformations, this is equivalent to
``transform(values)``.

Accepts a numpy array of shape (N x :attr:`input_dims`) and
returns a numpy array of shape (N x :attr:`output_dims`).
Parameters
----------
values : array
The input values as NumPy array of length :attr:`input_dims` or
shape (N x :attr:`input_dims`).

Alternatively, accepts a numpy array of length :attr:`input_dims`
and returns a numpy array of length :attr:`output_dims`.
Returns
-------
values : array
The output values as NumPy array of length :attr:`input_dims` or
shape (N x :attr:`output_dims`), depending on the input.
"""
return self.get_affine().transform(values)

Expand All @@ -1422,11 +1428,17 @@ def transform_non_affine(self, values):
``transform(values)``. In affine transformations, this is
always a no-op.

Accepts a numpy array of shape (N x :attr:`input_dims`) and
returns a numpy array of shape (N x :attr:`output_dims`).
Parameters
----------
values : array
The input values as NumPy array of length :attr:`input_dims` or
shape (N x :attr:`input_dims`).

Alternatively, accepts a numpy array of length :attr:`input_dims`
and returns a numpy array of length :attr:`output_dims`.
Returns
-------
values : array
The output values as NumPy array of length :attr:`input_dims` or
shape (N x :attr:`output_dims`), depending on the input.
"""
return values

Expand Down Expand Up @@ -1558,11 +1570,11 @@ def inverted(self):
"""
Return the corresponding inverse transformation.

It holds ``x == self.inverted().transform(self.transform(x))``.

The return value of this method should be treated as
temporary. An update to *self* does not cause a corresponding
update to its inverted copy.

``x === self.inverted().transform(self.transform(x))``
"""
raise NotImplementedError()

Expand Down