plotastro 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- plotastro/__init__.py +68 -0
- plotastro/_authors.py +302 -0
- plotastro/_colors.py +227 -0
- plotastro/_core.py +256 -0
- plotastro/_extras.py +187 -0
- plotastro/styles/aanda.mplstyle +101 -0
- plotastro/styles/apj.mplstyle +101 -0
- plotastro/styles/jcap.mplstyle +100 -0
- plotastro/styles/mnras.mplstyle +101 -0
- plotastro/styles/natastro.mplstyle +102 -0
- plotastro/styles/oja.mplstyle +102 -0
- plotastro/styles/prd.mplstyle +101 -0
- plotastro/styles/rasti.mplstyle +101 -0
- plotastro-1.0.0.dist-info/METADATA +432 -0
- plotastro-1.0.0.dist-info/RECORD +18 -0
- plotastro-1.0.0.dist-info/WHEEL +4 -0
- plotastro-1.0.0.dist-info/entry_points.txt +2 -0
- plotastro-1.0.0.dist-info/licenses/LICENSE +23 -0
plotastro/_core.py
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
"""Journal definitions, style activation and figure sizing."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import matplotlib as mpl
|
|
8
|
+
import matplotlib.pyplot as plt
|
|
9
|
+
|
|
10
|
+
STYLE_DIR = Path(__file__).resolve().parent / "styles"
|
|
11
|
+
|
|
12
|
+
#: Golden ratio (height/width) used for default figure heights.
|
|
13
|
+
GOLDEN = (5 ** 0.5 - 1) / 2 # 0.618...
|
|
14
|
+
|
|
15
|
+
_SERIF_TEX = r"\usepackage{newtxtext}\usepackage{newtxmath}"
|
|
16
|
+
_SANS_TEX = (r"\usepackage{helvet}\usepackage{sansmath}\sansmath"
|
|
17
|
+
r"\renewcommand{\familydefault}{\sfdefault}")
|
|
18
|
+
|
|
19
|
+
#: Text-block widths in LaTeX points (1 pt = 1/72.27 inch) per journal,
|
|
20
|
+
#: the style sheet each journal uses, and its LaTeX font preamble.
|
|
21
|
+
JOURNALS = {
|
|
22
|
+
"mnras": {"column": 240.0, "full": 504.0, "style": "mnras",
|
|
23
|
+
"tex": _SERIF_TEX,
|
|
24
|
+
"name": "Monthly Notices of the RAS"},
|
|
25
|
+
"rasti": {"column": 240.0, "full": 504.0, "style": "rasti",
|
|
26
|
+
"tex": _SERIF_TEX,
|
|
27
|
+
"name": "RAS Techniques and Instruments"},
|
|
28
|
+
"aanda": {"column": 250.38, "full": 512.15, "style": "aanda",
|
|
29
|
+
"tex": _SERIF_TEX,
|
|
30
|
+
"name": "Astronomy & Astrophysics"},
|
|
31
|
+
"apj": {"column": 242.26653, "full": 513.11743, "style": "apj",
|
|
32
|
+
"tex": _SERIF_TEX,
|
|
33
|
+
"name": "The Astrophysical Journal (AASTeX)"},
|
|
34
|
+
"oja": {"column": 245.26653, "full": 508.0, "style": "oja",
|
|
35
|
+
"tex": _SERIF_TEX,
|
|
36
|
+
"name": "The Open Journal of Astrophysics"},
|
|
37
|
+
"prd": {"column": 246.0, "full": 510.0, "style": "prd",
|
|
38
|
+
"tex": _SERIF_TEX,
|
|
39
|
+
"name": "Physical Review D (REVTeX 4.2)"},
|
|
40
|
+
"jcap": {"column": 455.24, "full": 455.24, "style": "jcap",
|
|
41
|
+
"tex": _SERIF_TEX,
|
|
42
|
+
"name": "J. of Cosmology and Astroparticle Physics"},
|
|
43
|
+
"natastro": {"column": 253.23, "full": 520.68, "style": "natastro",
|
|
44
|
+
"tex": _SANS_TEX,
|
|
45
|
+
"name": "Nature Astronomy"},
|
|
46
|
+
# Not journals, but handy width presets (they use the MNRAS look):
|
|
47
|
+
"thesis": {"column": 426.79135, "full": 426.79135, "style": "mnras",
|
|
48
|
+
"tex": _SERIF_TEX,
|
|
49
|
+
"name": "A4 thesis text width"},
|
|
50
|
+
"beamer": {"column": 307.28987, "full": 307.28987, "style": "mnras",
|
|
51
|
+
"tex": _SERIF_TEX,
|
|
52
|
+
"name": "Beamer slide text width"},
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
_ALIASES = {
|
|
56
|
+
"a&a": "aanda", "aa": "aanda", "astronomy&astrophysics": "aanda",
|
|
57
|
+
"apjl": "apj", "aj": "apj", "aas": "apj", "aastex": "apj",
|
|
58
|
+
"openjournal": "oja", "theoj": "oja", "openjournalofastrophysics": "oja",
|
|
59
|
+
"prl": "prd", "aps": "prd", "revtex": "prd",
|
|
60
|
+
"nature": "natastro", "natureastronomy": "natastro", "natastron": "natastro",
|
|
61
|
+
"mnras_full": "mnras", # legacy name from the old set_size() API
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
_state = {"journal": "mnras"}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _resolve(journal):
|
|
68
|
+
key = str(journal).lower().replace(" ", "").replace("-", "")
|
|
69
|
+
key = _ALIASES.get(key, key)
|
|
70
|
+
if key not in JOURNALS:
|
|
71
|
+
options = ", ".join(sorted(JOURNALS))
|
|
72
|
+
raise ValueError(f"Unknown journal {journal!r}. Choose one of: {options}")
|
|
73
|
+
return key
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def current_journal():
|
|
77
|
+
"""Name of the journal activated by the last :func:`set_style` call."""
|
|
78
|
+
return _state["journal"]
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# ----------------------------------------------------------------------
|
|
82
|
+
# Style activation
|
|
83
|
+
# ----------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
def set_style(journal="mnras", *, usetex=False, grid=None, **rc_overrides):
|
|
86
|
+
"""Activate the plotting style for a journal.
|
|
87
|
+
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
journal : str
|
|
91
|
+
One of ``"mnras"``, ``"rasti"``, ``"aanda"`` (aliases ``"a&a"``,
|
|
92
|
+
``"aa"``), ``"apj"`` (aliases ``"apjl"``, ``"aastex"``), ``"oja"``,
|
|
93
|
+
``"prd"`` (aliases ``"prl"``, ``"revtex"``), ``"jcap"``,
|
|
94
|
+
``"natastro"`` (alias ``"nature"``), ``"thesis"`` or ``"beamer"``.
|
|
95
|
+
usetex : bool, optional
|
|
96
|
+
If True, render all text with a real LaTeX installation using
|
|
97
|
+
fonts matching the journal (newtx Times for the serif journals,
|
|
98
|
+
Helvetica for Nature Astronomy). Default False (portable mathtext).
|
|
99
|
+
grid : bool, optional
|
|
100
|
+
Override the style's grid setting (the styles default to a
|
|
101
|
+
subtle grid; pass ``grid=False`` for a clean journal look).
|
|
102
|
+
**rc_overrides
|
|
103
|
+
Any extra rcParams, e.g. ``set_style("mnras", **{"font.size": 10})``.
|
|
104
|
+
|
|
105
|
+
Examples
|
|
106
|
+
--------
|
|
107
|
+
>>> pa.set_style("aanda")
|
|
108
|
+
>>> pa.set_style("mnras", usetex=True, grid=False)
|
|
109
|
+
"""
|
|
110
|
+
key = _resolve(journal)
|
|
111
|
+
style_file = STYLE_DIR / f"{JOURNALS[key]['style']}.mplstyle"
|
|
112
|
+
plt.style.use(style_file)
|
|
113
|
+
_state["journal"] = key
|
|
114
|
+
# Presets sharing a style file (thesis, beamer) still get the right
|
|
115
|
+
# default figure size:
|
|
116
|
+
mpl.rcParams["figure.figsize"] = figsize("column", journal=key)
|
|
117
|
+
if usetex:
|
|
118
|
+
mpl.rcParams.update({
|
|
119
|
+
"text.usetex": True,
|
|
120
|
+
"text.latex.preamble": JOURNALS[key]["tex"],
|
|
121
|
+
})
|
|
122
|
+
if grid is not None:
|
|
123
|
+
mpl.rcParams["axes.grid"] = bool(grid)
|
|
124
|
+
if rc_overrides:
|
|
125
|
+
mpl.rcParams.update(rc_overrides)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
#: Alias for :func:`set_style`, for those who prefer ``pa.use("mnras")`` —
|
|
129
|
+
#: after which everything is plain matplotlib.
|
|
130
|
+
use = set_style
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# ----------------------------------------------------------------------
|
|
134
|
+
# Figure sizing
|
|
135
|
+
# ----------------------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
def figsize(width="column", *, journal=None, fraction=1.0, nrows=1, ncols=1,
|
|
138
|
+
aspect=GOLDEN, height=None):
|
|
139
|
+
"""Figure dimensions (inches) that match the journal's text layout,
|
|
140
|
+
so the figure is never rescaled (and its fonts shrunk) by LaTeX.
|
|
141
|
+
|
|
142
|
+
Parameters
|
|
143
|
+
----------
|
|
144
|
+
width : {"column", "full"} or float
|
|
145
|
+
``"column"`` for a one-column figure, ``"full"`` for the full
|
|
146
|
+
text width, or a number = a custom width in LaTeX points
|
|
147
|
+
(get yours with ``\\the\\columnwidth`` in your .tex file).
|
|
148
|
+
journal : str, optional
|
|
149
|
+
Journal to size for; defaults to the one from the last
|
|
150
|
+
:func:`set_style` call.
|
|
151
|
+
fraction : float, optional
|
|
152
|
+
Fraction of that width to occupy (e.g. 0.5 for half a column).
|
|
153
|
+
nrows, ncols : int, optional
|
|
154
|
+
Subplot grid shape; the height scales so each panel keeps the
|
|
155
|
+
requested aspect ratio.
|
|
156
|
+
aspect : float, optional
|
|
157
|
+
Height/width ratio of one panel. Default: golden ratio (0.618).
|
|
158
|
+
Use ``aspect=1`` for square panels.
|
|
159
|
+
height : float, optional
|
|
160
|
+
Explicit figure height in inches (overrides ``aspect``).
|
|
161
|
+
|
|
162
|
+
Returns
|
|
163
|
+
-------
|
|
164
|
+
(width_in, height_in) : tuple of float
|
|
165
|
+
"""
|
|
166
|
+
key = _resolve(journal) if journal is not None else _state["journal"]
|
|
167
|
+
if isinstance(width, str):
|
|
168
|
+
w = width.lower()
|
|
169
|
+
if w in ("column", "col", "onecolumn", "one", "single"):
|
|
170
|
+
width_pt = JOURNALS[key]["column"]
|
|
171
|
+
elif w in ("full", "fullwidth", "two", "twocolumn", "page", "text"):
|
|
172
|
+
width_pt = JOURNALS[key]["full"]
|
|
173
|
+
else:
|
|
174
|
+
raise ValueError(
|
|
175
|
+
f"width must be 'column', 'full' or a number of points, got {width!r}")
|
|
176
|
+
else:
|
|
177
|
+
width_pt = float(width)
|
|
178
|
+
|
|
179
|
+
fig_width_in = width_pt * fraction / 72.27
|
|
180
|
+
if height is not None:
|
|
181
|
+
fig_height_in = float(height)
|
|
182
|
+
else:
|
|
183
|
+
fig_height_in = fig_width_in * aspect * (nrows / ncols)
|
|
184
|
+
return (fig_width_in, fig_height_in)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def subplots(nrows=1, ncols=1, *, width="column", journal=None, fraction=1.0,
|
|
188
|
+
aspect=GOLDEN, height=None, **kwargs):
|
|
189
|
+
"""`plt.subplots` with the figure size computed by :func:`figsize`.
|
|
190
|
+
|
|
191
|
+
Examples
|
|
192
|
+
--------
|
|
193
|
+
>>> fig, ax = pa.subplots() # one-column figure
|
|
194
|
+
>>> fig, axes = pa.subplots(2, 2, width="full") # full-width 2x2 grid
|
|
195
|
+
>>> fig, ax = pa.subplots(aspect=1) # square panel
|
|
196
|
+
"""
|
|
197
|
+
if "figsize" not in kwargs:
|
|
198
|
+
kwargs["figsize"] = figsize(width, journal=journal, fraction=fraction,
|
|
199
|
+
nrows=nrows, ncols=ncols, aspect=aspect,
|
|
200
|
+
height=height)
|
|
201
|
+
return plt.subplots(nrows, ncols, **kwargs)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def savefig(name, fig=None, formats=("pdf",), **kwargs):
|
|
205
|
+
"""Save a figure under one or more formats at once.
|
|
206
|
+
|
|
207
|
+
Parameters
|
|
208
|
+
----------
|
|
209
|
+
name : str or Path
|
|
210
|
+
Output path without extension (a known extension is stripped).
|
|
211
|
+
fig : Figure, optional
|
|
212
|
+
Defaults to the current figure.
|
|
213
|
+
formats : sequence of str, optional
|
|
214
|
+
e.g. ``("pdf", "png")`` to get both a vector file for the paper
|
|
215
|
+
and a raster preview.
|
|
216
|
+
**kwargs
|
|
217
|
+
Forwarded to ``fig.savefig`` (e.g. ``dpi=600``).
|
|
218
|
+
|
|
219
|
+
Returns
|
|
220
|
+
-------
|
|
221
|
+
list of str : the files written.
|
|
222
|
+
"""
|
|
223
|
+
fig = fig if fig is not None else plt.gcf()
|
|
224
|
+
base = Path(name)
|
|
225
|
+
if base.suffix.lower() in (".pdf", ".png", ".eps", ".svg", ".jpg", ".tiff"):
|
|
226
|
+
formats = (base.suffix[1:],)
|
|
227
|
+
base = base.with_suffix("")
|
|
228
|
+
written = []
|
|
229
|
+
for ext in formats:
|
|
230
|
+
out = f"{base}.{ext}"
|
|
231
|
+
fig.savefig(out, **kwargs)
|
|
232
|
+
written.append(out)
|
|
233
|
+
return written
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
# ----------------------------------------------------------------------
|
|
237
|
+
# Backwards compatibility with the original myfigsize.set_size()
|
|
238
|
+
# ----------------------------------------------------------------------
|
|
239
|
+
|
|
240
|
+
def set_size(width="mnras", fraction=1, subplots=(1, 1), hight_ratio=1):
|
|
241
|
+
"""Deprecated — use :func:`figsize` instead. Kept so old scripts run.
|
|
242
|
+
|
|
243
|
+
``set_size('mnras')`` == ``figsize('column', journal='mnras')`` and
|
|
244
|
+
``set_size('mnras_full')`` == ``figsize('full', journal='mnras')``.
|
|
245
|
+
"""
|
|
246
|
+
if width == "mnras_full":
|
|
247
|
+
return figsize("full", journal="mnras", fraction=fraction,
|
|
248
|
+
nrows=subplots[0], ncols=subplots[1],
|
|
249
|
+
aspect=GOLDEN * hight_ratio)
|
|
250
|
+
if isinstance(width, str):
|
|
251
|
+
return figsize("column", journal=width, fraction=fraction,
|
|
252
|
+
nrows=subplots[0], ncols=subplots[1],
|
|
253
|
+
aspect=GOLDEN * hight_ratio)
|
|
254
|
+
return figsize(width, fraction=fraction,
|
|
255
|
+
nrows=subplots[0], ncols=subplots[1],
|
|
256
|
+
aspect=GOLDEN * hight_ratio)
|
plotastro/_extras.py
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""Markers, line styles, property cyclers, panel labels, reference charts."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import functools
|
|
6
|
+
import operator
|
|
7
|
+
import string
|
|
8
|
+
|
|
9
|
+
import matplotlib.pyplot as plt
|
|
10
|
+
from cycler import cycler
|
|
11
|
+
|
|
12
|
+
from ._colors import COLORS, CYCLE
|
|
13
|
+
from ._core import figsize
|
|
14
|
+
|
|
15
|
+
#: A marker sequence that stays distinguishable at small sizes.
|
|
16
|
+
MARKERS = ["o", "s", "^", "D", "v", "p", "*", "X"]
|
|
17
|
+
|
|
18
|
+
#: Named dash patterns. The tuples are matplotlib (offset, (on, off, ...))
|
|
19
|
+
#: dash specs — they scale with the line width and print cleanly.
|
|
20
|
+
LINESTYLES = {
|
|
21
|
+
"solid": "-",
|
|
22
|
+
"dashed": (0, (5, 2)),
|
|
23
|
+
"dotted": (0, (1, 1.5)),
|
|
24
|
+
"dashdot": (0, (5, 2, 1, 2)),
|
|
25
|
+
"long dash": (0, (9, 3)),
|
|
26
|
+
"dash dot dot": (0, (5, 2, 1, 2, 1, 2)),
|
|
27
|
+
"densely dotted": (0, (1, 0.8)),
|
|
28
|
+
"loosely dashed": (0, (5, 6)),
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def style_cycler(n=None, *, colors=True, markers=False, linestyles=False):
|
|
33
|
+
"""Build a property cycler that pairs colours with markers and/or
|
|
34
|
+
dash patterns, so lines stay distinguishable in greyscale and for
|
|
35
|
+
colour-blind readers (redundant encoding).
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
n : int, optional
|
|
40
|
+
Number of entries (default: length of the colour cycle, or 8
|
|
41
|
+
when markers/linestyles are included).
|
|
42
|
+
colors, markers, linestyles : bool
|
|
43
|
+
Which properties to cycle together.
|
|
44
|
+
|
|
45
|
+
Examples
|
|
46
|
+
--------
|
|
47
|
+
>>> ax.set_prop_cycle(pa.style_cycler(markers=True))
|
|
48
|
+
>>> ax.set_prop_cycle(pa.style_cycler(linestyles=True))
|
|
49
|
+
>>> plt.rc("axes", prop_cycle=pa.style_cycler(markers=True)) # globally
|
|
50
|
+
"""
|
|
51
|
+
if n is None:
|
|
52
|
+
n = len(CYCLE) if not (markers or linestyles) else min(len(CYCLE), 8)
|
|
53
|
+
parts = []
|
|
54
|
+
if colors:
|
|
55
|
+
parts.append(cycler(color=(CYCLE * 3)[:n]))
|
|
56
|
+
if markers:
|
|
57
|
+
parts.append(cycler(marker=(MARKERS * 3)[:n]))
|
|
58
|
+
if linestyles:
|
|
59
|
+
parts.append(cycler(linestyle=(list(LINESTYLES.values()) * 3)[:n]))
|
|
60
|
+
if not parts:
|
|
61
|
+
raise ValueError("Enable at least one of colors/markers/linestyles.")
|
|
62
|
+
return functools.reduce(operator.add, parts)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# ----------------------------------------------------------------------
|
|
66
|
+
# Panel labels
|
|
67
|
+
# ----------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
_PANEL_POSITIONS = {
|
|
70
|
+
# loc: (x, y, ha, va) in axes coordinates
|
|
71
|
+
"upper left": (0.05, 0.95, "left", "top"),
|
|
72
|
+
"upper right": (0.95, 0.95, "right", "top"),
|
|
73
|
+
"lower left": (0.05, 0.05, "left", "bottom"),
|
|
74
|
+
"lower right": (0.95, 0.05, "right", "bottom"),
|
|
75
|
+
"outside": (0.0, 1.02, "left", "bottom"),
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def label_panels(axes, fmt="({})", loc="upper left", uppercase=False,
|
|
80
|
+
labels=None, **text_kw):
|
|
81
|
+
"""Stamp (a), (b), (c), ... on a grid of subplots, the way most
|
|
82
|
+
journals want multi-panel figures labelled.
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
axes : Axes, sequence of Axes, or array from plt.subplots
|
|
87
|
+
Labelled in the order given (arrays are flattened row-major).
|
|
88
|
+
fmt : str, optional
|
|
89
|
+
Applied to each letter; e.g. ``"({})"`` -> "(a)", ``"{}."`` -> "a.".
|
|
90
|
+
loc : str, optional
|
|
91
|
+
One of "upper left", "upper right", "lower left", "lower right",
|
|
92
|
+
or "outside" (above the top-left corner — the Nature convention,
|
|
93
|
+
usually combined with ``fmt="{}"`` and bold text).
|
|
94
|
+
uppercase : bool, optional
|
|
95
|
+
Use A, B, C instead of a, b, c.
|
|
96
|
+
labels : sequence of str, optional
|
|
97
|
+
Explicit labels, overriding the alphabet.
|
|
98
|
+
**text_kw
|
|
99
|
+
Forwarded to ``ax.text`` (e.g. ``fontweight="bold"``).
|
|
100
|
+
|
|
101
|
+
Returns
|
|
102
|
+
-------
|
|
103
|
+
list of the Text objects created.
|
|
104
|
+
|
|
105
|
+
Examples
|
|
106
|
+
--------
|
|
107
|
+
>>> fig, axes = pa.subplots(2, 2, width="full")
|
|
108
|
+
>>> pa.label_panels(axes)
|
|
109
|
+
>>> pa.label_panels(axes, loc="outside", fmt="{}", fontweight="bold")
|
|
110
|
+
"""
|
|
111
|
+
if hasattr(axes, "flat"): # numpy array from plt.subplots
|
|
112
|
+
axes = list(axes.flat)
|
|
113
|
+
elif not hasattr(axes, "__iter__"):
|
|
114
|
+
axes = [axes]
|
|
115
|
+
if loc not in _PANEL_POSITIONS:
|
|
116
|
+
options = ", ".join(_PANEL_POSITIONS)
|
|
117
|
+
raise ValueError(f"loc must be one of: {options}; got {loc!r}")
|
|
118
|
+
x, y, ha, va = _PANEL_POSITIONS[loc]
|
|
119
|
+
letters = string.ascii_uppercase if uppercase else string.ascii_lowercase
|
|
120
|
+
if labels is None:
|
|
121
|
+
labels = [fmt.format(letters[i]) for i in range(len(axes))]
|
|
122
|
+
texts = []
|
|
123
|
+
for ax, label in zip(axes, labels):
|
|
124
|
+
texts.append(ax.text(x, y, label, transform=ax.transAxes,
|
|
125
|
+
ha=ha, va=va, **text_kw))
|
|
126
|
+
return texts
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# ----------------------------------------------------------------------
|
|
130
|
+
# Reference charts (used in the tutorial and README)
|
|
131
|
+
# ----------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
def show_colors(palette=None, title="Default colour-blind-friendly cycle"):
|
|
134
|
+
"""Swatch chart of a palette dict (default: the style's colour cycle)."""
|
|
135
|
+
palette = palette if palette is not None else COLORS
|
|
136
|
+
names = list(palette)
|
|
137
|
+
fig, ax = plt.subplots(
|
|
138
|
+
figsize=figsize("full", journal="mnras", fraction=0.9,
|
|
139
|
+
height=0.32 * len(names) + 0.5))
|
|
140
|
+
ax.set_axis_off()
|
|
141
|
+
ax.set_title(title)
|
|
142
|
+
for i, name in enumerate(names):
|
|
143
|
+
y = len(names) - 1 - i
|
|
144
|
+
ax.add_patch(plt.Rectangle((0, y + 0.1), 1.6, 0.8,
|
|
145
|
+
color=palette[name], ec="0.2", lw=0.4))
|
|
146
|
+
ax.text(1.75, y + 0.5, f"C{i} · {name} · {str(palette[name]).upper()}",
|
|
147
|
+
va="center", ha="left", fontsize=8, family="monospace")
|
|
148
|
+
ax.set_xlim(0, 6)
|
|
149
|
+
ax.set_ylim(0, len(names))
|
|
150
|
+
return fig
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def show_markers():
|
|
154
|
+
"""Reference chart of the marker sequence (and a few more)."""
|
|
155
|
+
extra = ["<", ">", "h", "8", "P", "d", "x", "+"]
|
|
156
|
+
all_markers = MARKERS + extra
|
|
157
|
+
fig, ax = plt.subplots(
|
|
158
|
+
figsize=figsize("full", journal="mnras", fraction=0.9, height=1.6))
|
|
159
|
+
ax.set_axis_off()
|
|
160
|
+
ax.set_title("Markers — first row is plotastro.MARKERS")
|
|
161
|
+
for i, m in enumerate(all_markers):
|
|
162
|
+
row, col = divmod(i, 8)
|
|
163
|
+
y = 1.4 - row
|
|
164
|
+
ax.plot(col, y, marker=m, ms=7, color=CYCLE[col % len(CYCLE)],
|
|
165
|
+
ls="none", clip_on=False)
|
|
166
|
+
ax.text(col, y - 0.42, repr(m), ha="center", va="top", fontsize=8,
|
|
167
|
+
family="monospace")
|
|
168
|
+
ax.set_xlim(-0.5, 7.5)
|
|
169
|
+
ax.set_ylim(-0.7, 2.0)
|
|
170
|
+
return fig
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def show_linestyles():
|
|
174
|
+
"""Reference chart of the named dash patterns in LINESTYLES."""
|
|
175
|
+
fig, ax = plt.subplots(
|
|
176
|
+
figsize=figsize("full", journal="mnras", fraction=0.9,
|
|
177
|
+
height=0.34 * len(LINESTYLES) + 0.5))
|
|
178
|
+
ax.set_axis_off()
|
|
179
|
+
ax.set_title("Named line styles — plotastro.LINESTYLES")
|
|
180
|
+
for i, (name, ls) in enumerate(LINESTYLES.items()):
|
|
181
|
+
y = len(LINESTYLES) - 1 - i
|
|
182
|
+
ax.plot([0.35, 1.0], [y, y], ls=ls, lw=1.4,
|
|
183
|
+
color=CYCLE[i % len(CYCLE)])
|
|
184
|
+
ax.text(0.32, y, name, ha="right", va="center", fontsize=8)
|
|
185
|
+
ax.set_xlim(0, 1.02)
|
|
186
|
+
ax.set_ylim(-0.6, len(LINESTYLES) - 0.4)
|
|
187
|
+
return fig
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# =====================================================================
|
|
2
|
+
# aanda.mplstyle — Astronomy & Astrophysics (A&A)
|
|
3
|
+
#
|
|
4
|
+
# Figure widths:
|
|
5
|
+
# one column : 250.38 pt = 3.46 in (88 mm)
|
|
6
|
+
# full width : 512.15 pt = 7.09 in (180 mm)
|
|
7
|
+
# (from the A&A author guide: 88 mm / 170-180 mm)
|
|
8
|
+
# The default figsize below is one column wide with a golden-ratio
|
|
9
|
+
# height. For other sizes use plotastro.figsize() / plotastro.subplots().
|
|
10
|
+
#
|
|
11
|
+
# Colours: colour-blind-friendly cycle — see the README for details.
|
|
12
|
+
# Generated by tools/generate_styles.py — edit that, not this file.
|
|
13
|
+
#
|
|
14
|
+
# Usage: import plotastro; plotastro.set_style("aanda")
|
|
15
|
+
# or: import plotastro; plt.style.use("aanda")
|
|
16
|
+
# =====================================================================
|
|
17
|
+
|
|
18
|
+
## ---- Lines & markers ------------------------------------------------
|
|
19
|
+
lines.linewidth : 1.2
|
|
20
|
+
lines.markersize : 4
|
|
21
|
+
lines.markeredgewidth : 0.8
|
|
22
|
+
errorbar.capsize : 2
|
|
23
|
+
patch.linewidth : 0.8
|
|
24
|
+
|
|
25
|
+
## ---- Fonts ----------------------------------------------------------
|
|
26
|
+
font.family : serif
|
|
27
|
+
font.serif : Times New Roman, Times, Nimbus Roman, STIXGeneral, DejaVu Serif
|
|
28
|
+
font.size : 9
|
|
29
|
+
mathtext.fontset : stix # Times-compatible maths without LaTeX
|
|
30
|
+
|
|
31
|
+
# Full LaTeX text rendering (needs a working LaTeX installation).
|
|
32
|
+
# Uncomment below, or call plotastro.set_style("aanda", usetex=True).
|
|
33
|
+
#text.usetex : True
|
|
34
|
+
#text.latex.preamble : \usepackage{newtxtext}\usepackage{newtxmath}
|
|
35
|
+
|
|
36
|
+
## ---- Axes -----------------------------------------------------------
|
|
37
|
+
axes.linewidth : 0.6
|
|
38
|
+
axes.labelsize : medium
|
|
39
|
+
axes.titlesize : medium
|
|
40
|
+
axes.labelpad : 3
|
|
41
|
+
axes.axisbelow : True # grid behind the data
|
|
42
|
+
axes.formatter.use_mathtext: True
|
|
43
|
+
axes.xmargin : 0.03
|
|
44
|
+
axes.ymargin : 0.05
|
|
45
|
+
|
|
46
|
+
# Colour-blind-friendly colour cycle (see README, "The colour palette")
|
|
47
|
+
axes.prop_cycle : cycler('color', ['377eb8', 'ff7f00', '4daf4a', 'f781bf', 'a65628', '984ea3', '999999', 'e41a1c', 'dede00', 'a2c8ec', 'ffbc79', 'ababab'])
|
|
48
|
+
|
|
49
|
+
## ---- Grid (subtle; set axes.grid: False to disable) -----------------
|
|
50
|
+
axes.grid : True
|
|
51
|
+
grid.linewidth : 0.4
|
|
52
|
+
grid.alpha : 0.25
|
|
53
|
+
|
|
54
|
+
## ---- Ticks: all four sides, pointing in, with minors ----------------
|
|
55
|
+
xtick.direction : in
|
|
56
|
+
xtick.top : True
|
|
57
|
+
xtick.bottom : True
|
|
58
|
+
xtick.minor.visible : True
|
|
59
|
+
xtick.major.size : 3.5
|
|
60
|
+
xtick.minor.size : 2
|
|
61
|
+
xtick.major.width : 0.6
|
|
62
|
+
xtick.minor.width : 0.4
|
|
63
|
+
xtick.labelsize : small # ~1 pt below the base font size
|
|
64
|
+
|
|
65
|
+
ytick.direction : in
|
|
66
|
+
ytick.left : True
|
|
67
|
+
ytick.right : True
|
|
68
|
+
ytick.minor.visible : True
|
|
69
|
+
ytick.major.size : 3.5
|
|
70
|
+
ytick.minor.size : 2
|
|
71
|
+
ytick.major.width : 0.6
|
|
72
|
+
ytick.minor.width : 0.4
|
|
73
|
+
ytick.labelsize : small
|
|
74
|
+
|
|
75
|
+
## ---- Legend ---------------------------------------------------------
|
|
76
|
+
legend.fontsize : small
|
|
77
|
+
legend.title_fontsize : small
|
|
78
|
+
legend.frameon : False
|
|
79
|
+
legend.handlelength : 1.8
|
|
80
|
+
legend.handletextpad : 0.5
|
|
81
|
+
legend.labelspacing : 0.3
|
|
82
|
+
legend.columnspacing : 1.2
|
|
83
|
+
legend.borderaxespad : 0.4
|
|
84
|
+
|
|
85
|
+
## ---- Figure ---------------------------------------------------------
|
|
86
|
+
figure.figsize : 3.4646, 2.1412 # one column, golden ratio
|
|
87
|
+
figure.dpi : 150 # on-screen / notebook display
|
|
88
|
+
figure.titlesize : medium
|
|
89
|
+
figure.constrained_layout.use : True # no cut-off labels
|
|
90
|
+
|
|
91
|
+
## ---- Images ---------------------------------------------------------
|
|
92
|
+
image.cmap : viridis
|
|
93
|
+
#image.origin : lower # uncomment for the astro image convention
|
|
94
|
+
|
|
95
|
+
## ---- Saving ---------------------------------------------------------
|
|
96
|
+
savefig.format : pdf # journals prefer vector formats
|
|
97
|
+
savefig.dpi : 450 # comfortably above journal raster minimums
|
|
98
|
+
savefig.bbox : tight
|
|
99
|
+
savefig.pad_inches : 0.02
|
|
100
|
+
pdf.fonttype : 42 # embed TrueType fonts (no Type-3)
|
|
101
|
+
ps.fonttype : 42
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# =====================================================================
|
|
2
|
+
# apj.mplstyle — The Astrophysical Journal (ApJ / ApJL, AASTeX v6.3+)
|
|
3
|
+
#
|
|
4
|
+
# Figure widths:
|
|
5
|
+
# one column : 242.27 pt = 3.35 in
|
|
6
|
+
# full width : 513.12 pt = 7.10 in
|
|
7
|
+
# (from the aastex631 two-column class)
|
|
8
|
+
# The default figsize below is one column wide with a golden-ratio
|
|
9
|
+
# height. For other sizes use plotastro.figsize() / plotastro.subplots().
|
|
10
|
+
#
|
|
11
|
+
# Colours: colour-blind-friendly cycle — see the README for details.
|
|
12
|
+
# Generated by tools/generate_styles.py — edit that, not this file.
|
|
13
|
+
#
|
|
14
|
+
# Usage: import plotastro; plotastro.set_style("apj")
|
|
15
|
+
# or: import plotastro; plt.style.use("apj")
|
|
16
|
+
# =====================================================================
|
|
17
|
+
|
|
18
|
+
## ---- Lines & markers ------------------------------------------------
|
|
19
|
+
lines.linewidth : 1.2
|
|
20
|
+
lines.markersize : 4
|
|
21
|
+
lines.markeredgewidth : 0.8
|
|
22
|
+
errorbar.capsize : 2
|
|
23
|
+
patch.linewidth : 0.8
|
|
24
|
+
|
|
25
|
+
## ---- Fonts ----------------------------------------------------------
|
|
26
|
+
font.family : serif
|
|
27
|
+
font.serif : Times New Roman, Times, Nimbus Roman, STIXGeneral, DejaVu Serif
|
|
28
|
+
font.size : 9
|
|
29
|
+
mathtext.fontset : stix # Times-compatible maths without LaTeX
|
|
30
|
+
|
|
31
|
+
# Full LaTeX text rendering (needs a working LaTeX installation).
|
|
32
|
+
# Uncomment below, or call plotastro.set_style("apj", usetex=True).
|
|
33
|
+
#text.usetex : True
|
|
34
|
+
#text.latex.preamble : \usepackage{newtxtext}\usepackage{newtxmath}
|
|
35
|
+
|
|
36
|
+
## ---- Axes -----------------------------------------------------------
|
|
37
|
+
axes.linewidth : 0.6
|
|
38
|
+
axes.labelsize : medium
|
|
39
|
+
axes.titlesize : medium
|
|
40
|
+
axes.labelpad : 3
|
|
41
|
+
axes.axisbelow : True # grid behind the data
|
|
42
|
+
axes.formatter.use_mathtext: True
|
|
43
|
+
axes.xmargin : 0.03
|
|
44
|
+
axes.ymargin : 0.05
|
|
45
|
+
|
|
46
|
+
# Colour-blind-friendly colour cycle (see README, "The colour palette")
|
|
47
|
+
axes.prop_cycle : cycler('color', ['377eb8', 'ff7f00', '4daf4a', 'f781bf', 'a65628', '984ea3', '999999', 'e41a1c', 'dede00', 'a2c8ec', 'ffbc79', 'ababab'])
|
|
48
|
+
|
|
49
|
+
## ---- Grid (subtle; set axes.grid: False to disable) -----------------
|
|
50
|
+
axes.grid : True
|
|
51
|
+
grid.linewidth : 0.4
|
|
52
|
+
grid.alpha : 0.25
|
|
53
|
+
|
|
54
|
+
## ---- Ticks: all four sides, pointing in, with minors ----------------
|
|
55
|
+
xtick.direction : in
|
|
56
|
+
xtick.top : True
|
|
57
|
+
xtick.bottom : True
|
|
58
|
+
xtick.minor.visible : True
|
|
59
|
+
xtick.major.size : 3.5
|
|
60
|
+
xtick.minor.size : 2
|
|
61
|
+
xtick.major.width : 0.6
|
|
62
|
+
xtick.minor.width : 0.4
|
|
63
|
+
xtick.labelsize : small # ~1 pt below the base font size
|
|
64
|
+
|
|
65
|
+
ytick.direction : in
|
|
66
|
+
ytick.left : True
|
|
67
|
+
ytick.right : True
|
|
68
|
+
ytick.minor.visible : True
|
|
69
|
+
ytick.major.size : 3.5
|
|
70
|
+
ytick.minor.size : 2
|
|
71
|
+
ytick.major.width : 0.6
|
|
72
|
+
ytick.minor.width : 0.4
|
|
73
|
+
ytick.labelsize : small
|
|
74
|
+
|
|
75
|
+
## ---- Legend ---------------------------------------------------------
|
|
76
|
+
legend.fontsize : small
|
|
77
|
+
legend.title_fontsize : small
|
|
78
|
+
legend.frameon : False
|
|
79
|
+
legend.handlelength : 1.8
|
|
80
|
+
legend.handletextpad : 0.5
|
|
81
|
+
legend.labelspacing : 0.3
|
|
82
|
+
legend.columnspacing : 1.2
|
|
83
|
+
legend.borderaxespad : 0.4
|
|
84
|
+
|
|
85
|
+
## ---- Figure ---------------------------------------------------------
|
|
86
|
+
figure.figsize : 3.3522, 2.0718 # one column, golden ratio
|
|
87
|
+
figure.dpi : 150 # on-screen / notebook display
|
|
88
|
+
figure.titlesize : medium
|
|
89
|
+
figure.constrained_layout.use : True # no cut-off labels
|
|
90
|
+
|
|
91
|
+
## ---- Images ---------------------------------------------------------
|
|
92
|
+
image.cmap : viridis
|
|
93
|
+
#image.origin : lower # uncomment for the astro image convention
|
|
94
|
+
|
|
95
|
+
## ---- Saving ---------------------------------------------------------
|
|
96
|
+
savefig.format : pdf # journals prefer vector formats
|
|
97
|
+
savefig.dpi : 450 # comfortably above journal raster minimums
|
|
98
|
+
savefig.bbox : tight
|
|
99
|
+
savefig.pad_inches : 0.02
|
|
100
|
+
pdf.fonttype : 42 # embed TrueType fonts (no Type-3)
|
|
101
|
+
ps.fonttype : 42
|