Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
2d90c5a
Added ArbitaryNorm and RootNorm classes in colors, as well as example…
Oct 17, 2016
57aad3d
PEP8 formatting on examples, plotting using the object oriented appro…
Oct 18, 2016
f818aff
Added title/description to the examples
Oct 18, 2016
ffe1b9d
Class attributes are now hidden
Oct 18, 2016
1d22b90
Major update: complete refactorization of code. A much more powerful …
Oct 19, 2016
b5801ea
Corrected lambda function syntax that was not compatible with python …
Oct 19, 2016
e93d82d
Added FuncNorm: now everything inherits from this. Changed the name o…
Oct 20, 2016
3749b0a
Forgot to uncomment an import
Oct 20, 2016
de62491
Improved the auto-tick feature, and corrected some pep8 issues
Oct 20, 2016
d148756
Improved examples, created a new file for generating sample data.'
alvarosg Oct 22, 2016
5373a98
Corrected a double line, and removed a comment
alvarosg Oct 22, 2016
13edeab
Tests for FuncNorm added, and bug corrected in FuncNorm
alvarosg Oct 22, 2016
21d5cd0
Added compatibility for python 3 string check, added tests for Piecew…
alvarosg Oct 22, 2016
d359a4e
Added tests on all classes, including all public methods
alvarosg Oct 22, 2016
4622829
Change type of arrays in tests from int to float
alvarosg Oct 22, 2016
30ff404
Corrected wrong `super()` for RootNorm
alvarosg Oct 22, 2016
df835cb
Solve problem with implicit int to float casting that was not working…
alvarosg Oct 22, 2016
dfaa0f8
Added documentation in the numpydoc format
alvarosg Oct 23, 2016
a386395
Improve style in the examples. Corrected intending problem in the doc…
alvarosg Oct 23, 2016
b9dafb0
Added example in `FuncNorm` docstring
alvarosg Oct 23, 2016
d10be73
Finished with the examples in the docstrings
alvarosg Oct 24, 2016
c85a14c
Implemented clipping behavoir. Refactored _func_parser
alvarosg Oct 26, 2016
7597ddd
It now allows some string functions with parameters. Added a test for…
alvarosg Oct 28, 2016
7fce503
Forgot to add a file...
alvarosg Oct 28, 2016
bcd7dd0
Forgot to add another file...
alvarosg Oct 28, 2016
a71e1e9
Improved tests, documentation, and exceptions
alvarosg Oct 31, 2016
33f57d1
Removed test_colors.py from __init__.py after including parametrize
alvarosg Oct 31, 2016
9687173
Moved the string function parser to its own class in cbook. Added tes…
alvarosg Nov 1, 2016
46395aa
Improved documentation
Nov 2, 2016
63dab61
Added new example
Nov 2, 2016
8abf2c2
Added example for PiecewiseNorm, and MirrorPiecewiseNorm. String in t…
alvarosg Nov 3, 2016
b4ecdb2
Removed sampledata.py no longer necessary, and changed examples in do…
alvarosg Nov 3, 2016
42007ee
Added examples for MirrorRootNorm and RootNorm
alvarosg Nov 3, 2016
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
Prev Previous commit
Next Next commit
Improved documentation
  • Loading branch information
alvarosg committed Nov 2, 2016
commit 46395aabbaff456e39b601067d21658c64ac3ac0
7 changes: 4 additions & 3 deletions lib/matplotlib/cbook.py
Original file line number Diff line number Diff line change
Expand Up @@ -2752,11 +2752,12 @@ def _get_element(self, ind):
param = float(parstring)
except:
raise ValueError("'a' in parametric function strings must be "
"replaced by a number different than 0, "
"e.g. 'log10(x+{0.1})'.")
"replaced by a number that is not "
"zero, e.g. 'log10(x+{0.1})'.")
if param == 0:
raise ValueError("'a' in parametric function strings must be "
"replaced by a number different than 0.")
"replaced by a number that is not "
"zero.")
str_func = re.sub(regex, '{a}', str_func)

try:
Expand Down
95 changes: 57 additions & 38 deletions lib/matplotlib/colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -1010,7 +1010,7 @@ def __init__(self, f, finv=None, **normalize_kw):
finv = func_parser.get_invfunc()

if finv is None:
raise ValueError("Inverse function finv not provided")
raise ValueError("Inverse function `finv` not provided")

self._f = f
self._finv = finv
Expand All @@ -1037,8 +1037,8 @@ def __call__(self, value, clip=None):
-------
result : masked array of floats
Normalized data to the `[0.0, 1.0]` interval. If clip == False,
the values original below vmin and above vmax will be assigned to
-0.1 and 1.1, respectively.
values smaller than vmin or greater than vmax will be clipped to
-0.1 and 1.1 respectively.

