# -*- coding: utf-8 -*-
"""Plotting Functions.
.. todo
- these would be better done in plotly
"""
__author__ = ["Nathaniel Starkman", "Jagjit Sidhu", "Inherited Code People"]
__maintainer__ = "Nathaniel Starkman"
__all__ = [
# density lines
"plot_atomic_density_line",
"plot_nuclear_density_line",
"plot_black_hole_line",
"plot_reference_densities",
# constraints
"plot_mica_constraints",
"plot_white_dwarf_constraints",
"plot_cmb_constraints",
"plot_superbursts_constraints",
"plot_humandeath_constraints",
"plot_dfn_constraints",
"plot_lensing_constraints",
"plot_black_hole_constraints",
# contextmanager
"constraints_plot",
]
##############################################################################
# IMPORTS
# BUILT-IN
# BUILT-IN
import typing as T
from contextlib import contextmanager
# THIRD PARTY
import numpy as np
from matplotlib import pyplot
# PROJECT-SPECIFIC
from . import data
from .physics import CMB, LMCTop, atomic_density, black_hole, nuclear_density
##############################################################################
# PARAMETERS
##############################################################################
# CODE
##############################################################################
#####################################################################
# Reference Densities
[docs]def plot_atomic_density_line(mass: T.Sequence, label: bool = True):
r"""Plot Atomic Density Line.
Parameters
----------
mass : Sequence
used in atomic_density(mass)
Returns
-------
:class:`~matplotlib.lines.Line2D`
Other Parameters
----------------
label : bool
Whether to add the label :math:`\rho_{atomic}`
Notes
-----
Plot properties:
- color : black
- markersize : 4
- linewidth : 1
See Also
--------
:func:`~macro_lightning.plot.plot_reference_densities`
"""
line = pyplot.loglog(
mass,
atomic_density(mass),
"k",
markersize=4,
color="k",
lw=1,
label=r"$\rho_{atomic}$" if label else None,
zorder=0,
)
return line[0]
# /def
# -------------------------------------------------------------------
[docs]def plot_nuclear_density_line(mass: T.Sequence, label: bool = True):
r"""Plot Nuclear Density Line.
Parameters
----------
mass : Sequence
Used in atomic_density(mass)
Returns
-------
`~matplotlib.lines.Line2D`
Other Parameters
----------------
label : bool
whether to add the label :math:`\rho_{nuclear}`
Notes
-----
Plot properties:
- color : green
- markersize : 4
- linewidth : 2
See Also
--------
:func:`~macro_lightning.plot.plot_reference_densities`
"""
line = pyplot.loglog(
mass,
nuclear_density(mass),
markersize=4,
color="g",
lw=2,
label=r"$\rho_{nuclear}$" if label else None,
zorder=0,
)
return line[0]
# /def
# -------------------------------------------------------------------
[docs]def plot_black_hole_line(mass: T.Sequence, label: bool = True):
r"""Plot Black Hole Density Line.
Parameters
----------
mass : Sequence
Used in atomic_density(mass)
Returns
-------
`~matplotlib.lines.Line2D`
Other Parameters
----------------
label : bool
Whether to add the label :math:`\rho_{BH}`
Notes
-----
Plot properties:
- color : black
- markersize : 4
- linewidth : 3
See Also
--------
:func:`~macro_lightning.plot.plot_reference_densities`
"""
line = pyplot.loglog(
mass,
black_hole(mass),
markersize=4,
color="k",
lw=3,
label=r"$\rho_{BH}$" if label else None,
zorder=3,
)
return line[0]
# /def
# -------------------------------------------------------------------
[docs]def plot_reference_densities(mass: T.Sequence, label: bool = True):
"""Plot Reference Density lines / constraints.
- atomic density line
- nuclear density line
- black hole density line
.. |Line2D| replace:: :class:`~matplotlib.lines.Line2D`
Parameters
----------
mass : Sequence
Used in atomic_density(mass)
Returns
-------
atom_line : |Line2D|
see `plot_atomic_density_line`
nuc_line : |Line2D|
see `plot_nuclear_density_line`
bh_line : |Line2D|
see `plot_black_hole_line`
Other Parameters
----------------
label : bool
whether to add the labels to the lines.
See Also
--------
:func:`~macro_lightning.plot.plot_atomic_density_line`
:func:`~macro_lightning.plot.plot_nuclear_density_line`
:func:`~macro_lightning.plot.plot_black_hole_line`
"""
atom_line = plot_atomic_density_line(mass, label=label)
nuc_line = plot_nuclear_density_line(mass, label=label)
bh_line = plot_black_hole_line(mass, label=label)
return atom_line, nuc_line, bh_line
# /def
#####################################################################
[docs]def plot_mica_constraints(
points: T.Optional[T.Sequence] = None,
label: bool = False,
):
r"""Plot Constraints from Mica.
A longstanding constraint comes from examination of a slab of
ancient mica for tracks that would have been left by the passage of
a macro moving at the typical speed of dark matter in the Galaxy.
This was used to rule out macros of :math:`M_x \leq 55\,` g for a wide
range of cross sections [1]_, [2]_, [3]_
Parameters
----------
points : `~numpy.ndarray`, optional
N x 2 array for a `~matplotlib.patches.Polygon`
if None (default) will load from
:func:`~macro_lightning.data.load_mica_constraints`
Returns
-------
:class:`~matplotlib.patches.Polygon`
Other Parameters
----------------
label : bool
whether to add the label 'Mica'
Notes
-----
plot properties:
- facecolor: yellow
- edgecolor: black
- hatched: |
- linewidth: 1
- alpha: 0.8
References
----------
.. [1] Price, P. (1988). Limits on Contribution of Cosmic Nuclearites
to Galactic Dark MatterPhysical Review D, 38, 3813-3814.
.. [2] De Rujula, A., & Glashow, S. (1984).
Nuclearites: A Novel Form of Cosmic RadiationNature, 312, 734-737.
.. [3] David M. Jacobs, Glenn D. Starkman, & Bryan W. Lynn (2014).
Macro Dark MatterMNRAS.
See Also
--------
:func:`~macro_lightning.plot.constraints_plot`
"""
if points is None:
points = data.load_mica_constraints()
mica_poly = pyplot.Polygon(
points,
closed=None,
fill=True,
facecolor="yellow",
edgecolor="black",
alpha=0.8,
hatch="|",
lw=1,
zorder=0,
label="Mica" if label else None,
)
pyplot.gca().add_patch(mica_poly)
return mica_poly
# /def
# -------------------------------------------------------------------
[docs]def plot_white_dwarf_constraints(
points: T.Optional[T.Sequence] = None,
label=False,
):
r"""Plot Constraints from the existence of massive White Dwarfs.
For sufficiently large cross-sections, the linear energy deposition could
produce observable signals if a macro were to pass through compact objects
such as white dwarfs in the form of thermonuclear runaway leading to a
type IA supernova. These are weaker than previously inferred [2]_ in
important respects because of more careful treatment of the passage of a
macro through the white dwarf and greater conservatism regarding the size
of the region that must be heated to initiate runaway. On the other hand,
more stringent constraints are placed on macros at low cross-section,
using new data from the Montreal White Dwarf Database [1]_.
Parameters
----------
points : `~numpy.ndarray`, optional
N x 2 array for a :class:`~matplotlib.patches.Polygon`
if None (default) will load from :mod:`~macro_lightning.data`
Returns
-------
:class:`~matplotlib.patches.Polygon`
Other Parameters
----------------
label : bool
whether to add the label 'WD'
Notes
-----
plot properties:
- facecolor: blue
- edgecolor: black
- linewidth: 1
- alpha: 0.6
References
----------
.. [1] J. S. Sidhu and G. D. Starkman, Physical Review D 101 (2020),
0.1103/physrevd.101.083503.
.. [2] P. Graham, R. Janish, V. Narayan, S. Rajendran, and P. Riggins,
Physical Review D 98, 115027 (2018).
See Also
--------
:func:`~macro_lightning.plot.constraints_plot`
"""
if points is None:
points = data.load_whitedwarf_constraints()
wd_poly = pyplot.Polygon(
points,
closed=None,
fill=True,
facecolor="blue",
edgecolor="black",
alpha=0.6,
hatch="",
lw=1,
zorder=2,
label="WD" if label else None,
)
pyplot.gca().add_patch(wd_poly)
return wd_poly
# /def
# -------------------------------------------------------------------
[docs]def plot_superbursts_constraints(
points1: T.Optional[T.Sequence] = None,
points2: T.Optional[T.Sequence] = None,
label=False,
):
r"""Plot Constraints from Superbursts in Neutron Stars.
For sufficiently large cross-sections, the linear energy deposition could
produce observable signals if a macro were to pass through compact objects
such as neutron stars in the form of thermonuclear runaway, leading to a
superburst. New constraints are inferred from the low mass X-ray
binary 4U 1820-30, in which more than a decade passed between successive
superbursts [1]_.
.. |Polygon| replace:: :class:`~matplotlib.patches.Polygon`
Parameters
----------
points1 : `~numpy.ndarray`, optional
N x 2 array for a |Polygon|
if None (default) will load from
:func:`~macro_lightning.data.load_superbursts_polygons`
points2 : `~numpy.ndarray`, optional
N x 2 array for a |Polygon|
if None (default) will load from
:func:`~macro_lightning.data.load_superbursts_polygons`
Returns
-------
superbursts1_poly : |Polygon|
superbursts2_poly : |Polygon|
Other Parameters
----------------
label : bool
whether to add the label 'superbursts(1/2)'
Notes
-----
plot properties:
- facecolor: purple
- edgecolor: black
- alpha: 0.6
References
----------
.. [1] J. S. Sidhu and G. D. Starkman, Physical Review D 101 (2020),
0.1103/physrevd.101.083503.
See Also
--------
:func:`~macro_lightning.plot.constraints_plot`
"""
_points1, _points2 = data.load_superbursts_polygons()
points1 = points1 or _points1
points2 = points2 or _points2
superbursts1_poly = pyplot.Polygon(
points1,
closed=None,
fill=True,
facecolor="purple",
edgecolor="black",
alpha=0.6,
hatch="",
lw=1,
zorder=5,
label="superbursts(1/2)" if label else None,
)
pyplot.gca().add_patch(superbursts1_poly)
superbursts2_poly = pyplot.Polygon(
points2,
closed=None,
fill=True,
facecolor="purple",
edgecolor="black",
alpha=0.6,
hatch="//",
lw=1,
zorder=5,
)
pyplot.gca().add_patch(superbursts2_poly)
return superbursts1_poly, superbursts2_poly
# /def
# -------------------------------------------------------------------
[docs]def plot_cmb_constraints(
m_arr: T.Sequence,
sigmax: float,
label: bool = False,
):
r"""Plot Constraints from the CMB.
Wilkinson et al. [1] utilized the full Boltzmann formalism to
obtain constraints from macro-photon elastic scattering using the first
year release of Planck data.
Parameters
----------
m_arr : `~numpy.ndarray`
sigmax : float
maximum plotted sigma
Returns
-------
:class:`~matplotlib.collections.PolyCollection`
Other Parameters
----------------
label : bool
whether to add the label 'CMB'
Notes
-----
plot properties:
- facecolor: grey
- edgecolor: black
- alpha: 0.7
References
----------
.. [1] R. J. Wilkinson, J. Lesgourgues, and C. Bœhm,
Journal of Cosmology and Astroparticle Physics 2014, 026 (2014)
See Also
--------
:func:`~macro_lightning.plot.constraints_plot`
"""
cmb_fill = pyplot.fill_between(
m_arr,
CMB(m_arr),
sigmax,
where=None,
color="grey",
edgecolor="black",
hatch="",
alpha=0.7,
zorder=1,
label="CMB" if label else None,
)
return cmb_fill
# /def
# -------------------------------------------------------------------
[docs]def plot_humandeath_constraints(
human_mass: T.Optional[T.Sequence] = None,
human_xsec: T.Optional[T.Sequence] = None,
human_upper: T.Optional[T.Sequence] = None,
label=False,
):
r"""Plot Constraints from dark matter caused human deaths.
Macroscopic dark matter (macros) refers to a class of dark matter
candidates that scatter elastically off of ordinary matter with a large
geometric cross-section. A wide range of macro masses :math:`M_X` and
cross-sections :math:`\sigma_X` remain unprobed. Over a wide region within
the unexplored parameter space, collisions of a macro with a human body
would result in serious injury or death. The absence of such unexplained
impacts with a well-monitored subset of the human population to exclude a
region bounded by :math:`\sigma_X > 10^{−8} − 10^{−7}` cm2 and :math:`M_X
< 50` kg [1].
.. |ndarray| replace:: :class:`~numpy.ndarray`
Parameters
----------
human_mass : |ndarray|, optional
N x 1 array for a :class:`~matplotlib.pyplot.fill_between`
if None (default) will load from
:func:`~macro_lightning.data.load_humandeath_constraints`
human_xsec : |ndarray|, optional
N x 1 array for a `~fill_between`
if None (default) will load from
:func:`~macro_lightning.data.load_humandeath_constraints`
human_upper : |ndarray|, optional
N x 1 array for a `~fill_between`
if None (default) will load from
:func:`~macro_lightning.data.load_humandeath_constraints`
Returns
-------
:class:`~matplotlib.collections.PolyCollection`
Other Parameters
----------------
label : bool
whether to add the label 'death'
References
----------
.. [1] J. S. Sidhu, R. Scherrer, and G. Starkman,
Physics Let- ters B 803, 135300 (2020).
See Also
--------
:func:`~macro_lightning.plot.constraints_plot`
"""
_human_mass, _human_xsec, _human_upper = data.load_humandeath_constraints()
human_mass = human_mass or _human_mass
human_xsec = human_xsec or _human_xsec
human_upper = human_upper or _human_upper
human_fill = pyplot.fill_between(
human_mass,
human_xsec,
human_upper,
where=None,
facecolor="red",
edgecolor="black",
hatch="",
alpha=0.6,
zorder=4,
label="death" if label else None,
)
return human_fill
# /def
# -------------------------------------------------------------------
[docs]def plot_dfn_constraints(
dfn_mass: T.Optional[T.Sequence] = None,
dfn_xsec: T.Optional[T.Sequence] = None,
dfn_upper: T.Optional[T.Sequence] = None,
label=False,
):
r"""Plot Constraints from Desert Fireball Network (DFN).
Constraints for low mass macros from the null observation of bright
meteors formed by a passing macro, across two extensive networks of
cameras built originally to observe meteorites. The parameter space that
could be probed with planned upgrades to the existing array of cameras in
one of these networks still currently in use, the Desert Fireball Network
in Australia, is estimated [1]_.
.. |ndarray| replace:: :class:`~numpy.ndarray`
Parameters
----------
DFNmass : |ndarray|, optional
N x 1 array for a :class:`~matplotlib.pyplot.fill_between`
if None (default) will load from :mod:`~macro_lightning.data`
dfn_xsec : |ndarray|, optional
N x 1 array for a `~fill_between`
if None (default) will load from :mod:`~macro_lightning.data`
dfn_upper : |ndarray|, optional
N x 1 array for a `~fill_between`
if None (default) will load from :mod:`~macro_lightning.data`
Returns
-------
:class:`~matplotlib.collections.PolyCollection`
Other Parameters
----------------
label : bool
whether to add the label 'DFN'
References
----------
.. [1] J. S. Sidhu and G. Starkman, Physical Review D 100 (2019),
10.1103/physrevd.100.123008.
See Also
--------
:func:`~macro_lightning.plot.constraints_plot`
"""
_dfn_mass, _dfn_xsec, _dfn_upper = data.load_dfn_constraints()
dfn_mass = dfn_mass or _dfn_mass
dfn_xsec = dfn_xsec or _dfn_xsec
dfn_upper = dfn_upper or _dfn_upper
dfn_fill = pyplot.fill_between(
dfn_mass,
dfn_xsec,
dfn_upper,
where=None,
facecolor="green",
edgecolor="black",
hatch="",
alpha=0.6,
zorder=4,
label="DFN" if label else None,
)
return dfn_fill
# /def
# -------------------------------------------------------------------
[docs]def plot_lensing_constraints(
Mmicro: T.Optional[T.Sequence] = None,
label=False,
):
r"""Plot Constraints from microlensing of the LMC.
Parameters
----------
Mmicro : `~numpy.ndarray`, optional
N x 1 array for a :class:`~matplotlib.pyplot.fill_between`
if None (default) will ``np.logspace(23.0, 28.0)``
Returns
-------
:class:`~matplotlib.collections.PolyCollection`
Other Parameters
----------------
label : bool
whether to add the label "$\mu$-lens"
References
----------
.. [1] C. Alcock et al., The Astrophysical Journal 550, L169 (2001).
.. [2] K. Griest, A. M. Cieplak, and M. J. Lehner, Physical
Review Letters 111, 181302 (2013).
.. [3] P. Tisserand et al., Astronomy & Astrophysics 469, 387 (2007).
.. [4] B. J. Carr, K. Kohri, Y. Sendouda, and J. Yokoyama,
Physical Review D 81, 104019 (2010).
.. [5] H. Niikura et al., Nature Astronomy 3, 524 (2019)
See Also
--------
:func:`~macro_lightning.plot.constraints_plot`
"""
if Mmicro is None:
Mmicro = np.logspace(23.0, 28.0)
micro_fill = pyplot.fill_between(
Mmicro,
black_hole(Mmicro),
LMCTop(Mmicro),
where=None,
facecolor="brown",
edgecolor="black",
# hatch="/",
alpha=1,
zorder=2,
label=r"$\mu$-lens" if label else None,
)
return micro_fill
# /def
# -------------------------------------------------------------------
[docs]def plot_black_hole_constraints(
m_arr: T.Sequence,
sigmin: float,
label: bool = False,
):
r"""Plot Constraints from Black Holes.
Parameters
----------
m_arr : `~numpy.ndarray`, optional
N x 1 array for a :class:`~matplotlib.pyplot.fill_between`
sigmin : float
minimum plotted sigma
Returns
-------
:class:`~matplotlib.collections.PolyCollection`
Other Parameters
----------------
label : bool
whether to add the label "BH"
See Also
--------
:func:`~macro_lightning.plot.constraints_plot`
"""
bh_fill = pyplot.fill_between(
m_arr,
sigmin,
black_hole(m_arr),
where=None,
color="black",
hatch="+",
zorder=2,
label="BH" if label else None,
)
return bh_fill
# /def
#####################################################################
[docs]@contextmanager
def constraints_plot(
m_arr: T.Sequence,
sigmin: float = 1e-15,
sigmax: float = 1e25,
*,
savefig: T.Optional[str] = None,
constr_labels: bool = False,
all_constrs: bool = False,
# individual constraints
mica_constr: bool = False,
CMB_constr: bool = False,
WD_constr: bool = False,
superbursts_constr: bool = False,
humandeath_constr: bool = False,
dfn_constr: bool = False,
lensing_constr: bool = False,
bh_constr: bool = False,
):
"""Make standard constraint plot, with custom constraints in context.
Custom constraints are created in the `with` statement
Parameters
----------
m_arr : Sequence
Mass array
sigmin : float
Minimum plotted sigma
sigmax : float
Maximum plotted sigma
constr_labels : bool
Whether to add labels to all the `Other Parameters`
Yields
------
fig : :class:`~matplotlib.Figure`
ax : :class:`~matplotlib.Axes`
m_arr : Sequence
Mass array
sigmin : float
Minimum plotted sigma
sigmax : float
Maximum plotted sigma
Other Parameters
----------------
mica_constr: bool
Whether to label the mica constraints (default False)
References : [1]_, [2]_, [3]_
See :func:`~macro_lightning.plot.plot_mica_constraints`
CMB_constr: bool
Whether to label the CMB constraints (default False).
References : [5]_
See :func:`~macro_lightning.plot.plot_cmb_constraints`
WD_constr: bool
Whether to label the White Dwarf constraints (default False).
References : [4]_
See :func:`~macro_lightning.plot.plot_white_dwarf_constraints`
superbursts_constr: bool
Whether to label the superbursts constraints (default False).
References : [4]_
See :func:`~macro_lightning.plot.plot_superbursts_constraints`
humandeath_constr: bool
Whether to label the human-death constraints (default False).
References : [6]_
See :func:`~macro_lightning.plot.plot_humandeath_constraints`
dfn_constr: bool
Whether to label the DFN constraints (default False).
References : [7]_
See :func:`~macro_lightning.plot.plot_dfn_constraints`
lensing_constr: bool
Whether to label the micro-lensing constraints (default False).
References : [8]_, [9]_, [10]_, [11]_, [12]_
See :func:`~macro_lightning.plot.plot_lensing_constraints`
bh_constr: bool
Whether to label the black hole constraints (default False).
See :func:`~macro_lightning.plot.plot_black_hole_constraints`
Examples
--------
In this example we make an empty constraint plot.
>>> M = np.logspace(1, 25)
>>> with constraints_plot(M, sigmin=1e-15):
... pass
References
----------
.. [1] Price, P. (1988). Limits on Contribution of Cosmic Nuclearites
to Galactic Dark MatterPhysical Review D, 38, 3813-3814.
.. [2] De Rujula, A., & Glashow, S. (1984).
Nuclearites: A Novel Form of Cosmic RadiationNature, 312, 734-737.
.. [3] David M. Jacobs, Glenn D. Starkman, & Bryan W. Lynn (2014).
Macro Dark MatterMNRAS.
.. [4] R. J. Wilkinson, J. Lesgourgues, and C. Bœhm,
Journal of Cosmology and Astroparticle Physics 2014, 026 (2014)
.. [5] J. S. Sidhu and G. D. Starkman, Physical Review D 101 (2020),
0.1103/physrevd.101.083503.
.. [6] J. S. Sidhu, R. Scherrer, and G. Starkman,
Physics Letters B 803, 135300 (2020).
.. [7] J. S. Sidhu and G. Starkman, Physical Review D 100 (2019),
10.1103/physrevd.100.123008.
.. [8] C. Alcock et al., The Astrophysical Journal 550, L169 (2001).
.. [9] K. Griest, A. M. Cieplak, and M. J. Lehner, Physical
Review Letters 111, 181302 (2013).
.. [10] P. Tisserand et al., Astronomy & Astrophysics 469, 387 (2007).
.. [11] B. J. Carr, K. Kohri, Y. Sendouda, and J. Yokoyama,
Physical Review D 81, 104019 (2010).
.. [12] H. Niikura et al., Nature Astronomy 3, 524 (2019)
"""
fig, ax = pyplot.subplots(figsize=(8, 5.5))
ax.grid(True, alpha=0.7)
ax.set_xlabel(r"$M_{X}$ [g]", fontsize=18)
ax.set_xlim([m_arr.min(), m_arr.max()])
for tick in ax.xaxis.get_major_ticks():
tick.label.set_fontsize(14)
ax.set_ylim(sigmin, sigmax) # min/max of nuclear_density(M1)
ax.set_ylabel(r"$\sigma_{X}$ [cm$^{2}$]", fontsize=18)
for tick in ax.yaxis.get_major_ticks():
tick.label.set_fontsize(14)
plot_reference_densities(m_arr)
# previous constraints
if mica_constr or all_constrs:
plot_mica_constraints(label=constr_labels)
if WD_constr or all_constrs:
plot_white_dwarf_constraints(label=constr_labels)
if CMB_constr or all_constrs:
plot_cmb_constraints(m_arr, sigmax=sigmax, label=constr_labels)
if superbursts_constr or all_constrs:
plot_superbursts_constraints(label=constr_labels)
if humandeath_constr or all_constrs:
plot_humandeath_constraints(label=constr_labels)
if dfn_constr or all_constrs:
plot_dfn_constraints(label=constr_labels)
if lensing_constr or all_constrs:
plot_lensing_constraints(Mmicro=None, label=constr_labels)
if bh_constr or all_constrs:
plot_black_hole_constraints(m_arr, sigmin=sigmin, label=constr_labels)
try:
yield fig, ax, m_arr, sigmin, sigmax
finally:
ax.legend(loc="upper left", shadow=True, fontsize=12, ncol=2)
pyplot.tight_layout()
if savefig is not None:
fig.savefig(savefig)
# /def
##############################################################################
# END