lsst-utils 29.2025.1600__py3-none-any.whl → 29.2025.1800__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.
@@ -11,10 +11,19 @@
11
11
  """Utilities for making publication-quality figures."""
12
12
 
13
13
  __all__ = [
14
+ "accent_color",
15
+ "divergent_cmap",
16
+ "galaxies_cmap",
17
+ "galaxies_color",
14
18
  "get_band_dicts",
19
+ "mk_colormap",
15
20
  "set_rubin_plotstyle",
21
+ "stars_cmap",
22
+ "stars_color",
16
23
  ]
17
24
 
25
+ import numpy as np
26
+
18
27
  from . import (
19
28
  get_multiband_plot_colors,
20
29
  get_multiband_plot_linestyles,
@@ -31,6 +40,112 @@ def set_rubin_plotstyle() -> None:
31
40
  style.use("lsst.utils.plotting.rubin")
32
41
 
33
42
 
43
+ def mk_colormap(colorNames): # type: ignore
44
+ """Make a colormap from the list of color names.
45
+
46
+ Parameters
47
+ ----------
48
+ colorNames : `list`
49
+ A list of strings that correspond to matplotlib named colors.
50
+
51
+ Returns
52
+ -------
53
+ cmap : `matplotlib.colors.LinearSegmentedColormap`
54
+ A colormap stepping through the supplied list of names.
55
+ """
56
+ from matplotlib import colors
57
+
58
+ blues = []
59
+ greens = []
60
+ reds = []
61
+ alphas = []
62
+
63
+ if len(colorNames) == 1:
64
+ # Alpha is between 0 and 1 really but
65
+ # using 1.5 saturates out the top of the
66
+ # colorscale, this looks good for ComCam data
67
+ # but might want to be changed in the future.
68
+ alphaRange = [0.2, 1.0]
69
+ nums = np.linspace(0, 1, len(alphaRange))
70
+ r, g, b = colors.colorConverter.to_rgb(colorNames[0])
71
+ for num, alpha in zip(nums, alphaRange):
72
+ blues.append((num, b, b))
73
+ greens.append((num, g, g))
74
+ reds.append((num, r, r))
75
+ alphas.append((num, alpha, alpha))
76
+
77
+ else:
78
+ nums = np.linspace(0, 1, len(colorNames))
79
+ if len(colorNames) == 3:
80
+ alphaRange = [1.0, 0.3, 1.0]
81
+ elif len(colorNames) == 5:
82
+ alphaRange = [1.0, 0.7, 0.3, 0.7, 1.0]
83
+ else:
84
+ alphaRange = np.ones(len(colorNames))
85
+
86
+ for num, color, alpha in zip(nums, colorNames, alphaRange):
87
+ r, g, b = colors.colorConverter.to_rgb(color)
88
+ blues.append((num, b, b))
89
+ greens.append((num, g, g))
90
+ reds.append((num, r, r))
91
+ alphas.append((num, alpha, alpha))
92
+
93
+ colorDict = {"blue": blues, "red": reds, "green": greens, "alpha": alphas}
94
+ cmap = colors.LinearSegmentedColormap("newCmap", colorDict)
95
+ return cmap
96
+
97
+
98
+ def divergent_cmap(): # type: ignore
99
+ """
100
+ Make a divergent color map.
101
+ """
102
+ import seaborn as sns
103
+ from matplotlib.colors import ListedColormap
104
+
105
+ cmap = ListedColormap(sns.color_palette("icefire", 256))
106
+
107
+ return cmap
108
+
109
+
110
+ def stars_cmap(single_color=False): # type: ignore
111
+ """Make a color map for stars."""
112
+ import seaborn as sns
113
+ from matplotlib.colors import ListedColormap
114
+
115
+ if single_color:
116
+ cmap = mk_colormap([stars_color()])
117
+ else:
118
+ cmap = ListedColormap(sns.color_palette("mako", 256))
119
+ return cmap
120
+
121
+
122
+ def stars_color() -> str:
123
+ """Return the star color string for lines"""
124
+ return "#357BA3"
125
+
126
+
127
+ def accent_color() -> str:
128
+ """Return a contrasting color for overplotting,
129
+ black is the best for this but if you need two colors
130
+ this works well on blue.
131
+ """
132
+ return "#DE8F05"
133
+
134
+
135
+ def galaxies_cmap(single_color=False): # type: ignore
136
+ """Make a color map for galaxies."""
137
+ if single_color:
138
+ cmap = mk_colormap([galaxies_color()])
139
+ else:
140
+ cmap = "inferno"
141
+ return cmap
142
+
143
+
144
+ def galaxies_color() -> str:
145
+ """Return the galaxy color string for lines"""
146
+ return "#961A45"
147
+
148
+
34
149
  def get_band_dicts() -> dict:
35
150
  """
36
151
  Define palettes, from RTN-045. This includes dicts for colors (bandpass
@@ -1,19 +1,19 @@
1
1
  axes.labelweight: normal
2
2
  figure.titleweight : normal
3
3
  axes.labelsize : large
4
- axes.linewidth: 2
4
+ axes.linewidth: 1
5
5
  axes.titleweight: normal
6
6
  axes.titlesize : small
7
7
  figure.titlesize: small
8
8
  errorbar.capsize: 3.0
9
9
 
10
- lines.linewidth : 3
10
+ lines.linewidth : 2
11
11
  lines.markersize : 10
12
12
 
13
- xtick.labelsize : large
14
- ytick.labelsize : large
13
+ xtick.labelsize : small
14
+ ytick.labelsize : small
15
15
 
16
- figure.dpi : 150.0
16
+ figure.dpi : 300.0
17
17
  figure.facecolor: White
18
18
  figure.figsize : 6.4, 4.8
19
19
 
@@ -24,16 +24,16 @@ patch.facecolor: 006BA4
24
24
  font.size : 14
25
25
  legend.fontsize: x-small
26
26
 
27
- xtick.major.width: 2.0
28
- xtick.minor.width: 1.5
27
+ xtick.major.width: 1.0
28
+ xtick.minor.width: 0.5
29
29
  xtick.major.size: 7
30
30
  xtick.minor.size: 4
31
31
  xtick.minor.visible: True
32
32
  xtick.direction: in
33
33
  xtick.top: True
34
34
  xtick.bottom: True
35
- ytick.major.width: 2.0
36
- ytick.minor.width: 1.5
35
+ ytick.major.width: 1.0
36
+ ytick.minor.width: 0.5
37
37
  ytick.major.size: 7
38
38
  ytick.minor.size: 4
39
39
  ytick.minor.visible: True
lsst/utils/timer.py CHANGED
@@ -16,6 +16,7 @@ from __future__ import annotations
16
16
 
17
17
  __all__ = ["duration_from_timeMethod", "logInfo", "profile", "timeMethod", "time_this"]
18
18
 
19
+ import dataclasses
19
20
  import datetime
20
21
  import functools
21
22
  import logging
@@ -338,6 +339,18 @@ def timeMethod(
338
339
  return decorator_timer(_func)
339
340
 
340
341
 
342
+ @dataclasses.dataclass
343
+ class _TimerResult:
344
+ duration: float = 0.0
345
+ """Duration of context in seconds."""
346
+ mem_current_usage: float | None = None
347
+ """Memory usage at end of context in requested units."""
348
+ mem_peak_delta: float | None = None
349
+ """Peak differential between entering and leaving context."""
350
+ mem_current_delta: float | None = None
351
+ """Difference in usage between entering and leaving context."""
352
+
353
+
341
354
  @contextmanager
342
355
  def time_this(
343
356
  log: LsstLoggers | None = None,
@@ -349,7 +362,8 @@ def time_this(
349
362
  mem_child: bool = False,
350
363
  mem_unit: u.Quantity = u.byte,
351
364
  mem_fmt: str = ".0f",
352
- ) -> Iterator[None]:
365
+ force_mem_usage: bool = False,
366
+ ) -> Iterator[_TimerResult]:
353
367
  """Time the enclosed block and issue a log message.
354
368
 
355
369
  Parameters
@@ -372,7 +386,8 @@ def time_this(
372
386
  written to ``msg``.
373
387
  mem_usage : `bool`, optional
374
388
  Flag indicating whether to include the memory usage in the report.
375
- Defaults, to False.
389
+ Defaults, to False. Does nothing if the log message will not be
390
+ generated.
376
391
  mem_child : `bool`, optional
377
392
  Flag indication whether to include memory usage of the child processes.
378
393
  mem_unit : `astropy.units.Unit`, optional
@@ -380,6 +395,16 @@ def time_this(
380
395
  mem_fmt : `str`, optional
381
396
  Format specifier to use when displaying values related to memory usage.
382
397
  Defaults to '.0f'.
398
+ force_mem_usage : `bool`, optional
399
+ If `True` memory usage is always calculated even if the log message
400
+ will not be delivered. Use this if you want the information recorded
401
+ by the context manager.
402
+
403
+ Yields
404
+ ------
405
+ timer_result : `_TimerResult`
406
+ Simple data class containing the duration of the block in seconds via
407
+ the ``duration`` property.
383
408
  """
384
409
  if log is None:
385
410
  log = logging.getLogger()
@@ -391,14 +416,17 @@ def time_this(
391
416
 
392
417
  if mem_usage and not log.isEnabledFor(level):
393
418
  mem_usage = False
419
+ if force_mem_usage:
420
+ mem_usage = True
394
421
 
395
422
  if mem_usage:
396
423
  current_usages_start = get_current_mem_usage()
397
424
  peak_usages_start = get_peak_mem_usage()
398
425
 
426
+ timer_result = _TimerResult()
399
427
  errmsg = ""
400
428
  try:
401
- yield
429
+ yield timer_result
402
430
  except BaseException as e:
403
431
  frame, lineno = list(traceback.walk_tb(e.__traceback__))[-1]
404
432
  errmsg = f"{e!r} @ {frame.f_code.co_filename}:{lineno}"
@@ -416,9 +444,12 @@ def time_this(
416
444
  # mypy stop complaining when additional parameters will be added below.
417
445
  params = list(args) if args else []
418
446
 
447
+ duration = end - start
448
+ timer_result.duration = duration
449
+
419
450
  # Specify stacklevel to ensure the message is reported from the
420
451
  # caller (1 is this file, 2 is contextlib, 3 is user)
421
- params += (": " if msg else "", end - start)
452
+ params += (": " if msg else "", duration)
422
453
  msg += "%sTook %.4f seconds"
423
454
  if errmsg:
424
455
  params += (f" (timed code triggered exception of {errmsg!r})",)
@@ -442,10 +473,18 @@ def time_this(
442
473
  _LOG.warning("Invalid memory unit '%s', using '%s' instead", mem_unit, u.byte)
443
474
  mem_unit = u.byte
444
475
 
476
+ current_usage = current_usage.to(mem_unit)
477
+ current_delta = current_delta.to(mem_unit)
478
+ peak_delta = peak_delta.to(mem_unit)
479
+
480
+ timer_result.mem_current_usage = float(current_usage.value)
481
+ timer_result.mem_current_delta = float(current_delta.value)
482
+ timer_result.mem_peak_delta = float(peak_delta.value)
483
+
445
484
  msg += (
446
- f"; current memory usage: {current_usage.to(mem_unit):{mem_fmt}}"
447
- f", delta: {current_delta.to(mem_unit):{mem_fmt}}"
448
- f", peak delta: {peak_delta.to(mem_unit):{mem_fmt}}"
485
+ f"; current memory usage: {current_usage:{mem_fmt}}"
486
+ f", delta: {current_delta:{mem_fmt}}"
487
+ f", peak delta: {peak_delta:{mem_fmt}}"
449
488
  )
450
489
  log.log(level, msg, *params, stacklevel=3)
451
490
 
lsst/utils/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  __all__ = ["__version__"]
2
- __version__ = "29.2025.1600"
2
+ __version__ = "29.2025.1800"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lsst-utils
3
- Version: 29.2025.1600
3
+ Version: 29.2025.1800
4
4
  Summary: Utility functions from Rubin Observatory Data Management for the Legacy Survey of Space and Time (LSST).
5
5
  Author-email: Rubin Observatory Data Management <dm-admin@lists.lsst.org>
6
6
  License: BSD 3-Clause License
@@ -27,6 +27,7 @@ Provides-Extra: test
27
27
  Requires-Dist: pytest>=3.2; extra == "test"
28
28
  Provides-Extra: plotting
29
29
  Requires-Dist: matplotlib; extra == "plotting"
30
+ Requires-Dist: seaborn; extra == "plotting"
30
31
  Dynamic: license-file
31
32
 
32
33
  ==========
@@ -14,19 +14,19 @@ lsst/utils/packages.py,sha256=D2eD2Qy3P_Os7RbUKsG2mPyLoSLjqejUX6lNhaC16wg,27455
14
14
  lsst/utils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  lsst/utils/tests.py,sha256=1cjyXtEL2LNhnPKjtiTt9cdPmlaEWgaWBx9BfM-xSmA,39152
16
16
  lsst/utils/threads.py,sha256=WNl3uvbE7bx5UyxTX0fwN5AkU3Yty_m8y_pMKcMCdv8,2551
17
- lsst/utils/timer.py,sha256=i7MCe6AeGPuHi4SReELJK5fQER-tHOA-1PreQoo83X4,18472
17
+ lsst/utils/timer.py,sha256=Vt5yTuyGL-EAQ9ZE9rtzYLNRQDQ3njN97J5_kZn9Kh4,19923
18
18
  lsst/utils/usage.py,sha256=qunydx-KlcbNp-vFcBtvBayWwZAa0tHtSWvz5BycvLA,4598
19
- lsst/utils/version.py,sha256=DWDCyavYRMZByGPGMYcnpz6piNv1sQvCKH8yohX_F3c,55
19
+ lsst/utils/version.py,sha256=uRdffTNnwH4GQy77H1Wk3Md64craDCIuRxmCtF7ON0g,55
20
20
  lsst/utils/wrappers.py,sha256=KCvsrGXziLQ5pC8ytiFEXeDH9mBSo8eCZ8g08f7s404,19209
21
21
  lsst/utils/plotting/__init__.py,sha256=OEAZv2W12UAcUfDxH5H_k8v7cK4fVTOssuqNksZTuIs,507
22
22
  lsst/utils/plotting/figures.py,sha256=dPJfP0W-GkRhv6bEiPzH7kLV0a4MIrtavmLbGv7Wt9E,4167
23
23
  lsst/utils/plotting/limits.py,sha256=6ilPmb4wg4aVtjlBgm75FPBrjDVSkW_ywZrj_QIQD2U,5839
24
- lsst/utils/plotting/publication_plots.py,sha256=rWHxe4PL3R0UpacmlJ8NCLLDgbUZyxXCd08ru6OFLs8,1607
25
- lsst/utils/plotting/rubin.mplstyle,sha256=S1h7MX5KeMIrEWuOO6e_jF27AOYJ5hZ1hjCKQkwgHLg,1084
26
- lsst_utils-29.2025.1600.dist-info/licenses/COPYRIGHT,sha256=I6Bxnp_LkIqDjafZNIXM8jfjYWC4XIlpNpZ7jkdeZK0,361
27
- lsst_utils-29.2025.1600.dist-info/licenses/LICENSE,sha256=7wrtgl8meQ0_RIuv2TjIKpAnNrl-ODH-QLwyHe9citI,1516
28
- lsst_utils-29.2025.1600.dist-info/METADATA,sha256=tnbheK_glDssJ1IJenGFOUrivTujMIBsMahLI5RuBgE,1647
29
- lsst_utils-29.2025.1600.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
30
- lsst_utils-29.2025.1600.dist-info/top_level.txt,sha256=eUWiOuVVm9wwTrnAgiJT6tp6HQHXxIhj2QSZ7NYZH80,5
31
- lsst_utils-29.2025.1600.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
32
- lsst_utils-29.2025.1600.dist-info/RECORD,,
24
+ lsst/utils/plotting/publication_plots.py,sha256=nwttKC3818okJFZrquuRDDsnOys3WflGGZOmpZ0hcLI,4739
25
+ lsst/utils/plotting/rubin.mplstyle,sha256=SaonqdWUIOT8Z4f5oplS21Z6wmYVjuCs--PyJnjS8us,1084
26
+ lsst_utils-29.2025.1800.dist-info/licenses/COPYRIGHT,sha256=I6Bxnp_LkIqDjafZNIXM8jfjYWC4XIlpNpZ7jkdeZK0,361
27
+ lsst_utils-29.2025.1800.dist-info/licenses/LICENSE,sha256=7wrtgl8meQ0_RIuv2TjIKpAnNrl-ODH-QLwyHe9citI,1516
28
+ lsst_utils-29.2025.1800.dist-info/METADATA,sha256=H1gzLTw26UaqY44PoK_q9fqe7bX1hOYQNTpN-5omHuw,1691
29
+ lsst_utils-29.2025.1800.dist-info/WHEEL,sha256=wXxTzcEDnjrTwFYjLPcsW_7_XihufBwmpiBeiXNBGEA,91
30
+ lsst_utils-29.2025.1800.dist-info/top_level.txt,sha256=eUWiOuVVm9wwTrnAgiJT6tp6HQHXxIhj2QSZ7NYZH80,5
31
+ lsst_utils-29.2025.1800.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
32
+ lsst_utils-29.2025.1800.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.0)
2
+ Generator: setuptools (80.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5