"""
if clip is None:
Expand Down Expand Up @@ -1177,8 +1177,8 @@ class PiecewiseNorm(FuncNorm):
"""
Normalization defined as a piecewise function

It allows the definition of any linear or non-linear
function for different ranges of the colorbar.
It allows the definition of different linear or non-linear
functions for different ranges of the colorbar.

"""

Expand All @@ -1190,11 +1190,11 @@ def __init__(self, flist,
"""
Specify a series of functions, as well as intervals, to map the data
space into `[0,1]`. Each individual function may not diverge in the
[0,1] interval, as they will be normalized as
[0,1] interval, as it will be normalized as
fnorm(x)=(f(x)-f(0))/(f(1)-f(0)) to guarantee that fnorm(0)=0 and
fnorm(1)=1. Then each function will be transformed to map a different
data range [d0, d1] into colormap ranges [cm0, cm1] as
ftrans=fnorm((x-d0)/(d1-d0))*(cm1-cm0)+cm0.
fnorm(1)=1. Then each function will be transformed to map each
different data range [d0, d1] into its respective colormap range
[cm0, cm1] as ftrans=fnorm((x-d0)/(d1-d0))*(cm1-cm0)+cm0.

Parameters
----------
Expand All @@ -1209,11 +1209,12 @@ def __init__(self, flist,
inverse for the functions that were specified as a string in
`flist`. It must satisfy `len(flist)==len(finvlist)`.
refpoints_cm, refpoints_data : list or array of scalars
Reference points for the colorbar ranges which will go as
Depending on the reference points,
the colorbar ranges will be:
`[0., refpoints_cm[0]]`,... ,
`[refpoints_cm[i], refpoints_cm[i+1]]`,
`[refpoints_cm[-1], 0.]`,
and for the data ranges which will go as
and the data ranges will be:
`[self.vmin, refpoints_data[0]]`,... ,
`[refpoints_data[i], refpoints_data[i+1]]`,
`[refpoints_cm[-1], self.vmax]`
Expand Down Expand Up @@ -1435,11 +1436,29 @@ def ticks(self, nticks=None):

class MirrorPiecewiseNorm(PiecewiseNorm):
"""
Normalization allowing a dual `PiecewiseNorm` symmetrically around a point.
Normalization allowing a dual :class:`~matplotlib.colors.PiecewiseNorm`
symmetrically around a point.

Data above `center_data` will be normalized with the `fpos` function and
mapped into the inverval [`center_cm`,1] of the colorbar.

Data below `center_data` will be process in a similar way after a mirror
transformation:

* The interval [`vmin`, `center_data`] is mirrored around center_data,
so the upper side of the interval becomes the lower, and viceversa.
* The function `fneg` will be applied to the inverted interval to give an
interval in the colorbar.
* The obtained interval is mirrored again and mapped into the
[0, center_cm] interval of the colorbar.

In practice this is effectively the same as applying a transformed
function: `lambda x:(-fneg(-x + 1) + 1))`

If `fneg` is set to be equal to `fpos`, `center_cm` is set to 0.5 and
`center_data` is set to be the exact middle point between `vmin` and
`vmax`, then the normalization will be perfectly symmetric.

Data above `center_data` will be normalized independently that data below
it. If only one function is given, the normalization will be symmetric
around that point.
"""

def __init__(self,
Expand All @@ -1448,9 +1467,6 @@ def __init__(self,
center_data=0.0, center_cm=.5,
**normalize_kw):
"""
Specify two functions to normalize the data above and below a
provided reference point.

Parameters
----------
fpos, fposinv : callable or string
Expand All @@ -1465,11 +1481,11 @@ def __init__(self,
i.e. the actual normalization passed to `PiecewiseNorm` will be
(-fneg(-x + 1) + 1)). Default `fneg`=`fpos`.
center_data : float, optional
Value in the data that will separate the use of `fneg` and `fpos`.
Value at which the normalization will be mirrored.
Must be in the (vmin, vmax) range. Default 0.0.
center_cm : float, optional
Normalized value that will correspond to `center_data`.
Must be in the (0.0, 1.0) range.
Normalized value that will correspond do `center_data` in the
colorbar. Must be in the (0.0, 1.0) range.
Default 0.5.
normalize_kw : dict, optional
Dict with keywords (`vmin`,`vmax`,`clip`) passed
Expand Down Expand Up @@ -1550,21 +1566,25 @@ def __init__(self,

class MirrorRootNorm(MirrorPiecewiseNorm):
"""
Root normalization for positive and negative data using
`MirrorPiecewiseNorm`.
Root normalization using :class:`~matplotlib.colors.MirrorPiecewiseNorm`.

:class:`~matplotlib.backend_bases.LocationEvent`

Data above `center_data` will be normalized with a root of the order
`orderpos` and data below it with a symmetric root of order `orderneg`.
If only `orderpos` function is given, the normalization will be completely
mirrored.
`orderpos` and mapped into the inverval [`center_cm`,1] of the colorbar.

Data below `center_data` will be normalized with a root of the order
`orderneg` and mapped into the inverval [0, `center_cm`] under a mirror
transformation (see :class:`~matplotlib.colors.MirrorPiecewiseNorm` for
more details).

`mcolors.MirrorRootNorm(orderpos=2)` is equivalent
`colors.MirrorRootNorm(orderpos=2)` is equivalent
to `colors.MirrorPiecewiseNorm(fpos='sqrt')`

`mcolors.MirrorRootNorm(orderpos=2, orderneg=3)` is equivalent
`colors.MirrorRootNorm(orderpos=2, orderneg=3)` is equivalent
to `colors.MirrorPiecewiseNorm(fpos='sqrt', fneg='crt')`

`mcolors.MirrorRootNorm(orderpos=N1, orderneg=N2)` is equivalent
`colors.MirrorRootNorm(orderpos=N1, orderneg=N2)` is equivalent
to `colors.MirrorPiecewiseNorm(fpos=root{N1}', fneg=root{N2}')`

"""
Expand All @@ -1583,12 +1603,11 @@ def __init__(self, orderpos=2, orderneg=None,
below `center_data` using `MirrorPiecewiseNorm`. Default
`orderpos`.
center_data : float, optional
Value in the data that will separate the ranges. Must be
in the (vmin, vmax) range.
Default 0.0.
Value at which the normalization will be mirrored.
Must be in the (vmin, vmax) range. Default 0.0.
center_cm : float, optional
Normalized value that will correspond do `center_data`. Must be
in the (0.0, 1.0) range.
Normalized value that will correspond do `center_data` in the
colorbar. Must be in the (0.0, 1.0) range.
Default 0.5.
normalize_kw : dict, optional
Dict with keywords (`vmin`,`vmax`,`clip`) passed
Expand Down Expand Up @@ -1625,17 +1644,17 @@ def __init__(self, orderpos=2, orderneg=None,

class RootNorm(FuncNorm):
"""
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Example? Still unclear what this does.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is essentially equivalent to this which has han example:
norm = colors.FuncNorm(f='sqrt', vmin=0.0, vmax=2) <--> mcolors.RootNorm(order=3, vmin=0.0, vmax=2)
norm = colors.FuncNorm(f='crt') <--> mcolors.RootNorm(order=3)
with the advantage that it is just an integer number, that can be easily increased..

Although I am considering supressing this class, as now that the string functions can take paramenters, the same can be achieved with:
colors.FuncNorm(f='root{2}', vmin=0.0, vmax=2)
colors.FuncNorm(f='root{3}', vmin=0.0)
But still, it is not as good as just inputing an integer number. The same may apply to MirrorRootNorm.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

At the least I'm in favor of documenting that in docstring, but I'd also lean towards taking it out if it's supported fairly cleanly in the other functions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I have now included those equivalent examples in the docstrings. I think there are two reasons why they should be kept:

  • There are also existing classes for LogNorm, PowerNorm, SymLogNorm,...
  • Even though the same behavior can be obtained by using fun='root{N}', it involved formatting a number into a string, which is not as elegant as passing a number as an argument.

Simple root normalization using `FuncNorm`.
Simple root normalization using :class:`~matplotlib.colors.FuncNorm`.

It defines the root normalization as function of the order of the root.
Data will be normalized as (f(x)-f(`vmin`))/(f(`vmax`)-f(`vmin`)), where
f(x)=x**(1./`order`)

`mcolors.RootNorm(order=2)` is equivalent to `colors.FuncNorm(f='sqrt')`
`colors.RootNorm(order=2)` is equivalent to `colors.FuncNorm(f='sqrt')`

`mcolors.RootNorm(order=3)` is equivalent to `colors.FuncNorm(f='crt')`
`colors.RootNorm(order=3)` is equivalent to `colors.FuncNorm(f='crt')`

`mcolors.RootNorm(order=N)` is equivalent to `colors.FuncNorm(f='root{N}')`
`colors.RootNorm(order=N)` is equivalent to `colors.FuncNorm(f='root{N}')`

"""

Expand Down