mirror of
https://github.com/Estom/notes.git
synced 2026-02-07 04:23:55 +08:00
617 lines
16 KiB
Markdown
617 lines
16 KiB
Markdown
---
|
|
sidebarDepth: 3
|
|
sidebar: auto
|
|
---
|
|
|
|
# Overview of axisartist toolkit
|
|
|
|
The axisartist toolkit tutorial.
|
|
|
|
::: danger Warning
|
|
|
|
*axisartist* uses a custom Axes class
|
|
(derived from the mpl's original Axes class).
|
|
As a side effect, some commands (mostly tick-related) do not work.
|
|
|
|
:::
|
|
|
|
The *axisartist* contains a custom Axes class that is meant to support
|
|
curvilinear grids (e.g., the world coordinate system in astronomy).
|
|
Unlike mpl's original Axes class which uses Axes.xaxis and Axes.yaxis
|
|
to draw ticks, ticklines, etc., axisartist uses a special
|
|
artist (AxisArtist) that can handle ticks, ticklines, etc. for
|
|
curved coordinate systems.
|
|
|
|
Demo Floating Axis
|
|
|
|
Since it uses special artists, some Matplotlib commands that work on
|
|
Axes.xaxis and Axes.yaxis may not work.
|
|
|
|
## axisartist
|
|
|
|
The *axisartist* module provides a custom (and very experimental) Axes
|
|
class, where each axis (left, right, top, and bottom) have a separate
|
|
associated artist which is responsible for drawing the axis-line, ticks,
|
|
ticklabels, and labels. You can also create your own axis, which can pass
|
|
through a fixed position in the axes coordinate, or a fixed position
|
|
in the data coordinate (i.e., the axis floats around when viewlimit
|
|
changes).
|
|
|
|
The axes class, by default, has its xaxis and yaxis invisible, and
|
|
has 4 additional artists which are responsible for drawing the 4 axis spines in
|
|
"left", "right", "bottom", and "top". They are accessed as
|
|
ax.axis["left"], ax.axis["right"], and so on, i.e., ax.axis is a
|
|
dictionary that contains artists (note that ax.axis is still a
|
|
callable method and it behaves as an original Axes.axis method in
|
|
Matplotlib).
|
|
|
|
To create an axes,
|
|
|
|
``` python
|
|
import mpl_toolkits.axisartist as AA
|
|
fig = plt.figure()
|
|
ax = AA.Axes(fig, [0.1, 0.1, 0.8, 0.8])
|
|
fig.add_axes(ax)
|
|
```
|
|
|
|
or to create a subplot
|
|
|
|
``` python
|
|
ax = AA.Subplot(fig, 111)
|
|
fig.add_subplot(ax)
|
|
```
|
|
|
|
For example, you can hide the right and top spines using:
|
|
|
|
``` python
|
|
ax.axis["right"].set_visible(False)
|
|
ax.axis["top"].set_visible(False)
|
|
```
|
|
|
|
Simple Axisline3
|
|
|
|
It is also possible to add a horizontal axis. For example, you may have an
|
|
horizontal axis at y=0 (in data coordinate).
|
|
|
|
``` python
|
|
ax.axis["y=0"] = ax.new_floating_axis(nth_coord=0, value=0)
|
|
```
|
|
|
|
Simple Axisartist1
|
|
|
|
Or a fixed axis with some offset
|
|
|
|
``` python
|
|
# make new (right-side) yaxis, but with some offset
|
|
ax.axis["right2"] = ax.new_fixed_axis(loc="right",
|
|
offset=(20, 0))
|
|
```
|
|
|
|
### axisartist with ParasiteAxes
|
|
|
|
Most commands in the axes_grid1 toolkit can take an axes_class keyword
|
|
argument, and the commands create an axes of the given class. For example,
|
|
to create a host subplot with axisartist.Axes,
|
|
|
|
``` python
|
|
import mpl_toolkits.axisartist as AA
|
|
from mpl_toolkits.axes_grid1 import host_subplot
|
|
|
|
host = host_subplot(111, axes_class=AA.Axes)
|
|
```
|
|
|
|
Here is an example that uses ParasiteAxes.
|
|
|
|
Demo Parasite Axes2
|
|
|
|
### Curvilinear Grid
|
|
|
|
The motivation behind the AxisArtist module is to support a curvilinear grid
|
|
and ticks.
|
|
|
|
Demo Curvelinear Grid
|
|
|
|
### Floating Axes
|
|
|
|
AxisArtist also supports a Floating Axes whose outer axes are defined as
|
|
floating axis.
|
|
|
|
Demo Floating Axes
|
|
|
|
## axisartist namespace
|
|
|
|
The *axisartist* namespace includes a derived Axes implementation. The
|
|
biggest difference is that the artists responsible to draw axis line,
|
|
ticks, ticklabel and axis labels are separated out from the mpl's Axis
|
|
class, which are much more than artists in the original mpl. This
|
|
change was strongly motivated to support curvilinear grid. Here are a
|
|
few things that mpl_toolkits.axisartist.Axes is different from original
|
|
Axes from mpl.
|
|
|
|
- Axis elements (axis line(spine), ticks, ticklabel and axis labels)
|
|
are drawn by a AxisArtist instance. Unlike Axis, left, right, top
|
|
and bottom axis are drawn by separate artists. And each of them may
|
|
have different tick location and different tick labels.
|
|
- gridlines are drawn by a Gridlines instance. The change was
|
|
motivated that in curvilinear coordinate, a gridline may not cross
|
|
axis-lines (i.e., no associated ticks). In the original Axes class,
|
|
gridlines are tied to ticks.
|
|
- ticklines can be rotated if necessary (i.e, along the gridlines)
|
|
|
|
In summary, all these changes was to support
|
|
|
|
- a curvilinear grid.
|
|
- a floating axis
|
|
|
|
Demo Floating Axis
|
|
|
|
*mpl_toolkits.axisartist.Axes* class defines a *axis* attribute, which
|
|
is a dictionary of AxisArtist instances. By default, the dictionary
|
|
has 4 AxisArtist instances, responsible for drawing of left, right,
|
|
bottom and top axis.
|
|
|
|
xaxis and yaxis attributes are still available, however they are set
|
|
to not visible. As separate artists are used for rendering axis, some
|
|
axis-related method in mpl may have no effect.
|
|
In addition to AxisArtist instances, the mpl_toolkits.axisartist.Axes will
|
|
have *gridlines* attribute (Gridlines), which obviously draws grid
|
|
lines.
|
|
|
|
In both AxisArtist and Gridlines, the calculation of tick and grid
|
|
location is delegated to an instance of GridHelper class.
|
|
mpl_toolkits.axisartist.Axes class uses GridHelperRectlinear as a grid
|
|
helper. The GridHelperRectlinear class is a wrapper around the *xaxis*
|
|
and *yaxis* of mpl's original Axes, and it was meant to work as the
|
|
way how mpl's original axes works. For example, tick location changes
|
|
using set_ticks method and etc. should work as expected. But change in
|
|
artist properties (e.g., color) will not work in general, although
|
|
some effort has been made so that some often-change attributes (color,
|
|
etc.) are respected.
|
|
|
|
## AxisArtist
|
|
|
|
AxisArtist can be considered as a container artist with following
|
|
attributes which will draw ticks, labels, etc.
|
|
|
|
- line
|
|
- major_ticks, major_ticklabels
|
|
- minor_ticks, minor_ticklabels
|
|
- offsetText
|
|
- label
|
|
|
|
### line
|
|
|
|
Derived from Line2d class. Responsible for drawing a spinal(?) line.
|
|
|
|
### major_ticks, minor_ticks
|
|
|
|
Derived from Line2d class. Note that ticks are markers.
|
|
|
|
### major_ticklabels, minor_ticklabels
|
|
|
|
Derived from Text. Note that it is not a list of Text artist, but a
|
|
single artist (similar to a collection).
|
|
|
|
### axislabel
|
|
|
|
Derived from Text.
|
|
|
|
## Default AxisArtists
|
|
|
|
By default, following for axis artists are defined.:
|
|
|
|
``` python
|
|
ax.axis["left"], ax.axis["bottom"], ax.axis["right"], ax.axis["top"]
|
|
```
|
|
|
|
The ticklabels and axislabel of the top and the right axis are set to
|
|
not visible.
|
|
|
|
For example, if you want to change the color attributes of
|
|
major_ticklabels of the bottom x-axis
|
|
|
|
``` python
|
|
ax.axis["bottom"].major_ticklabels.set_color("b")
|
|
```
|
|
|
|
Similarly, to make ticklabels invisible
|
|
|
|
``` python
|
|
ax.axis["bottom"].major_ticklabels.set_visible(False)
|
|
```
|
|
|
|
AxisArtist provides a helper method to control the visibility of ticks,
|
|
ticklabels, and label. To make ticklabel invisible,
|
|
|
|
``` python
|
|
ax.axis["bottom"].toggle(ticklabels=False)
|
|
```
|
|
|
|
To make all of ticks, ticklabels, and (axis) label invisible
|
|
|
|
``` python
|
|
ax.axis["bottom"].toggle(all=False)
|
|
```
|
|
|
|
To turn all off but ticks on
|
|
|
|
``` python
|
|
ax.axis["bottom"].toggle(all=False, ticks=True)
|
|
```
|
|
|
|
To turn all on but (axis) label off
|
|
|
|
``` python
|
|
ax.axis["bottom"].toggle(all=True, label=False))
|
|
```
|
|
|
|
ax.axis's __getitem__ method can take multiple axis names. For
|
|
example, to turn ticklabels of "top" and "right" axis on,
|
|
|
|
``` python
|
|
ax.axis["top","right"].toggle(ticklabels=True))
|
|
```
|
|
|
|
Note that 'ax.axis["top","right"]' returns a simple proxy object that translate above code to something like below.
|
|
|
|
``` python
|
|
for n in ["top","right"]:
|
|
ax.axis[n].toggle(ticklabels=True))
|
|
```
|
|
|
|
So, any return values in the for loop are ignored. And you should not
|
|
use it anything more than a simple method.
|
|
|
|
Like the list indexing ":" means all items, i.e.,
|
|
|
|
``` python
|
|
ax.axis[:].major_ticks.set_color("r")
|
|
```
|
|
|
|
changes tick color in all axis.
|
|
|
|
## HowTo
|
|
|
|
1. Changing tick locations and label.
|
|
|
|
Same as the original mpl's axes.:
|
|
|
|
``` python
|
|
ax.set_xticks([1,2,3])
|
|
```
|
|
|
|
1. Changing axis properties like color, etc.
|
|
|
|
Change the properties of appropriate artists. For example, to change
|
|
the color of the ticklabels:
|
|
|
|
``` python
|
|
ax.axis["left"].major_ticklabels.set_color("r")
|
|
```
|
|
|
|
## Rotation and Alignment of TickLabels
|
|
|
|
This is also quite different from the original mpl and can be
|
|
confusing. When you want to rotate the ticklabels, first consider
|
|
using "set_axis_direction" method.
|
|
|
|
``` python
|
|
ax1.axis["left"].major_ticklabels.set_axis_direction("top")
|
|
ax1.axis["right"].label.set_axis_direction("left")
|
|
```
|
|
|
|
Simple Axis Direction01
|
|
|
|
The parameter for set_axis_direction is one of ["left", "right",
|
|
"bottom", "top"].
|
|
|
|
You must understand some underlying concept of directions.
|
|
|
|
On the other hand, there is a concept of "axis_direction". This is a
|
|
default setting of above properties for each, "bottom", "left", "top",
|
|
and "right" axis.
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
?
|
|
?
|
|
left
|
|
bottom
|
|
right
|
|
top
|
|
|
|
axislabel
|
|
direction
|
|
'-'
|
|
'+'
|
|
'+'
|
|
'-'
|
|
|
|
axislabel
|
|
rotation
|
|
180
|
|
0
|
|
0
|
|
180
|
|
|
|
axislabel
|
|
va
|
|
center
|
|
top
|
|
center
|
|
bottom
|
|
|
|
axislabel
|
|
ha
|
|
right
|
|
center
|
|
right
|
|
center
|
|
|
|
ticklabel
|
|
direction
|
|
'-'
|
|
'+'
|
|
'+'
|
|
'-'
|
|
|
|
ticklabels
|
|
rotation
|
|
90
|
|
0
|
|
-90
|
|
180
|
|
|
|
ticklabel
|
|
ha
|
|
right
|
|
center
|
|
right
|
|
center
|
|
|
|
ticklabel
|
|
va
|
|
center
|
|
baseline
|
|
center
|
|
baseline
|
|
|
|
|
|
|
|
|
|
And, 'set_axis_direction("top")' means to adjust the text rotation
|
|
etc, for settings suitable for "top" axis. The concept of axis
|
|
direction can be more clear with curved axis.
|
|
|
|
Demo Axis Direction
|
|
|
|
The axis_direction can be adjusted in the AxisArtist level, or in the
|
|
level of its child artists, i.e., ticks, ticklabels, and axis-label.
|
|
|
|
``` python
|
|
ax1.axis["left"].set_axis_direction("top")
|
|
```
|
|
|
|
changes axis_direction of all the associated artist with the "left"
|
|
axis, while
|
|
|
|
``` python
|
|
ax1.axis["left"].major_ticklabels.set_axis_direction("top")
|
|
```
|
|
|
|
changes the axis_direction of only the major_ticklabels. Note that
|
|
set_axis_direction in the AxisArtist level changes the
|
|
ticklabel_direction and label_direction, while changing the
|
|
axis_direction of ticks, ticklabels, and axis-label does not affect
|
|
them.
|
|
|
|
If you want to make ticks outward and ticklabels inside the axes,
|
|
use invert_ticklabel_direction method.
|
|
|
|
``` python
|
|
ax.axis[:].invert_ticklabel_direction()
|
|
```
|
|
|
|
A related method is "set_tick_out". It makes ticks outward (as a
|
|
matter of fact, it makes ticks toward the opposite direction of the
|
|
default direction).
|
|
|
|
``` python
|
|
ax.axis[:].major_ticks.set_tick_out(True)
|
|
```
|
|
|
|
Simple Axis Direction03
|
|
|
|
So, in summary,
|
|
|
|
- AxisArtist's methods
|
|
|
|
set_axis_direction : "left", "right", "bottom", or "top"
|
|
set_ticklabel_direction : "+" or "-"
|
|
set_axislabel_direction : "+" or "-"
|
|
invert_ticklabel_direction
|
|
- set_axis_direction : "left", "right", "bottom", or "top"
|
|
- set_ticklabel_direction : "+" or "-"
|
|
- set_axislabel_direction : "+" or "-"
|
|
- invert_ticklabel_direction
|
|
- Ticks' methods (major_ticks and minor_ticks)
|
|
|
|
set_tick_out : True or False
|
|
set_ticksize : size in points
|
|
- set_tick_out : True or False
|
|
- set_ticksize : size in points
|
|
- TickLabels' methods (major_ticklabels and minor_ticklabels)
|
|
|
|
set_axis_direction : "left", "right", "bottom", or "top"
|
|
set_rotation : angle with respect to the reference direction
|
|
set_ha and set_va : see below
|
|
- set_axis_direction : "left", "right", "bottom", or "top"
|
|
- set_rotation : angle with respect to the reference direction
|
|
- set_ha and set_va : see below
|
|
- AxisLabels' methods (label)
|
|
|
|
set_axis_direction : "left", "right", "bottom", or "top"
|
|
set_rotation : angle with respect to the reference direction
|
|
set_ha and set_va
|
|
- set_axis_direction : "left", "right", "bottom", or "top"
|
|
- set_rotation : angle with respect to the reference direction
|
|
- set_ha and set_va
|
|
|
|
### Adjusting ticklabels alignment
|
|
|
|
Alignment of TickLabels are treated specially. See below
|
|
|
|
Demo Ticklabel Alignment
|
|
|
|
### Adjusting pad
|
|
|
|
To change the pad between ticks and ticklabels
|
|
|
|
``` python
|
|
ax.axis["left"].major_ticklabels.set_pad(10)
|
|
```
|
|
|
|
Or ticklabels and axis-label
|
|
|
|
``` python
|
|
ax.axis["left"].label.set_pad(10)
|
|
```
|
|
|
|
Simple Axis Pad
|
|
|
|
## GridHelper
|
|
|
|
To actually define a curvilinear coordinate, you have to use your own
|
|
grid helper. A generalised version of grid helper class is supplied
|
|
and this class should suffice in most of cases. A user may provide
|
|
two functions which defines a transformation (and its inverse pair)
|
|
from the curved coordinate to (rectilinear) image coordinate. Note that
|
|
while ticks and grids are drawn for curved coordinate, the data
|
|
transform of the axes itself (ax.transData) is still rectilinear
|
|
(image) coordinate.
|
|
|
|
``` python
|
|
from mpl_toolkits.axisartist.grid_helper_curvelinear \
|
|
import GridHelperCurveLinear
|
|
from mpl_toolkits.axisartist import Subplot
|
|
|
|
# from curved coordinate to rectlinear coordinate.
|
|
def tr(x, y):
|
|
x, y = np.asarray(x), np.asarray(y)
|
|
return x, y-x
|
|
|
|
# from rectlinear coordinate to curved coordinate.
|
|
def inv_tr(x,y):
|
|
x, y = np.asarray(x), np.asarray(y)
|
|
return x, y+x
|
|
|
|
grid_helper = GridHelperCurveLinear((tr, inv_tr))
|
|
|
|
ax1 = Subplot(fig, 1, 1, 1, grid_helper=grid_helper)
|
|
|
|
fig.add_subplot(ax1)
|
|
```
|
|
|
|
You may use matplotlib's Transform instance instead (but a
|
|
inverse transformation must be defined). Often, coordinate range in a
|
|
curved coordinate system may have a limited range, or may have
|
|
cycles. In those cases, a more customized version of grid helper is
|
|
required.
|
|
|
|
``` python
|
|
import mpl_toolkits.axisartist.angle_helper as angle_helper
|
|
|
|
# PolarAxes.PolarTransform takes radian. However, we want our coordinate
|
|
# system in degree
|
|
tr = Affine2D().scale(np.pi/180., 1.) + PolarAxes.PolarTransform()
|
|
|
|
# extreme finder : find a range of coordinate.
|
|
# 20, 20 : number of sampling points along x, y direction
|
|
# The first coordinate (longitude, but theta in polar)
|
|
# has a cycle of 360 degree.
|
|
# The second coordinate (latitude, but radius in polar) has a minimum of 0
|
|
extreme_finder = angle_helper.ExtremeFinderCycle(20, 20,
|
|
lon_cycle = 360,
|
|
lat_cycle = None,
|
|
lon_minmax = None,
|
|
lat_minmax = (0, np.inf),
|
|
)
|
|
|
|
# Find a grid values appropriate for the coordinate (degree,
|
|
# minute, second). The argument is a approximate number of grids.
|
|
grid_locator1 = angle_helper.LocatorDMS(12)
|
|
|
|
# And also uses an appropriate formatter. Note that,the
|
|
# acceptable Locator and Formatter class is a bit different than
|
|
# that of mpl's, and you cannot directly use mpl's Locator and
|
|
# Formatter here (but may be possible in the future).
|
|
tick_formatter1 = angle_helper.FormatterDMS()
|
|
|
|
grid_helper = GridHelperCurveLinear(tr,
|
|
extreme_finder=extreme_finder,
|
|
grid_locator1=grid_locator1,
|
|
tick_formatter1=tick_formatter1
|
|
)
|
|
```
|
|
|
|
Again, the *transData* of the axes is still a rectilinear coordinate
|
|
(image coordinate). You may manually do conversion between two
|
|
coordinates, or you may use Parasite Axes for convenience.:
|
|
|
|
``` python
|
|
ax1 = SubplotHost(fig, 1, 2, 2, grid_helper=grid_helper)
|
|
|
|
# A parasite axes with given transform
|
|
ax2 = ParasiteAxesAuxTrans(ax1, tr, "equal")
|
|
# note that ax2.transData == tr + ax1.transData
|
|
# Anything you draw in ax2 will match the ticks and grids of ax1.
|
|
ax1.parasites.append(ax2)
|
|
```
|
|
|
|
Demo Curvelinear Grid
|
|
|
|
## FloatingAxis
|
|
|
|
A floating axis is an axis one of whose data coordinate is fixed, i.e,
|
|
its location is not fixed in Axes coordinate but changes as axes data
|
|
limits changes. A floating axis can be created using
|
|
*new_floating_axis* method. However, it is your responsibility that
|
|
the resulting AxisArtist is properly added to the axes. A recommended
|
|
way is to add it as an item of Axes's axis attribute.:
|
|
|
|
``` python
|
|
# floating axis whose first (index starts from 0) coordinate
|
|
# (theta) is fixed at 60
|
|
|
|
ax1.axis["lat"] = axis = ax1.new_floating_axis(0, 60)
|
|
axis.label.set_text(r"$\theta = 60^{\circ}$")
|
|
axis.label.set_visible(True)
|
|
```
|
|
|
|
See the first example of this page.
|
|
|
|
## Current Limitations and TODO's
|
|
|
|
The code need more refinement. Here is a incomplete list of issues and TODO's
|
|
|
|
- No easy way to support a user customized tick location (for
|
|
curvilinear grid). A new Locator class needs to be created.
|
|
- FloatingAxis may have coordinate limits, e.g., a floating axis of x
|
|
= 0, but y only spans from 0 to 1.
|
|
- The location of axislabel of FloatingAxis needs to be optionally
|
|
given as a coordinate value. ex, a floating axis of x=0 with label at y=1
|
|
|
|
## Download
|
|
|
|
- [Download Python source code: axisartist.py](https://matplotlib.org/_downloads/009aa8b612fe75c3b3046dbffcd0d1c7/axisartist.py)
|
|
- [Download Jupyter notebook: axisartist.ipynb](https://matplotlib.org/_downloads/47bc25cb4e9c18eccf1385f78c4ea405/axisartist.ipynb)
|
|
|