Organize in submodules

This commit is contained in:
Noe Brucy
2022-10-07 11:20:04 +02:00
parent 1f3b0762c9
commit 0d90179292
32 changed files with 231 additions and 510 deletions
View File
+122
View File
@@ -0,0 +1,122 @@
"""
from https://gist.github.com/coroa/cdcdb1ec1c73d4f6588501e2f7f46c45
MIT License
"""
import numpy as np
from matplotlib.text import Annotation
from matplotlib.transforms import Affine2D
class LineAnnotation(Annotation):
"""A sloped annotation to *line* at position *x* with *text*
Optionally an arrow pointing from the text to the graph at *x* can be drawn.
Usage
-----
fig, ax = subplots()
x = linspace(0, 2*pi)
line, = ax.plot(x, sin(x))
ax.add_artist(LineAnnotation("text", line, 1.5))
"""
def __init__(
self, text, line, x, xytext=(0, 5), textcoords="offset points", **kwargs
):
"""Annotate the point at *x* of the graph *line* with text *text*.
By default, the text is displayed with the same rotation as the slope of the
graph at a relative position *xytext* above it (perpendicularly above).
An arrow pointing from the text to the annotated point *xy* can
be added by defining *arrowprops*.
Parameters
----------
text : str
The text of the annotation.
line : Line2D
Matplotlib line object to annotate
x : float
The point *x* to annotate. y is calculated from the points on the line.
xytext : (float, float), default: (0, 5)
The position *(x, y)* relative to the point *x* on the *line* to place the
text at. The coordinate system is determined by *textcoords*.
**kwargs
Additional keyword arguments are passed on to `Annotation`.
See also
--------
`Annotation`
`line_annotate`
"""
assert textcoords.startswith(
"offset "
), "*textcoords* must be 'offset points' or 'offset pixels'"
self.line = line
self.xytext = xytext
# Determine points of line immediately to the left and right of x
xs, ys = line.get_data()
def neighbours(x, xs, ys, try_invert=True):
(inds,) = np.where((xs <= x)[:-1] & (xs > x)[1:])
if len(inds) == 0:
assert try_invert, "line must cross x"
return neighbours(x, xs[::-1], ys[::-1], try_invert=False)
i = inds[0]
return np.asarray([(xs[i], ys[i]), (xs[i + 1], ys[i + 1])])
self.neighbours = n1, n2 = neighbours(x, xs, ys)
# Calculate y by interpolating neighbouring points
y = n1[1] + ((x - n1[0]) * (n2[1] - n1[1]) / (n2[0] - n1[0]))
kwargs = {
"horizontalalignment": "center",
"rotation_mode": "anchor",
**kwargs,
}
super().__init__(text, (x, y), xytext=xytext, textcoords=textcoords, **kwargs)
def get_rotation(self):
"""Determines angle of the slope of the neighbours in display coordinate system"""
transData = self.line.get_transform()
dx, dy = np.diff(transData.transform(self.neighbours), axis=0).squeeze()
return np.rad2deg(np.arctan2(dy, dx))
def update_positions(self, renderer):
"""Updates relative position of annotation text
Note
----
Called during annotation `draw` call
"""
xytext = Affine2D().rotate_deg(self.get_rotation()).transform(self.xytext)
self.set_position(xytext)
super().update_positions(renderer)
def line_annotate(text, line, x, *args, **kwargs):
"""Add a sloped annotation to *line* at position *x* with *text*
Optionally an arrow pointing from the text to the graph at *x* can be drawn.
Usage
-----
x = linspace(0, 2*pi)
line, = ax.plot(x, sin(x))
line_annotate("sin(x)", line, 1.5)
See also
--------
`LineAnnotation`
`plt.annotate`
"""
ax = line.axes
a = LineAnnotation(text, line, x, *args, **kwargs)
if "clip_on" in kwargs:
a.set_clip_path(ax.patch)
ax.add_artist(a)
return a
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import multiprocessing
# We must import this explicitly, it is not imported by the top-level
# multiprocessing module.
import multiprocessing.pool
class NoDaemonProcess(multiprocessing.Process):
def __init__(self, *args, **kwargs):
super(NoDaemonProcess, self).__init__(**kwargs)
# make 'daemon' attribute always return False
def _get_daemon(self):
return False
def _set_daemon(self, value):
pass
daemon = property(_get_daemon, _set_daemon)
# We sub-class multiprocessing.pool.Pool instead of multiprocessing.Pool
# because the latter is only a wrapper function, not a proper class.
class MyPool(multiprocessing.pool.Pool):
Process = NoDaemonProcess
+45
View File
@@ -0,0 +1,45 @@
# coding: utf-8
import os
import re
import munch
import yaml
_dir_path = os.path.dirname(os.path.realpath(__file__))
# Add support for '1e3' kind of float
_loader = yaml.SafeLoader
_loader.add_implicit_resolver(
u"tag:yaml.org,2002:float",
re.compile(
u"""^(?:
[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?
|[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)
|\\.[0-9_]+(?:[eE][-+][0-9]+)?
|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*
|[-+]?\\.(?:inf|Inf|INF)
|\\.(?:nan|NaN|NAN))$""",
re.X,
),
list(u"-+0123456789."),
)
def params_from_file(filename):
with open(filename) as f:
para_disk = yaml.load(f, Loader=_loader)
return munch.munchify(para_disk)
def default_params():
return params_from_file(_dir_path + "/../params.yml")
def load_params(filename):
basic_params = default_params()
new_params = params_from_file(filename)
for key in new_params:
if key in basic_params:
basic_params[key].update(new_params[key])
return basic_params
+98
View File
@@ -0,0 +1,98 @@
# coding: utf-8
import astrophysix.units as U
create_unit = U.Unit.create_unit
def parse_exp_unit(u):
splitted = u.split("^")
name_u = U.Unit.from_name(splitted[0]).latex.replace("text", "math")
exp = ""
if len(splitted) > 1:
exp = "^{" + str(splitted[1]) + "}"
return name_u + exp
def convert_exp(number, digits=4):
# Split string as [coeff, exponent]
splitted = "{num:.{digits}g}".format(num=number, digits=digits).split("e")
# If no need of scientific notation (low number of digits)
if len(splitted) == 1:
return "{}".format(splitted[0])
else:
coeff = splitted[0]
exp = splitted[1]
exp_str = "10^{" + str(int(exp)) + "}"
if float(coeff) == 1.0:
return f"${exp_str}$"
else:
return f"${coeff}\\times {exp_str}$"
def unit_str(unit, base=None, prefix="", format=" [{unit}]"):
"""
Format a unit in matplotlib parsable latex
unit : astrophysics.units.unit.Unit
base : astrophysics.units.unit.Unit to use as base unit (if None `unit` is used)
prefix : str to put befor the unit
format : str with the {unit} key, to put external decoration
"""
if unit == U.none:
return ""
elif base is not None:
coeff = unit.express(base)
return unit_str(base, prefix=convert_exp(coeff)+" ")
elif len(unit.latex) > 0:
if "." in unit.latex or "^" in unit.latex:
base_str = ".".join(map(parse_exp_unit, unit.name.split(".")))
u_str = r"{}${}$".format(prefix, base_str)
else:
u_str = r"{}${}$".format(prefix, unit.latex.replace("text", "math"))
elif len(unit.name) > 0:
base_str = ".".join(map(parse_exp_unit, unit.name.split(".")))
u_str = r"{}${}$".format(prefix, base_str)
else:
base_str = ".".join(
map(parse_exp_unit, unit._decompose_base_units().split("."))
)
u_str = r"{}${} {}$".format(prefix, unit.coeff, base_str)
return format.format(unit=u_str)
U.coldens = create_unit(
"Msun.pc^-2", base_unit=U.Msun / U.pc ** 2, descr="Column density"
)
U.km_s = create_unit("km.s^-1", base_unit=U.km / U.s, descr="Speed")
U.Msun_pc3 = create_unit("Msun.pc^-3", base_unit=U.Msun / U.pc ** 3, descr="Density")
U.kg_m3 = create_unit("kg.m^-3", base_unit=U.kg / U.m ** 3, descr="Density")
U.ssfr = create_unit(
"Msun.year^-1.pc^-2",
base_unit=U.Msun / U.year / U.pc ** 2,
descr="Surfacic SFR",
)
# latex='M$_{\odot}$.yr$^{-1}$.pc$^{-2}$')
U.ssfrG = create_unit(
"Msun.Gyr^-1.pc^-2",
base_unit=1e-9 * U.Msun / U.year / U.pc ** 2,
descr="Surfacic SFR",
latex="\mathrm{M}_{\odot}.\mathrm{Gyr}^{-1}.\mathrm{pc}^{-2}",
)
U.uG = create_unit(
"μG", base_unit=1e-10 * U.T, descr="Micro Gauss", latex="\\mu\\mathrm{G}"
)
U.ssfrK = create_unit(
"Msun.year^-1.kpc^-2",
base_unit=U.Msun / U.year / U.kpc ** 2,
descr="Surfacic SFR",
latex="\mathrm{M}_{\odot}.\mathrm{yr}^{-1}.\mathrm{kpc}^{-2}",
)