lsst-utils 25.2023.600__py3-none-any.whl → 29.2025.4800__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.
- lsst/utils/__init__.py +0 -3
- lsst/utils/_packaging.py +2 -0
- lsst/utils/argparsing.py +79 -0
- lsst/utils/classes.py +27 -9
- lsst/utils/db_auth.py +339 -0
- lsst/utils/deprecated.py +10 -7
- lsst/utils/doImport.py +8 -9
- lsst/utils/inheritDoc.py +34 -6
- lsst/utils/introspection.py +285 -19
- lsst/utils/iteration.py +193 -7
- lsst/utils/logging.py +155 -105
- lsst/utils/packages.py +324 -82
- lsst/utils/plotting/__init__.py +15 -0
- lsst/utils/plotting/figures.py +159 -0
- lsst/utils/plotting/limits.py +155 -0
- lsst/utils/plotting/publication_plots.py +184 -0
- lsst/utils/plotting/rubin.mplstyle +46 -0
- lsst/utils/tests.py +231 -102
- lsst/utils/threads.py +9 -3
- lsst/utils/timer.py +207 -110
- lsst/utils/usage.py +6 -6
- lsst/utils/version.py +1 -1
- lsst/utils/wrappers.py +74 -29
- {lsst_utils-25.2023.600.dist-info → lsst_utils-29.2025.4800.dist-info}/METADATA +19 -15
- lsst_utils-29.2025.4800.dist-info/RECORD +32 -0
- {lsst_utils-25.2023.600.dist-info → lsst_utils-29.2025.4800.dist-info}/WHEEL +1 -1
- lsst/utils/_forwarded.py +0 -28
- lsst/utils/backtrace/__init__.py +0 -33
- lsst/utils/ellipsis.py +0 -54
- lsst/utils/get_caller_name.py +0 -45
- lsst_utils-25.2023.600.dist-info/RECORD +0 -29
- {lsst_utils-25.2023.600.dist-info → lsst_utils-29.2025.4800.dist-info/licenses}/COPYRIGHT +0 -0
- {lsst_utils-25.2023.600.dist-info → lsst_utils-29.2025.4800.dist-info/licenses}/LICENSE +0 -0
- {lsst_utils-25.2023.600.dist-info → lsst_utils-29.2025.4800.dist-info}/top_level.txt +0 -0
- {lsst_utils-25.2023.600.dist-info → lsst_utils-29.2025.4800.dist-info}/zip-safe +0 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# This file is part of utils.
|
|
2
|
+
#
|
|
3
|
+
# Developed for the LSST Data Management System.
|
|
4
|
+
# This product includes software developed by the LSST Project
|
|
5
|
+
# (https://www.lsst.org).
|
|
6
|
+
# See the COPYRIGHT file at the top-level directory of this distribution
|
|
7
|
+
# for details of code ownership.
|
|
8
|
+
#
|
|
9
|
+
# Use of this source code is governed by a 3-clause BSD-style
|
|
10
|
+
# license that can be found in the LICENSE file.
|
|
11
|
+
"""Utilities related to making matplotlib figures."""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"get_multiband_plot_colors",
|
|
17
|
+
"get_multiband_plot_linestyles",
|
|
18
|
+
"get_multiband_plot_symbols",
|
|
19
|
+
"make_figure",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
from typing import TYPE_CHECKING, Any
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from matplotlib.figure import Figure
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def make_figure(**kwargs: Any) -> Figure:
|
|
29
|
+
"""Make a matplotlib Figure with an Agg-backend canvas.
|
|
30
|
+
|
|
31
|
+
This routine creates a matplotlib figure without using
|
|
32
|
+
``matplotlib.pyplot``, and instead uses a fixed non-interactive
|
|
33
|
+
backend. The advantage is that these figures are not cached and
|
|
34
|
+
therefore do not need to be explicitly closed -- they
|
|
35
|
+
are completely self-contained and ephemeral unlike figures
|
|
36
|
+
created with `matplotlib.pyplot.figure()`.
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
**kwargs : `dict`
|
|
41
|
+
Keyword arguments to be passed to `matplotlib.figure.Figure()`.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
figure : `matplotlib.figure.Figure`
|
|
46
|
+
Figure with a fixed Agg backend, and no caching.
|
|
47
|
+
|
|
48
|
+
Notes
|
|
49
|
+
-----
|
|
50
|
+
The code here is based on
|
|
51
|
+
https://matplotlib.org/stable/gallery/user_interfaces/canvasagg.html
|
|
52
|
+
"""
|
|
53
|
+
try:
|
|
54
|
+
from matplotlib.backends.backend_agg import FigureCanvasAgg
|
|
55
|
+
from matplotlib.figure import Figure
|
|
56
|
+
except ImportError as e:
|
|
57
|
+
raise RuntimeError("Cannot use make_figure without matplotlib.") from e
|
|
58
|
+
|
|
59
|
+
fig = Figure(**kwargs)
|
|
60
|
+
FigureCanvasAgg(fig)
|
|
61
|
+
|
|
62
|
+
return fig
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def get_multiband_plot_colors(dark_background: bool = False) -> dict:
|
|
66
|
+
"""Get color mappings for multiband plots using SDSS filter names.
|
|
67
|
+
|
|
68
|
+
Notes
|
|
69
|
+
-----
|
|
70
|
+
From https://rtn-045.lsst.io/#colorblind-friendly-plots
|
|
71
|
+
|
|
72
|
+
Parameters
|
|
73
|
+
----------
|
|
74
|
+
dark_background : `bool`, optional
|
|
75
|
+
Use colors intended for a dark background.
|
|
76
|
+
Default colors are intended for a light background.
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
plot_colors : `dict` of `str`
|
|
81
|
+
Mapping of the LSST bands to colors.
|
|
82
|
+
"""
|
|
83
|
+
plot_filter_colors_white_background = {
|
|
84
|
+
"u": "#1600EA",
|
|
85
|
+
"g": "#31DE1F",
|
|
86
|
+
"r": "#B52626",
|
|
87
|
+
"i": "#370201",
|
|
88
|
+
"z": "#BA52FF",
|
|
89
|
+
"y": "#61A2B3",
|
|
90
|
+
}
|
|
91
|
+
plot_filter_colors_black_background = {
|
|
92
|
+
"u": "#3eb7ff",
|
|
93
|
+
"g": "#30c39f",
|
|
94
|
+
"r": "#ff7e00",
|
|
95
|
+
"i": "#2af5ff",
|
|
96
|
+
"z": "#a7f9c1",
|
|
97
|
+
"y": "#fdc900",
|
|
98
|
+
}
|
|
99
|
+
if dark_background:
|
|
100
|
+
return plot_filter_colors_black_background
|
|
101
|
+
else:
|
|
102
|
+
return plot_filter_colors_white_background
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def get_multiband_plot_symbols() -> dict:
|
|
106
|
+
"""Get symbol mappings for multiband plots using SDSS filter names.
|
|
107
|
+
|
|
108
|
+
Notes
|
|
109
|
+
-----
|
|
110
|
+
From https://rtn-045.lsst.io/#colorblind-friendly-plots
|
|
111
|
+
|
|
112
|
+
Returns
|
|
113
|
+
-------
|
|
114
|
+
plot_symbols : `dict` of `str`
|
|
115
|
+
Mapping of the LSST bands to symbols.
|
|
116
|
+
"""
|
|
117
|
+
plot_symbols = {
|
|
118
|
+
"u": "o",
|
|
119
|
+
"g": "^",
|
|
120
|
+
"r": "v",
|
|
121
|
+
"i": "s",
|
|
122
|
+
"z": "*",
|
|
123
|
+
"y": "p",
|
|
124
|
+
}
|
|
125
|
+
return plot_symbols
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def get_multiband_plot_linestyles() -> dict:
|
|
129
|
+
"""Get line style mappings for multiband plots using SDSS filter names.
|
|
130
|
+
|
|
131
|
+
Notes
|
|
132
|
+
-----
|
|
133
|
+
From https://rtn-045.lsst.io/#colorblind-friendly-plots
|
|
134
|
+
|
|
135
|
+
Returns
|
|
136
|
+
-------
|
|
137
|
+
plot_linestyles : `dict` of `str`
|
|
138
|
+
Mapping of the LSST bands to line styles.
|
|
139
|
+
"""
|
|
140
|
+
plot_line_styles = {
|
|
141
|
+
"u": "--",
|
|
142
|
+
"g": (0, (3, 1, 1, 1)),
|
|
143
|
+
"r": "-.",
|
|
144
|
+
"i": "-",
|
|
145
|
+
"z": (0, (3, 1, 1, 1, 1, 1)),
|
|
146
|
+
"y": ":",
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
# [SP-2200]: Restored to using parametric values.
|
|
150
|
+
# To avoid matplotlib v3.10 bug (see DM-49724),
|
|
151
|
+
# manually iterate over `patches` object returned
|
|
152
|
+
# by `plt.hist` when using histtype='step':
|
|
153
|
+
# _, _, patches = plt.hist()
|
|
154
|
+
# linestyle = plot_line_styles[band]
|
|
155
|
+
# for patch in patches:
|
|
156
|
+
# patch.set_linestyle(linestyle)
|
|
157
|
+
# It seems the bug will be fixed in matplotlib v.3.10.2,
|
|
158
|
+
# see DM-49724[TODO]
|
|
159
|
+
return plot_line_styles
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# This file is part of utils.
|
|
2
|
+
#
|
|
3
|
+
# Developed for the LSST Data Management System.
|
|
4
|
+
# This product includes software developed by the LSST Project
|
|
5
|
+
# (https://www.lsst.org).
|
|
6
|
+
# See the COPYRIGHT file at the top-level directory of this distribution
|
|
7
|
+
# for details of code ownership.
|
|
8
|
+
#
|
|
9
|
+
# Use of this source code is governed by a 3-clause BSD-style
|
|
10
|
+
# license that can be found in the LICENSE file.
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
__all__ = ["calculate_safe_plotting_limits", "make_calculate_safe_plotting_limits"]
|
|
15
|
+
|
|
16
|
+
from collections.abc import Callable, Iterable, Sequence
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def calculate_safe_plotting_limits(
|
|
22
|
+
data_series: Sequence,
|
|
23
|
+
percentile: float = 99.9,
|
|
24
|
+
constant_extra: float | None = None,
|
|
25
|
+
symmetric_around_zero: bool = False,
|
|
26
|
+
) -> tuple[float, float]:
|
|
27
|
+
"""Calculate the right limits for plotting for one or more data series.
|
|
28
|
+
|
|
29
|
+
Given one or more data series with potential outliers, calculated the
|
|
30
|
+
values to pass for ymin, ymax so that extreme outliers don't ruin the
|
|
31
|
+
plot. If you are plotting several series on a single axis, pass them
|
|
32
|
+
all in and the overall plotting range will be given.
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
data_series : `iterable` or `iterable` of `iterable`
|
|
37
|
+
One or more data series which will be going on the same axis, and
|
|
38
|
+
therefore want to have their common plotting limits calculated.
|
|
39
|
+
percentile : `float`, optional
|
|
40
|
+
The percentile used to clip the outliers from the data.
|
|
41
|
+
constant_extra : `float` or `None`, optional
|
|
42
|
+
The amount that's added on each side of the range so that data does not
|
|
43
|
+
quite touch the axes. If the default ``None`` is left then 5% of the
|
|
44
|
+
data range is added for cosmetics, but if zero is set this will
|
|
45
|
+
overrides this behaviour and zero you will get.
|
|
46
|
+
symmetric_around_zero : `bool`, optional
|
|
47
|
+
Whether to make the limits symmetric around zero.
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
ymin : `float`
|
|
52
|
+
The value to set the ylim minimum to.
|
|
53
|
+
ymax : `float`
|
|
54
|
+
The value to set the ylim maximum to.
|
|
55
|
+
"""
|
|
56
|
+
localFunc = make_calculate_safe_plotting_limits(percentile, constant_extra, symmetric_around_zero)
|
|
57
|
+
return localFunc(data_series)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def make_calculate_safe_plotting_limits(
|
|
61
|
+
percentile: float = 99.9,
|
|
62
|
+
constant_extra: float | None = None,
|
|
63
|
+
symmetric_around_zero: bool = False,
|
|
64
|
+
) -> Callable[[Sequence], tuple[float, float]]:
|
|
65
|
+
"""Make a ``calculate_safe_plotting_limits`` closure to get the common
|
|
66
|
+
limits when not all data series are available initially.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
percentile : `float`, optional
|
|
71
|
+
The percentile used to clip the outliers from the data.
|
|
72
|
+
constant_extra : `float`, optional
|
|
73
|
+
The amount that's added on each side of the range so that data does not
|
|
74
|
+
quite touch the axes. If the default ``None`` is left then 5% of the
|
|
75
|
+
data range is added for cosmetics, but if zero is set this will
|
|
76
|
+
overrides this behaviour and zero you will get.
|
|
77
|
+
symmetric_around_zero : `bool`, optional
|
|
78
|
+
Whether to make the limits symmetric around zero.
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
calculate_safe_plotting_limits : `callable`
|
|
83
|
+
The calculate_safe_plotting_limits function to pass the data series to.
|
|
84
|
+
"""
|
|
85
|
+
memory: list[Sequence] = []
|
|
86
|
+
|
|
87
|
+
def calculate_safe_plotting_limits(
|
|
88
|
+
data_series: Sequence, # a sequence of sequences is still a sequence
|
|
89
|
+
) -> tuple[float, float]:
|
|
90
|
+
"""Calculate the right limits for plotting for one or more data series.
|
|
91
|
+
|
|
92
|
+
Given one or more data series with potential outliers, calculated the
|
|
93
|
+
values to pass for ymin, ymax so that extreme outliers don't ruin the
|
|
94
|
+
plot. If you are plotting several series on a single axis, pass them
|
|
95
|
+
all in and the overall plotting range will be given.
|
|
96
|
+
|
|
97
|
+
Parameters
|
|
98
|
+
----------
|
|
99
|
+
data_series : `iterable` or `iterable` of `iterable`
|
|
100
|
+
One or more data series which will be going on the same axis, and
|
|
101
|
+
therefore want to have their common plotting limits calculated.
|
|
102
|
+
|
|
103
|
+
Returns
|
|
104
|
+
-------
|
|
105
|
+
ymin : `float`
|
|
106
|
+
The value to set the ylim minimum to.
|
|
107
|
+
ymax : `float`
|
|
108
|
+
The value to set the ylim maximum to.
|
|
109
|
+
"""
|
|
110
|
+
nonlocal constant_extra
|
|
111
|
+
nonlocal percentile
|
|
112
|
+
nonlocal symmetric_around_zero
|
|
113
|
+
|
|
114
|
+
if not isinstance(data_series, Iterable):
|
|
115
|
+
raise TypeError("data_series must be either an iterable, or an iterable of iterables")
|
|
116
|
+
|
|
117
|
+
# now we're sure we have an iterable, if it's just one make it a list
|
|
118
|
+
# of it lsst.utils.ensure_iterable is not suitable here as we already
|
|
119
|
+
# have one, we would need ensure_iterable_of_iterables here
|
|
120
|
+
|
|
121
|
+
# np.array are Iterable but not Sequence so isinstance that
|
|
122
|
+
if not isinstance(data_series[0], Iterable):
|
|
123
|
+
# we have a single data series, not multiple, wrap in [] so we can
|
|
124
|
+
# iterate over it as if we were given many
|
|
125
|
+
data_series = [data_series]
|
|
126
|
+
|
|
127
|
+
memory.extend(data_series)
|
|
128
|
+
|
|
129
|
+
mins = []
|
|
130
|
+
maxs = []
|
|
131
|
+
|
|
132
|
+
for dataSeries in memory:
|
|
133
|
+
max_val = np.nanpercentile(dataSeries, percentile)
|
|
134
|
+
min_val = np.nanpercentile(dataSeries, 100.0 - percentile)
|
|
135
|
+
|
|
136
|
+
if constant_extra is None:
|
|
137
|
+
data_range = max_val - min_val
|
|
138
|
+
constant_extra = 0.05 * data_range
|
|
139
|
+
|
|
140
|
+
max_val += constant_extra
|
|
141
|
+
min_val -= constant_extra
|
|
142
|
+
|
|
143
|
+
maxs.append(max_val)
|
|
144
|
+
mins.append(min_val)
|
|
145
|
+
|
|
146
|
+
max_val = max(maxs)
|
|
147
|
+
min_val = min(mins)
|
|
148
|
+
|
|
149
|
+
if symmetric_around_zero:
|
|
150
|
+
biggest_abs = max(abs(min_val), abs(max_val))
|
|
151
|
+
return -biggest_abs, biggest_abs
|
|
152
|
+
|
|
153
|
+
return min_val, max_val
|
|
154
|
+
|
|
155
|
+
return calculate_safe_plotting_limits
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# This file is part of utils.
|
|
2
|
+
#
|
|
3
|
+
# Developed for the LSST Data Management System.
|
|
4
|
+
# This product includes software developed by the LSST Project
|
|
5
|
+
# (https://www.lsst.org).
|
|
6
|
+
# See the COPYRIGHT file at the top-level directory of this distribution
|
|
7
|
+
# for details of code ownership.
|
|
8
|
+
#
|
|
9
|
+
# Use of this source code is governed by a 3-clause BSD-style
|
|
10
|
+
# license that can be found in the LICENSE file.
|
|
11
|
+
"""Utilities for making publication-quality figures."""
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"accent_color",
|
|
15
|
+
"divergent_cmap",
|
|
16
|
+
"galaxies_cmap",
|
|
17
|
+
"galaxies_color",
|
|
18
|
+
"get_band_dicts",
|
|
19
|
+
"mk_colormap",
|
|
20
|
+
"set_rubin_plotstyle",
|
|
21
|
+
"sso_cmap",
|
|
22
|
+
"sso_color",
|
|
23
|
+
"stars_cmap",
|
|
24
|
+
"stars_color",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
import numpy as np
|
|
28
|
+
|
|
29
|
+
from . import (
|
|
30
|
+
get_multiband_plot_colors,
|
|
31
|
+
get_multiband_plot_linestyles,
|
|
32
|
+
get_multiband_plot_symbols,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def set_rubin_plotstyle() -> None:
|
|
37
|
+
"""
|
|
38
|
+
Set the matplotlib style for Rubin publications
|
|
39
|
+
"""
|
|
40
|
+
from matplotlib import style
|
|
41
|
+
|
|
42
|
+
style.use("lsst.utils.plotting.rubin")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def mk_colormap(colorNames): # type: ignore
|
|
46
|
+
"""Make a colormap from the list of color names.
|
|
47
|
+
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
colorNames : `list`
|
|
51
|
+
A list of strings that correspond to matplotlib named colors.
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
cmap : `matplotlib.colors.LinearSegmentedColormap`
|
|
56
|
+
A colormap stepping through the supplied list of names.
|
|
57
|
+
"""
|
|
58
|
+
from matplotlib import colors
|
|
59
|
+
|
|
60
|
+
blues = []
|
|
61
|
+
greens = []
|
|
62
|
+
reds = []
|
|
63
|
+
alphas = []
|
|
64
|
+
|
|
65
|
+
if len(colorNames) == 1:
|
|
66
|
+
# Alpha is between 0 and 1 really but
|
|
67
|
+
# using 1.5 saturates out the top of the
|
|
68
|
+
# colorscale, this looks good for ComCam data
|
|
69
|
+
# but might want to be changed in the future.
|
|
70
|
+
alphaRange = [0.2, 1.0]
|
|
71
|
+
nums = np.linspace(0, 1, len(alphaRange))
|
|
72
|
+
r, g, b = colors.colorConverter.to_rgb(colorNames[0])
|
|
73
|
+
for num, alpha in zip(nums, alphaRange):
|
|
74
|
+
blues.append((num, b, b))
|
|
75
|
+
greens.append((num, g, g))
|
|
76
|
+
reds.append((num, r, r))
|
|
77
|
+
alphas.append((num, alpha, alpha))
|
|
78
|
+
|
|
79
|
+
else:
|
|
80
|
+
nums = np.linspace(0, 1, len(colorNames))
|
|
81
|
+
if len(colorNames) == 3:
|
|
82
|
+
alphaRange = [1.0, 1.0, 1.0]
|
|
83
|
+
elif len(colorNames) == 5:
|
|
84
|
+
alphaRange = [1.0, 0.7, 0.3, 0.7, 1.0]
|
|
85
|
+
else:
|
|
86
|
+
alphaRange = np.ones(len(colorNames))
|
|
87
|
+
|
|
88
|
+
for num, color, alpha in zip(nums, colorNames, alphaRange):
|
|
89
|
+
r, g, b = colors.colorConverter.to_rgb(color)
|
|
90
|
+
blues.append((num, b, b))
|
|
91
|
+
greens.append((num, g, g))
|
|
92
|
+
reds.append((num, r, r))
|
|
93
|
+
alphas.append((num, alpha, alpha))
|
|
94
|
+
|
|
95
|
+
colorDict = {"blue": blues, "red": reds, "green": greens, "alpha": alphas}
|
|
96
|
+
cmap = colors.LinearSegmentedColormap("newCmap", colorDict)
|
|
97
|
+
return cmap
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def divergent_cmap(): # type: ignore
|
|
101
|
+
"""
|
|
102
|
+
Make a divergent color map.
|
|
103
|
+
"""
|
|
104
|
+
cmap = mk_colormap([stars_color(), "#D9DCDE", accent_color()])
|
|
105
|
+
|
|
106
|
+
return cmap
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def stars_cmap(single_color=False): # type: ignore
|
|
110
|
+
"""Make a color map for stars."""
|
|
111
|
+
import seaborn as sns
|
|
112
|
+
from matplotlib.colors import ListedColormap
|
|
113
|
+
|
|
114
|
+
if single_color:
|
|
115
|
+
cmap = mk_colormap([stars_color()])
|
|
116
|
+
else:
|
|
117
|
+
cmap = ListedColormap(sns.color_palette("mako", 256))
|
|
118
|
+
return cmap
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def stars_color() -> str:
|
|
122
|
+
"""Return the star color string for lines"""
|
|
123
|
+
return "#084d96"
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def accent_color() -> str:
|
|
127
|
+
"""Return a contrasting color for overplotting,
|
|
128
|
+
black is the best for this but if you need two colors
|
|
129
|
+
this works well on blue.
|
|
130
|
+
"""
|
|
131
|
+
return "#DE8F05"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def galaxies_cmap(single_color=False): # type: ignore
|
|
135
|
+
"""Make a color map for galaxies."""
|
|
136
|
+
if single_color:
|
|
137
|
+
cmap = mk_colormap([galaxies_color()])
|
|
138
|
+
else:
|
|
139
|
+
cmap = "inferno"
|
|
140
|
+
return cmap
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def galaxies_color() -> str:
|
|
144
|
+
"""Return the galaxy color string for lines"""
|
|
145
|
+
return "#961A45"
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def sso_color() -> str:
|
|
149
|
+
"""Return the SSO color string for lines"""
|
|
150
|
+
return "#01694c"
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def sso_cmap(single_color=False): # type: ignore
|
|
154
|
+
"""Make a color map for solar system objects."""
|
|
155
|
+
if single_color:
|
|
156
|
+
cmap = mk_colormap([sso_color()])
|
|
157
|
+
else:
|
|
158
|
+
cmap = "viridis"
|
|
159
|
+
return cmap
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def get_band_dicts() -> dict:
|
|
163
|
+
"""
|
|
164
|
+
Define palettes, from RTN-045. This includes dicts for colors (bandpass
|
|
165
|
+
colors for white background), colors_black (bandpass colors for
|
|
166
|
+
black background), plot symbols, and line_styles, keyed on band (ugrizy).
|
|
167
|
+
|
|
168
|
+
Returns
|
|
169
|
+
-------
|
|
170
|
+
band_dict : `dict` of `dict`
|
|
171
|
+
Dicts of colors, colors_black, symbols, and line_styles,
|
|
172
|
+
keyed on bands 'u', 'g', 'r', 'i', 'z', and 'y'.
|
|
173
|
+
"""
|
|
174
|
+
colors = get_multiband_plot_colors()
|
|
175
|
+
colors_black = get_multiband_plot_colors(dark_background=True)
|
|
176
|
+
symbols = get_multiband_plot_symbols()
|
|
177
|
+
line_styles = get_multiband_plot_linestyles()
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
"colors": colors,
|
|
181
|
+
"colors_black": colors_black,
|
|
182
|
+
"symbols": symbols,
|
|
183
|
+
"line_styles": line_styles,
|
|
184
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
axes.labelweight: normal
|
|
2
|
+
figure.titleweight : normal
|
|
3
|
+
axes.labelsize : large
|
|
4
|
+
axes.linewidth: 1
|
|
5
|
+
axes.titleweight: normal
|
|
6
|
+
axes.titlesize : small
|
|
7
|
+
figure.titlesize: small
|
|
8
|
+
errorbar.capsize: 3.0
|
|
9
|
+
|
|
10
|
+
lines.linewidth : 2
|
|
11
|
+
lines.markersize : 10
|
|
12
|
+
|
|
13
|
+
xtick.labelsize : small
|
|
14
|
+
ytick.labelsize : small
|
|
15
|
+
|
|
16
|
+
figure.dpi : 300.0
|
|
17
|
+
figure.facecolor: White
|
|
18
|
+
figure.figsize : 6.4, 4.8
|
|
19
|
+
|
|
20
|
+
# From seaborn-v0_8-colorblind colormap: https://seaborn.pydata.org/tutorial/color_palettes.html
|
|
21
|
+
axes.prop_cycle: cycler('color', ['0173B2', 'DE8F05', '029E73', 'D55E00', 'CC78BC', 'CA9161', 'FBAFE4', '949494', 'ECE133', '56B4E9'])
|
|
22
|
+
patch.facecolor: 006BA4
|
|
23
|
+
|
|
24
|
+
font.size : 14
|
|
25
|
+
legend.fontsize: x-small
|
|
26
|
+
|
|
27
|
+
xtick.major.width: 1.0
|
|
28
|
+
xtick.minor.width: 0.5
|
|
29
|
+
xtick.major.size: 7
|
|
30
|
+
xtick.minor.size: 4
|
|
31
|
+
xtick.minor.visible: True
|
|
32
|
+
xtick.direction: in
|
|
33
|
+
xtick.top: True
|
|
34
|
+
xtick.bottom: True
|
|
35
|
+
ytick.major.width: 1.0
|
|
36
|
+
ytick.minor.width: 0.5
|
|
37
|
+
ytick.major.size: 7
|
|
38
|
+
ytick.minor.size: 4
|
|
39
|
+
ytick.minor.visible: True
|
|
40
|
+
ytick.direction: in
|
|
41
|
+
ytick.left: True
|
|
42
|
+
ytick.right: True
|
|
43
|
+
xtick.major.pad : 6
|
|
44
|
+
xtick.minor.pad : 6
|
|
45
|
+
ytick.major.pad : 6
|
|
46
|
+
ytick.minor.pad : 6
|