Skip to content

utils

utils

Author: Corentin Ravoux

Description : Utilities including coordinate conversion and various interfaces with other codes.

gaussian_fitter_2d

gaussian_fitter_2d(inpdata=None)

Bases: object

Fit a rotated 2D Gaussian (plus background) to a 2D array.

Attributes:

Name Type Description
inpdata ndarray

The 2D data being fitted.

Store the 2D data to fit.

Parameters:

Name Type Description Default
inpdata ndarray

The 2D data array.

None
Source code in lelantos/utils.py
721
722
723
724
725
726
727
def __init__(self, inpdata=None):
    """Store the 2D data to fit.

    Args:
        inpdata (numpy.ndarray, optional): The 2D data array.
    """
    self.inpdata = inpdata

moments2D

moments2D()

Returns the (amplitude, xcenter, ycenter, xsigma, ysigma, rot, bkg, e) estimated from moments in the 2d input array Data

Source code in lelantos/utils.py
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
def moments2D(self):
    """Returns the (amplitude, xcenter, ycenter, xsigma, ysigma, rot, bkg, e) estimated from moments in the 2d input array Data"""

    bkg = np.median(
        np.hstack(
            (
                self.inpdata[0, :],
                self.inpdata[-1, :],
                self.inpdata[:, 0],
                self.inpdata[:, -1],
            )
        )
    )  # Taking median of the 4 edges points as background
    Data = np.ma.masked_less(
        self.inpdata - bkg, 0
    )  # Removing the background for calculating moments of pure 2D gaussian
    # We also masked any negative values before measuring moments

    amplitude = Data.max()

    total = float(Data.sum())
    Xcoords, Ycoords = np.indices(Data.shape)

    xcenter = (Xcoords * Data).sum() / total
    ycenter = (Ycoords * Data).sum() / total

    RowCut = Data[
        int(xcenter), :
    ]  # Cut along the row of data near center of gaussian
    ColumnCut = Data[
        :, int(ycenter)
    ]  # Cut along the column of data near center of gaussian
    xsigma = np.sqrt(
        np.ma.sum(ColumnCut * (np.arange(len(ColumnCut)) - xcenter) ** 2)
        / ColumnCut.sum()
    )
    ysigma = np.sqrt(
        np.ma.sum(RowCut * (np.arange(len(RowCut)) - ycenter) ** 2) / RowCut.sum()
    )

    # Ellipcity and position angle calculation
    Mxx = np.ma.sum((Xcoords - xcenter) * (Xcoords - xcenter) * Data) / total
    Myy = np.ma.sum((Ycoords - ycenter) * (Ycoords - ycenter) * Data) / total
    Mxy = np.ma.sum((Xcoords - xcenter) * (Ycoords - ycenter) * Data) / total
    e = np.sqrt((Mxx - Myy) ** 2 + (2 * Mxy) ** 2) / (Mxx + Myy)
    pa = 0.5 * np.arctan(2 * Mxy / (Mxx - Myy))
    rot = np.rad2deg(pa)

    return amplitude, xcenter, ycenter, xsigma, ysigma, rot, bkg, e

Gaussian2D

Gaussian2D(amplitude, xcenter, ycenter, xsigma, ysigma, rot, bkg)

Returns a 2D Gaussian function with input parameters. rotation input rot should be in degress

Source code in lelantos/utils.py
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
def Gaussian2D(self, amplitude, xcenter, ycenter, xsigma, ysigma, rot, bkg):
    """Returns a 2D Gaussian function with input parameters. rotation input rot should be in degress"""
    rot = np.deg2rad(rot)  # Converting to radians
    Xc = xcenter * np.cos(rot) - ycenter * np.sin(
        rot
    )  # Centers in rotated coordinates
    Yc = xcenter * np.sin(rot) + ycenter * np.cos(rot)

    # Now lets define the 2D gaussian function
    def Gauss2D(x, y):
        """Returns the values of the defined 2d gaussian at x,y"""
        xr = x * np.cos(rot) - y * np.sin(rot)  # X position in rotated coordinates
        yr = x * np.sin(rot) + y * np.cos(rot)
        return (
            amplitude
            * np.exp(-(((xr - Xc) / xsigma) ** 2 + ((yr - Yc) / ysigma) ** 2) / 2)
            + bkg
        )

    return Gauss2D

FitGauss2D

FitGauss2D(ip=None)

Fits 2D gaussian to Data with optional Initial conditions ip=(amplitude, xcenter, ycenter, xsigma, ysigma, rot, bkg) Example:

X,Y=np.indices((40,40),dtype=np.float) Data=np.exp(-(((X-25)/5)2 +((Y-15)/10)2)/2) + 1 FitGauss2D(Data) (array([ 1.00000000e+00, 2.50000000e+01, 1.50000000e+01, 5.00000000e+00, 1.00000000e+01, 2.09859373e-07, 1]), 2)

Source code in lelantos/utils.py
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
def FitGauss2D(self, ip=None):
    """Fits 2D gaussian to Data with optional Initial conditions ip=(amplitude, xcenter, ycenter, xsigma, ysigma, rot, bkg)
    Example:
    >>> X,Y=np.indices((40,40),dtype=np.float)
    >>> Data=np.exp(-(((X-25)/5)**2 +((Y-15)/10)**2)/2) + 1
    >>> FitGauss2D(Data)
    (array([  1.00000000e+00,   2.50000000e+01,   1.50000000e+01, 5.00000000e+00,   1.00000000e+01,   2.09859373e-07, 1]), 2)
    """
    if (
        ip is None
    ):  # Estimate the initial parameters form moments and also set rot angle to be 0
        ip = self.moments2D()[
            :-1
        ]  # Remove ellipticity from the end in parameter list

    Xcoords, Ycoords = np.indices(self.inpdata.shape)

    def errfun(ip):
        dXcoords = Xcoords - ip[1]
        dYcoords = Ycoords - ip[2]
        Weights = np.sqrt(
            np.square(dXcoords) + np.square(dYcoords)
        )  # Taking radius as the weights for least square fitting
        return np.ravel(
            (self.Gaussian2D(*ip)(*np.indices(self.inpdata.shape)) - self.inpdata)
            / np.sqrt(Weights)
        )  # Taking a sqrt(weight) here so that while scipy takes square of this array it will become 1/r weight.

    p, success = leastsq(errfun, ip)

    return p, success

Logger

Logger(name='Python_Report', log_level='info')

Bases: object

Thin wrapper around :mod:logging for console or file reports.

Attributes:

Name Type Description
name str

Report file name (file mode).

log_level str

"info", "debug" or "warning".

Store the logger name and level (call a setup_* method next).

Parameters:

Name Type Description Default
name str

Report file path. Defaults to "Python_Report".

'Python_Report'
log_level str

Logging level. Defaults to "info".

'info'
Source code in lelantos/utils.py
873
874
875
876
877
878
879
880
881
def __init__(self, name="Python_Report", log_level="info"):
    """Store the logger name and level (call a ``setup_*`` method next).

    Args:
        name (str, optional): Report file path. Defaults to ``"Python_Report"``.
        log_level (str, optional): Logging level. Defaults to ``"info"``.
    """
    self.name = name
    self.log_level = log_level

setup_logging

setup_logging()

Taken from https://nbodykit.readthedocs.io/ Turn on logging, with the specified level. Parameters


log_level : 'info', 'debug', 'warning' the logging level to set; logging below this level is ignored

Source code in lelantos/utils.py
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
def setup_logging(self):
    """
    Taken from https://nbodykit.readthedocs.io/
    Turn on logging, with the specified level.
    Parameters
    ----------
    log_level : 'info', 'debug', 'warning'
            the logging level to set; logging below this level is ignored
    """

    # This gives:
    #
    # [ 000000.43 ]   0: 06-28 14:49  measurestats	INFO	 Nproc = [2, 1, 1]
    # [ 000000.43 ]   0: 06-28 14:49  measurestats	INFO	 Rmax = 120

    levels = {
        "info": logging.INFO,
        "debug": logging.DEBUG,
        "warning": logging.WARNING,
    }

    logger = logging.getLogger()
    t0 = time.time()

    class Formatter(logging.Formatter):
        def format(self, record):
            s1 = "[ %09.2f ]: " % (time.time() - t0)
            return s1 + logging.Formatter.format(self, record)

    fmt = Formatter(
        fmt="%(asctime)s %(name)-15s %(levelname)-8s %(message)s",
        datefmt="%m-%d %H:%M ",
    )

    global _logging_handler
    if _logging_handler is None:
        _logging_handler = logging.StreamHandler()
        logger.addHandler(_logging_handler)

    _logging_handler.setFormatter(fmt)
    logger.setLevel(levels[self.log_level])

setup_report_logging

setup_report_logging()

Configure :mod:logging to write to the report file name.

Source code in lelantos/utils.py
925
926
927
928
929
930
931
932
933
934
935
936
937
def setup_report_logging(self):
    """Configure :mod:`logging` to write to the report file ``name``."""
    levels = {
        "info": logging.INFO,
        "debug": logging.DEBUG,
        "warning": logging.WARNING,
    }
    logging.basicConfig(
        filename=self.name,
        filemode="w",
        level=levels[self.log_level],
        format="%(asctime)s :: %(levelname)s :: %(message)s",
    )

add staticmethod

add(line, level='info')

Emit a log line at the given level.

Parameters:

Name Type Description Default
line str

Message to log.

required
level str

"info", "warning" or "debug".

'info'
Source code in lelantos/utils.py
939
940
941
942
943
944
945
946
947
948
949
950
951
952
@staticmethod
def add(line, level="info"):
    """Emit a log line at the given level.

    Args:
        line (str): Message to log.
        level (str, optional): ``"info"``, ``"warning"`` or ``"debug"``.
    """
    if level == "info":
        logging.info(line)
    if level == "warning":
        logging.warning(line)
    if level == "debug":
        logging.debug(line)

add_array_statistics staticmethod

add_array_statistics(arr, char)

Log the min/max/mean/std of an array.

Parameters:

Name Type Description Default
arr ndarray | None

Array to summarise (no-op if None).

required
char str

Label used in the log messages.

required
Source code in lelantos/utils.py
954
955
956
957
958
959
960
961
962
963
964
965
966
@staticmethod
def add_array_statistics(arr, char):
    """Log the min/max/mean/std of an array.

    Args:
        arr (numpy.ndarray | None): Array to summarise (no-op if None).
        char (str): Label used in the log messages.
    """
    if arr is not None:
        Logger.add(f"Min of {char}: {arr.min()}")
        Logger.add(f"Max of {char}: {arr.max()}")
        Logger.add(f"Mean of {char}: {arr.mean()}")
        Logger.add(f"Standard deviation of {char}: {arr.std()}")

close staticmethod

close()

Flush and shut down the logging system.

Source code in lelantos/utils.py
968
969
970
971
@staticmethod
def close():
    """Flush and shut down the logging system."""
    logging.shutdown()

ForkingPickler4

ForkingPickler4(*args)

Bases: ForkingPickler

ForkingPickler forced to protocol 4 (for >4 GiB multiprocessing payloads).

Force pickle protocol 4 then delegate to the base pickler.

Source code in lelantos/utils.py
1018
1019
1020
1021
1022
1023
1024
def __init__(self, *args):
    """Force pickle protocol 4 then delegate to the base pickler."""
    if len(args) > 1:
        args[1] = 2
    else:
        args.append(2)
    super().__init__(*args)

dumps classmethod

dumps(obj, protocol=4)

Pickle obj with protocol 4.

Parameters:

Name Type Description Default
obj

Object to serialise.

required
protocol int

Pickle protocol. Defaults to 4.

4

Returns:

Name Type Description
bytes

The pickled payload.

Source code in lelantos/utils.py
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
@classmethod
def dumps(cls, obj, protocol=4):
    """Pickle ``obj`` with protocol 4.

    Args:
        obj: Object to serialise.
        protocol (int, optional): Pickle protocol. Defaults to 4.

    Returns:
        bytes: The pickled payload.
    """
    return ForkingPickler.dumps(obj, protocol)

Pickle4Reducer

Bases: AbstractReducer

Multiprocessing reducer using protocol-4 pickling.

Assign to a context reducer (ctx.reducer = Pickle4Reducer()) to allow multiprocessing payloads larger than 4 GiB.

mpc_per_pixel

mpc_per_pixel(size, shape)

Physical size of one pixel along each axis.

Parameters:

Name Type Description Default
size array - like

Box physical size per axis (Mpc.h^-1).

required
shape array - like

Box pixel count per axis.

required

Returns:

Type Description

numpy.ndarray: size / (shape - 1) per axis (Mpc.h^-1 per pixel).

Source code in lelantos/utils.py
41
42
43
44
45
46
47
48
49
50
51
def mpc_per_pixel(size, shape):
    """Physical size of one pixel along each axis.

    Args:
        size (array-like): Box physical size per axis (Mpc.h^-1).
        shape (array-like): Box pixel count per axis.

    Returns:
        numpy.ndarray: ``size / (shape - 1)`` per axis (Mpc.h^-1 per pixel).
    """
    return np.array(size) / (np.array(shape) - 1)

pixel_per_mpc

pixel_per_mpc(size, shape)

Number of pixels per Mpc.h^-1 along each axis.

Parameters:

Name Type Description Default
size array - like

Box physical size per axis (Mpc.h^-1).

required
shape array - like

Box pixel count per axis.

required

Returns:

Type Description

numpy.ndarray: (shape - 1) / size per axis.

Source code in lelantos/utils.py
54
55
56
57
58
59
60
61
62
63
64
def pixel_per_mpc(size, shape):
    """Number of pixels per Mpc.h^-1 along each axis.

    Args:
        size (array-like): Box physical size per axis (Mpc.h^-1).
        shape (array-like): Box pixel count per axis.

    Returns:
        numpy.ndarray: ``(shape - 1) / size`` per axis.
    """
    return (np.array(shape) - 1) / np.array(size)

get_map_shape

get_map_shape(size, mpc_per_pixel)

Pixel shape implied by a physical size and pixel scale.

Parameters:

Name Type Description Default
size array - like

Box physical size per axis (Mpc.h^-1).

required
mpc_per_pixel array - like

Mpc.h^-1 per pixel per axis.

required

Returns:

Type Description

numpy.ndarray: size / mpc_per_pixel + 1 per axis.

Source code in lelantos/utils.py
67
68
69
70
71
72
73
74
75
76
77
def get_map_shape(size, mpc_per_pixel):
    """Pixel shape implied by a physical size and pixel scale.

    Args:
        size (array-like): Box physical size per axis (Mpc.h^-1).
        mpc_per_pixel (array-like): Mpc.h^-1 per pixel per axis.

    Returns:
        numpy.ndarray: ``size / mpc_per_pixel + 1`` per axis.
    """
    return (np.array(size) / np.array(mpc_per_pixel)) + 1

get_map_size

get_map_size(shape, mpc_per_pixel)

Physical size implied by a pixel shape and pixel scale.

Parameters:

Name Type Description Default
shape array - like

Box pixel count per axis.

required
mpc_per_pixel array - like

Mpc.h^-1 per pixel per axis.

required

Returns:

Type Description

numpy.ndarray: (shape - 1) * mpc_per_pixel per axis (Mpc.h^-1).

Source code in lelantos/utils.py
80
81
82
83
84
85
86
87
88
89
90
def get_map_size(shape, mpc_per_pixel):
    """Physical size implied by a pixel shape and pixel scale.

    Args:
        shape (array-like): Box pixel count per axis.
        mpc_per_pixel (array-like): Mpc.h^-1 per pixel per axis.

    Returns:
        numpy.ndarray: ``(shape - 1) * mpc_per_pixel`` per axis (Mpc.h^-1).
    """
    return (np.array(shape) - 1) * mpc_per_pixel

get_cosmo_function

get_cosmo_function(Omega_m, Omega_k=0.0)

Build comoving-distance functions and their inverses (via picca).

Parameters:

Name Type Description Default
Omega_m float

Matter density parameter.

required
Omega_k float

Curvature density parameter. Defaults to 0.0.

0.0

Returns:

Name Type Description
tuple

(rcomov, distang, inv_rcomov, inv_distang) where rcomov

and distang map redshift to comoving / angular-diameter distance and

the two inv_* interpolators map distance back to redshift.

Source code in lelantos/utils.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
def get_cosmo_function(Omega_m, Omega_k=0.0):
    """Build comoving-distance functions and their inverses (via picca).

    Args:
        Omega_m (float): Matter density parameter.
        Omega_k (float, optional): Curvature density parameter. Defaults to 0.0.

    Returns:
        tuple: ``(rcomov, distang, inv_rcomov, inv_distang)`` where ``rcomov``
        and ``distang`` map redshift to comoving / angular-diameter distance and
        the two ``inv_*`` interpolators map distance back to redshift.
    """
    Cosmo = constants.Cosmo(Omega_m, Ok=Omega_k)
    rcomov = Cosmo.get_r_comov
    distang = Cosmo.get_dist_m
    redshift_array = np.linspace(0, 5, 10000)
    R_array = rcomov(redshift_array)
    Dm_array = rcomov(redshift_array)
    inv_rcomov = interpolate.interp1d(R_array, redshift_array)
    inv_distang = interpolate.interp1d(Dm_array, redshift_array)
    return (rcomov, distang, inv_rcomov, inv_distang)

return_suplementary_parameters

return_suplementary_parameters(mode, property=None, zmin=None, zmax=None)

Return the extra parameters needed by a coordinate transform.

For the "middle" transform this is the mid-redshift of the box, taken either from a property object or from an explicit (zmin, zmax) window.

Parameters:

Name Type Description Default
mode str

Coordinate transform mode (e.g. "middle").

required
property optional

Object exposing boundary_sky_coord to read the redshift bounds from.

None
zmin float

Minimum redshift (if property is None).

None
zmax float

Maximum redshift (if property is None).

None

Returns:

Type Description

list | None: [middle_z] for the "middle" mode, else None.

Source code in lelantos/utils.py
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
def return_suplementary_parameters(mode, property=None, zmin=None, zmax=None):
    """Return the extra parameters needed by a coordinate transform.

    For the ``"middle"`` transform this is the mid-redshift of the box, taken
    either from a property object or from an explicit ``(zmin, zmax)`` window.

    Args:
        mode (str): Coordinate transform mode (e.g. ``"middle"``).
        property (optional): Object exposing ``boundary_sky_coord`` to read the
            redshift bounds from.
        zmin (float, optional): Minimum redshift (if ``property`` is None).
        zmax (float, optional): Maximum redshift (if ``property`` is None).

    Returns:
        list | None: ``[middle_z]`` for the ``"middle"`` mode, else ``None``.
    """
    if mode == "middle":
        if property is not None:
            zmin = property.boundary_sky_coord[0][2]
            zmax = property.boundary_sky_coord[1][2]
            suplementary_parameters = [(zmin + zmax) / 2]
        elif (zmin is not None) & (zmin is not None):
            suplementary_parameters = [(zmin + zmax) / 2]
    else:
        suplementary_parameters = None
    return suplementary_parameters

convert_cartesian_to_sky

convert_cartesian_to_sky(X, Y, Z, method, inv_rcomov=None, inv_distang=None, distang=None, suplementary_parameters=None)

Convert cartesian coordinates to sky coordinates (Mpc.h-1 to radians).

Dispatches to the full_angle / full / middle implementation.

Parameters:

Name Type Description Default
X, Y, Z array - like

Cartesian comoving coordinates (Mpc.h^-1).

required
method str

Transform mode ("full_angle", "full", "middle").

required
inv_rcomov callable

Comoving distance -> redshift.

None
inv_distang callable

Angular-diameter distance -> redshift.

None
distang callable

Redshift -> angular-diameter distance.

None
suplementary_parameters list

Extra params (e.g. middle z).

None

Returns:

Name Type Description
tuple

(RA, DEC, z) with angles in radians.

Source code in lelantos/utils.py
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
def convert_cartesian_to_sky(
    X,
    Y,
    Z,
    method,
    inv_rcomov=None,
    inv_distang=None,
    distang=None,
    suplementary_parameters=None,
):
    """Convert cartesian coordinates to sky coordinates (Mpc.h-1 to radians).

    Dispatches to the ``full_angle`` / ``full`` / ``middle`` implementation.

    Args:
        X, Y, Z (array-like): Cartesian comoving coordinates (Mpc.h^-1).
        method (str): Transform mode (``"full_angle"``, ``"full"``, ``"middle"``).
        inv_rcomov (callable, optional): Comoving distance -> redshift.
        inv_distang (callable, optional): Angular-diameter distance -> redshift.
        distang (callable, optional): Redshift -> angular-diameter distance.
        suplementary_parameters (list, optional): Extra params (e.g. middle z).

    Returns:
        tuple: ``(RA, DEC, z)`` with angles in radians.
    """
    if method == "full_angle":
        (RA, DEC, z) = convert_cartesian_to_sky_full_angle(X, Y, Z, inv_rcomov)
    if method == "full":
        (RA, DEC, z) = convert_cartesian_to_sky_full(X, Y, Z, inv_rcomov)
    elif method == "middle":
        (RA, DEC, z) = convert_cartesian_to_sky_middle(
            X, Y, Z, inv_rcomov, distang, suplementary_parameters[0]
        )
    return (RA, DEC, z)

convert_sky_to_cartesian

convert_sky_to_cartesian(RA, DEC, z, method, rcomov=None, distang=None, suplementary_parameters=None)

Convert sky coordinates to cartesian coordinates (radians to Mpc.h-1).

Dispatches to the full_angle / full / middle implementation.

Parameters:

Name Type Description Default
RA, DEC array - like

Sky angles (radians).

required
z array - like

Redshift.

required
method str

Transform mode ("full_angle", "full", "middle").

required
rcomov callable

Redshift -> comoving distance.

None
distang callable

Redshift -> angular-diameter distance.

None
suplementary_parameters list

Extra params (e.g. middle z).

None

Returns:

Name Type Description
tuple

(X, Y, Z) cartesian comoving coordinates (Mpc.h^-1).

Source code in lelantos/utils.py
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
def convert_sky_to_cartesian(
    RA, DEC, z, method, rcomov=None, distang=None, suplementary_parameters=None
):
    """Convert sky coordinates to cartesian coordinates (radians to Mpc.h-1).

    Dispatches to the ``full_angle`` / ``full`` / ``middle`` implementation.

    Args:
        RA, DEC (array-like): Sky angles (radians).
        z (array-like): Redshift.
        method (str): Transform mode (``"full_angle"``, ``"full"``, ``"middle"``).
        rcomov (callable, optional): Redshift -> comoving distance.
        distang (callable, optional): Redshift -> angular-diameter distance.
        suplementary_parameters (list, optional): Extra params (e.g. middle z).

    Returns:
        tuple: ``(X, Y, Z)`` cartesian comoving coordinates (Mpc.h^-1).
    """
    if method == "full_angle":
        (X, Y, Z) = convert_sky_to_cartesian_full_angle(RA, DEC, z, rcomov)
    elif method == "full":
        (X, Y, Z) = convert_sky_to_cartesian_full(RA, DEC, z, rcomov)
    elif method == "middle":
        (X, Y, Z) = convert_sky_to_cartesian_middle(
            RA, DEC, z, rcomov, distang, suplementary_parameters[0]
        )
    return (X, Y, Z)

convert_cartesian_to_sky_full_angle

convert_cartesian_to_sky_full_angle(X, Y, Z, inv_rcomov)

Cartesian -> sky using the exact spherical angles.

Parameters:

Name Type Description Default
X, Y, Z array - like

Cartesian comoving coordinates (Mpc.h^-1).

required
inv_rcomov callable

Comoving distance -> redshift.

required

Returns:

Name Type Description
tuple

(RA, DEC, z) with angles in radians.

Source code in lelantos/utils.py
209
210
211
212
213
214
215
216
217
218
219
220
221
222
def convert_cartesian_to_sky_full_angle(X, Y, Z, inv_rcomov):
    """Cartesian -> sky using the exact spherical angles.

    Args:
        X, Y, Z (array-like): Cartesian comoving coordinates (Mpc.h^-1).
        inv_rcomov (callable): Comoving distance -> redshift.

    Returns:
        tuple: ``(RA, DEC, z)`` with angles in radians.
    """
    RA = np.arctan2(X, Z)
    DEC = np.arcsin(Y / np.sqrt(X**2 + Y**2 + Z**2))
    z = inv_rcomov(np.sqrt(X**2 + Y**2 + Z**2))
    return (RA, DEC, z)

convert_sky_to_cartesian_full_angle

convert_sky_to_cartesian_full_angle(RA, DEC, z, rcomov)

Sky -> cartesian using the exact spherical angles.

Parameters:

Name Type Description Default
RA, DEC array - like

Sky angles (radians).

required
z array - like

Redshift.

required
rcomov callable

Redshift -> comoving distance.

required

Returns:

Name Type Description
tuple

(X, Y, Z) cartesian comoving coordinates (Mpc.h^-1).

Source code in lelantos/utils.py
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
def convert_sky_to_cartesian_full_angle(RA, DEC, z, rcomov):
    """Sky -> cartesian using the exact spherical angles.

    Args:
        RA, DEC (array-like): Sky angles (radians).
        z (array-like): Redshift.
        rcomov (callable): Redshift -> comoving distance.

    Returns:
        tuple: ``(X, Y, Z)`` cartesian comoving coordinates (Mpc.h^-1).
    """
    X = rcomov(z) * np.sin(RA) * np.cos(DEC)
    Y = rcomov(z) * np.sin(DEC)
    Z = rcomov(z) * np.cos(RA) * np.cos(DEC)
    return (X, Y, Z)

convert_cartesian_to_sky_full

convert_cartesian_to_sky_full(X, Y, Z, inv_rcomov)

Cartesian -> sky using the small-angle (X/Z, Y/Z) approximation.

Parameters:

Name Type Description Default
X, Y, Z array - like

Cartesian comoving coordinates (Mpc.h^-1).

required
inv_rcomov callable

Comoving distance -> redshift.

required

Returns:

Name Type Description
tuple

(RA, DEC, z).

Source code in lelantos/utils.py
242
243
244
245
246
247
248
249
250
251
252
253
254
255
def convert_cartesian_to_sky_full(X, Y, Z, inv_rcomov):
    """Cartesian -> sky using the small-angle (X/Z, Y/Z) approximation.

    Args:
        X, Y, Z (array-like): Cartesian comoving coordinates (Mpc.h^-1).
        inv_rcomov (callable): Comoving distance -> redshift.

    Returns:
        tuple: ``(RA, DEC, z)``.
    """
    z = inv_rcomov(np.sqrt(X**2 + Y**2 + Z**2))
    RA = X / Z
    DEC = Y / Z
    return (RA, DEC, z)

convert_sky_to_cartesian_full

convert_sky_to_cartesian_full(RA, DEC, z, rcomov)

Sky -> cartesian using the small-angle approximation.

Parameters:

Name Type Description Default
RA, DEC array - like

Sky angles (radians).

required
z array - like

Redshift.

required
rcomov callable

Redshift -> comoving distance.

required

Returns:

Name Type Description
tuple

(X, Y, Z) (Mpc.h^-1).

Source code in lelantos/utils.py
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
def convert_sky_to_cartesian_full(RA, DEC, z, rcomov):
    """Sky -> cartesian using the small-angle approximation.

    Args:
        RA, DEC (array-like): Sky angles (radians).
        z (array-like): Redshift.
        rcomov (callable): Redshift -> comoving distance.

    Returns:
        tuple: ``(X, Y, Z)`` (Mpc.h^-1).
    """
    X = rcomov(z) * RA
    Y = rcomov(z) * DEC
    Z = rcomov(z)
    return (X, Y, Z)

convert_cartesian_to_sky_middle

convert_cartesian_to_sky_middle(X, Y, Z, inv_rcomov, distang, middle_z)

Cartesian -> sky using a tangent plane at the box mid-redshift.

Transverse coordinates are divided by the angular-diameter distance at the fixed middle_z; the radial coordinate maps directly to redshift.

Parameters:

Name Type Description Default
X, Y, Z array - like

Cartesian comoving coordinates (Mpc.h^-1).

required
inv_rcomov callable

Comoving distance -> redshift.

required
distang callable

Redshift -> angular-diameter distance.

required
middle_z float

Reference (box centre) redshift.

required

Returns:

Name Type Description
tuple

(RA, DEC, z).

Source code in lelantos/utils.py
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
def convert_cartesian_to_sky_middle(X, Y, Z, inv_rcomov, distang, middle_z):
    """Cartesian -> sky using a tangent plane at the box mid-redshift.

    Transverse coordinates are divided by the angular-diameter distance at the
    fixed ``middle_z``; the radial coordinate maps directly to redshift.

    Args:
        X, Y, Z (array-like): Cartesian comoving coordinates (Mpc.h^-1).
        inv_rcomov (callable): Comoving distance -> redshift.
        distang (callable): Redshift -> angular-diameter distance.
        middle_z (float): Reference (box centre) redshift.

    Returns:
        tuple: ``(RA, DEC, z)``.
    """
    RA = X / distang(middle_z)
    DEC = Y / distang(middle_z)
    z = inv_rcomov(Z)
    return (RA, DEC, z)

convert_sky_to_cartesian_middle

convert_sky_to_cartesian_middle(RA, DEC, z, rcomov, distang, middle_z)

Sky -> cartesian using a tangent plane at the box mid-redshift.

Parameters:

Name Type Description Default
RA, DEC array - like

Sky angles (radians).

required
z array - like

Redshift.

required
rcomov callable

Redshift -> comoving distance.

required
distang callable

Redshift -> angular-diameter distance.

required
middle_z float

Reference (box centre) redshift.

required

Returns:

Name Type Description
tuple

(X, Y, Z) (Mpc.h^-1).

Source code in lelantos/utils.py
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
def convert_sky_to_cartesian_middle(RA, DEC, z, rcomov, distang, middle_z):
    """Sky -> cartesian using a tangent plane at the box mid-redshift.

    Args:
        RA, DEC (array-like): Sky angles (radians).
        z (array-like): Redshift.
        rcomov (callable): Redshift -> comoving distance.
        distang (callable): Redshift -> angular-diameter distance.
        middle_z (float): Reference (box centre) redshift.

    Returns:
        tuple: ``(X, Y, Z)`` (Mpc.h^-1).
    """
    X = distang(middle_z) * RA
    Y = distang(middle_z) * DEC
    Z = rcomov(z)
    return (X, Y, Z)

convert_z_cartesian_to_sky_middle

convert_z_cartesian_to_sky_middle(Z, inv_rcomov)

Map the radial cartesian coordinate to redshift (middle transform).

Parameters:

Name Type Description Default
Z array - like

Radial comoving coordinate (Mpc.h^-1).

required
inv_rcomov callable

Comoving distance -> redshift.

required

Returns:

Type Description

array-like: Redshift.

Source code in lelantos/utils.py
315
316
317
318
319
320
321
322
323
324
325
326
def convert_z_cartesian_to_sky_middle(Z, inv_rcomov):
    """Map the radial cartesian coordinate to redshift (middle transform).

    Args:
        Z (array-like): Radial comoving coordinate (Mpc.h^-1).
        inv_rcomov (callable): Comoving distance -> redshift.

    Returns:
        array-like: Redshift.
    """
    z = inv_rcomov(Z)
    return z

convert_z_sky_to_cartesian_middle

convert_z_sky_to_cartesian_middle(z, rcomov)

Map redshift to the radial cartesian coordinate (middle transform).

Parameters:

Name Type Description Default
z array - like

Redshift.

required
rcomov callable

Redshift -> comoving distance.

required

Returns:

Type Description

array-like: Radial comoving coordinate (Mpc.h^-1).

Source code in lelantos/utils.py
329
330
331
332
333
334
335
336
337
338
339
340
def convert_z_sky_to_cartesian_middle(z, rcomov):
    """Map redshift to the radial cartesian coordinate (middle transform).

    Args:
        z (array-like): Redshift.
        rcomov (callable): Redshift -> comoving distance.

    Returns:
        array-like: Radial comoving coordinate (Mpc.h^-1).
    """
    Z = rcomov(z)
    return Z

get_direction_indexes

get_direction_indexes(direction, rotate)

Map a slicing direction name to axis indexes and labels.

Parameters:

Name Type Description Default
direction str

One of x/ra, y/dec, z/redshift.

required
rotate bool

Swap the in-plane x/y indexes if True.

required

Returns:

Name Type Description
tuple

(x_index, y_index, index_direction, index_dict) giving the

two in-plane axis indexes, the slice-normal axis index and a label dict.

Source code in lelantos/utils.py
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
def get_direction_indexes(direction, rotate):
    """Map a slicing direction name to axis indexes and labels.

    Args:
        direction (str): One of ``x/ra``, ``y/dec``, ``z/redshift``.
        rotate (bool): Swap the in-plane x/y indexes if True.

    Returns:
        tuple: ``(x_index, y_index, index_direction, index_dict)`` giving the
        two in-plane axis indexes, the slice-normal axis index and a label dict.
    """
    if (direction.lower() == "x") | (direction.lower() == "ra"):
        x_index, y_index, index_direction = 2, 1, 0
    elif (direction.lower() == "y") | (direction.lower() == "dec"):
        x_index, y_index, index_direction = 2, 0, 1
    elif (direction.lower() == "z") | (direction.lower() == "redshift"):
        x_index, y_index, index_direction = 1, 0, 2
    if rotate:
        x_index, y_index = y_index, x_index
    index_dict = {0: "x", 1: "y", 2: "z", "x_lab": "X", "y_lab": "Y", "z_lab": "Z"}
    return (x_index, y_index, index_direction, index_dict)

saclay_mock_box_cosmo_parameters

saclay_mock_box_cosmo_parameters(box_shape, size_cell)

Return the SaclayMocks fiducial cosmology and box radial bounds.

Parameters:

Name Type Description Default
box_shape tuple[int]

Box pixel shape (nx, ny, nz).

required
size_cell float

Cell size (Mpc.h^-1).

required

Returns:

Name Type Description
tuple

(R0, z0, R_of_z, z_of_R, Rmin, Rmax, h) — box-centre comoving

distance and redshift, distance/redshift interpolators, radial box

bounds and the reduced Hubble constant.

Source code in lelantos/utils.py
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
def saclay_mock_box_cosmo_parameters(box_shape, size_cell):
    """Return the SaclayMocks fiducial cosmology and box radial bounds.

    Args:
        box_shape (tuple[int]): Box pixel shape ``(nx, ny, nz)``.
        size_cell (float): Cell size (Mpc.h^-1).

    Returns:
        tuple: ``(R0, z0, R_of_z, z_of_R, Rmin, Rmax, h)`` — box-centre comoving
        distance and redshift, distance/redshift interpolators, radial box
        bounds and the reduced Hubble constant.
    """
    import cosmolopy.distance as dist

    try:
        from SaclayMocks import constant as saclay_mock_constant
    except:
        from lelantos.saclaymocks import constant as saclay_mock_constant

        print(
            "SaclayMocks might be updated, we suggest to install SaclayMocks independently"
        )
    NZ = box_shape[2]
    DZ = size_cell
    LZ = NZ * DZ

    h = saclay_mock_constant.h
    Om = saclay_mock_constant.omega_M_0
    OL = saclay_mock_constant.omega_lambda_0
    Ok = saclay_mock_constant.omega_k_0
    z0 = saclay_mock_constant.z0

    cosmo_fid = {"omega_M_0": Om, "omega_lambda_0": OL, "omega_k_0": Ok, "h": h}
    R_of_z, z_of_R = dist.quick_distance_function(
        dist.comoving_distance, return_inverse=True, **cosmo_fid
    )
    R0 = h * R_of_z(z0)
    Rmin = R0 - LZ / 2
    Rmax = R0 + LZ / 2
    return (R0, z0, R_of_z, z_of_R, Rmin, Rmax, h)

saclay_mock_center_of_the_box

saclay_mock_center_of_the_box(box_bound)

Return the (RA, Dec) centre of a SaclayMocks box footprint.

Parameters:

Name Type Description Default
box_bound sequence

(ramin, ramax, decmin, decmax).

required

Returns:

Name Type Description
tuple

(ra0_box, dec0_box) footprint centre.

Source code in lelantos/utils.py
425
426
427
428
429
430
431
432
433
434
435
436
def saclay_mock_center_of_the_box(box_bound):
    """Return the (RA, Dec) centre of a SaclayMocks box footprint.

    Args:
        box_bound (sequence): ``(ramin, ramax, decmin, decmax)``.

    Returns:
        tuple: ``(ra0_box, dec0_box)`` footprint centre.
    """
    ra0_box = (box_bound[0] + box_bound[1]) / 2
    dec0_box = (box_bound[2] + box_bound[3]) / 2
    return (ra0_box, dec0_box)

saclay_mock_coord_dm_map

saclay_mock_coord_dm_map(X, Y, Z, Rmin, size_cell, box_shape, interpolation_method)

Convert cartesian coordinates to SaclayMocks dark-matter box indexes.

Parameters:

Name Type Description Default
X, Y, Z array - like

Cartesian coordinates (Mpc.h^-1).

required
Rmin float

Radial lower bound of the box (Mpc.h^-1).

required
size_cell float

Cell size (Mpc.h^-1).

required
box_shape tuple[int]

Box pixel shape.

required
interpolation_method str

"NEAREST" rounds to integer indexes; otherwise fractional indexes are returned.

required

Returns:

Name Type Description
tuple

(n_i, n_j, n_k) box indexes (int for NEAREST, else float).

Source code in lelantos/utils.py
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
def saclay_mock_coord_dm_map(X, Y, Z, Rmin, size_cell, box_shape, interpolation_method):
    """Convert cartesian coordinates to SaclayMocks dark-matter box indexes.

    Args:
        X, Y, Z (array-like): Cartesian coordinates (Mpc.h^-1).
        Rmin (float): Radial lower bound of the box (Mpc.h^-1).
        size_cell (float): Cell size (Mpc.h^-1).
        box_shape (tuple[int]): Box pixel shape.
        interpolation_method (str): ``"NEAREST"`` rounds to integer indexes;
            otherwise fractional indexes are returned.

    Returns:
        tuple: ``(n_i, n_j, n_k)`` box indexes (int for NEAREST, else float).
    """
    size_cell = size_cell
    center_x = (box_shape[0] - 1) / 2
    center_y = (box_shape[1] - 1) / 2
    if interpolation_method.upper() == "NEAREST":
        n_i = (np.round(center_x + X / size_cell, 0)).astype(int)
        n_j = (np.round(center_y + Y / size_cell, 0)).astype(int)
        n_k = np.round((Z - Rmin) / size_cell, 0).astype(int)
    else:
        n_i = center_x + X / size_cell
        n_j = center_y + Y / size_cell
        n_k = (Z - Rmin) / size_cell
    return (n_i, n_j, n_k)

saclay_mock_read_box

saclay_mock_read_box(box_dir, n_x, name_box)

Read one SaclayMocks box FITS slab from disk.

Parameters:

Name Type Description Default
box_dir str

Directory holding the box FITS files.

required
n_x int

Slab index.

required
name_box str

Box field name (e.g. "box", "vx").

required

Returns:

Type Description

numpy.ndarray: The slab data array.

Source code in lelantos/utils.py
467
468
469
470
471
472
473
474
475
476
477
478
479
480
def saclay_mock_read_box(box_dir, n_x, name_box):
    """Read one SaclayMocks box FITS slab from disk.

    Args:
        box_dir (str): Directory holding the box FITS files.
        n_x (int): Slab index.
        name_box (str): Box field name (e.g. ``"box"``, ``"vx"``).

    Returns:
        numpy.ndarray: The slab data array.
    """
    name = "{}-{}.fits".format(name_box, str(n_x))
    box = fitsio.FITS(os.path.join(box_dir, name))[0][:, :, :][0]
    return box

saclay_mock_get_box

saclay_mock_get_box(box_dir, box_shape, name_box='box')

Assemble a full SaclayMocks box from its per-slab FITS files.

Parameters:

Name Type Description Default
box_dir str

Directory holding the box FITS files.

required
box_shape tuple[int]

Full box pixel shape.

required
name_box str

Box field name. Defaults to "box".

'box'

Returns:

Type Description

numpy.ndarray: The assembled 3D box.

Source code in lelantos/utils.py
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
def saclay_mock_get_box(box_dir, box_shape, name_box="box"):
    """Assemble a full SaclayMocks box from its per-slab FITS files.

    Args:
        box_dir (str): Directory holding the box FITS files.
        box_shape (tuple[int]): Full box pixel shape.
        name_box (str, optional): Box field name. Defaults to ``"box"``.

    Returns:
        numpy.ndarray: The assembled 3D box.
    """
    line_per_box = saclay_mock_lines_per_box[name_box]
    DM_mocks = np.zeros((box_shape[0], box_shape[1], box_shape[2]))
    for i in range(box_shape[0] // line_per_box):
        DM_mocks[
            i * line_per_box : (i + 1) * line_per_box, :, :
        ] = saclay_mock_read_box(box_dir, i, name_box)[:, :]
    return DM_mocks

saclay_mock_sky_to_cartesian

saclay_mock_sky_to_cartesian(ra, dec, R, ra0, dec0)

XYZ of a point P (ra,dec,R) in a frame with observer at O, Z along OP, X along ra0, Y along dec0 angles in radians tested that ra,dec, R = box.ComputeRaDecR(R0,ra0,dec0,X,Y,Z) x,y,z = box.ComputeXYZ(ra[0],dec[0],R,ra0,dec0) print x-X,y-Y,z-R0-Z prints ~1E-13 for random inputs

Source code in lelantos/utils.py
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
def saclay_mock_sky_to_cartesian(ra, dec, R, ra0, dec0):
    """
    XYZ of a point P (ra,dec,R) in a frame with
    observer at O, Z along OP, X along ra0, Y along dec0
    angles in radians
    tested that ra,dec, R = box.ComputeRaDecR(R0,ra0,dec0,X,Y,Z)
    x,y,z = box.ComputeXYZ(ra[0],dec[0],R,ra0,dec0)
    print x-X,y-Y,z-R0-Z        prints ~1E-13  for random inputs
    """
    try:
        from SaclayMocks import box as saclay_mock_box
    except:
        from lelantos.saclaymocks import box as saclay_mock_box

        print(
            "SaclayMocks might be updated, we suggest to install SaclayMocks independently"
        )
    X, Y, Z = saclay_mock_box.ComputeXYZ2(
        ra * (np.pi / 180),
        dec * (np.pi / 180),
        R,
        ra0 * (np.pi / 180),
        dec0 * (np.pi / 180),
    )
    return (X, Y, Z)

cut_sky_catalog

cut_sky_catalog(ra, dec, z, ramin=None, ramax=None, decmin=None, decmax=None, zmin=None, zmax=None)

Boolean mask selecting objects inside a sky/redshift footprint.

RA/Dec bounds are given in degrees and compared against ra/dec in radians; unset bounds impose no constraint on that edge.

Parameters:

Name Type Description Default
ra, dec array - like

Object sky angles (radians).

required
z array - like

Object redshift.

required
ramin, ramax, decmin, decmax float

Angular bounds (degrees).

required
zmin, zmax float

Redshift bounds.

required

Returns:

Type Description

numpy.ndarray: Boolean mask of the selected objects.

Source code in lelantos/utils.py
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
def cut_sky_catalog(
    ra, dec, z, ramin=None, ramax=None, decmin=None, decmax=None, zmin=None, zmax=None
):
    """Boolean mask selecting objects inside a sky/redshift footprint.

    RA/Dec bounds are given in degrees and compared against ``ra``/``dec`` in
    radians; unset bounds impose no constraint on that edge.

    Args:
        ra, dec (array-like): Object sky angles (radians).
        z (array-like): Object redshift.
        ramin, ramax, decmin, decmax (float, optional): Angular bounds (degrees).
        zmin, zmax (float, optional): Redshift bounds.

    Returns:
        numpy.ndarray: Boolean mask of the selected objects.
    """
    mask = np.full(ra.shape, True)
    if ramin is not None:
        mask &= ra > np.radians(ramin)
    if ramax is not None:
        mask &= ra < np.radians(ramax)
    if decmin is not None:
        mask &= dec > np.radians(decmin)
    if decmax is not None:
        mask &= dec < np.radians(decmax)
    if zmin is not None:
        mask &= z > zmin
    if zmax is not None:
        mask &= z < zmax
    return mask

init_shared_array

init_shared_array(shape, full_value=np.inf)

Allocate a flat multiprocessing shared array filled with a constant.

Parameters:

Name Type Description Default
shape tuple[int]

Logical array shape (flattened for sharing).

required
full_value float

Fill value. Defaults to np.inf.

inf

Returns:

Type Description

multiprocessing.Array: Shared double array of prod(shape) elements.

Source code in lelantos/utils.py
563
564
565
566
567
568
569
570
571
572
573
574
575
576
def init_shared_array(shape, full_value=np.inf):
    """Allocate a flat multiprocessing shared array filled with a constant.

    Args:
        shape (tuple[int]): Logical array shape (flattened for sharing).
        full_value (float, optional): Fill value. Defaults to ``np.inf``.

    Returns:
        multiprocessing.Array: Shared double array of ``prod(shape)`` elements.
    """
    distance_array = np.full(shape, full_value)
    shared_arr = mp.Array("d", distance_array.flatten())
    del distance_array
    return shared_arr

mp_array_to_numpyarray

mp_array_to_numpyarray(mp_arr)

View a multiprocessing shared array as a numpy array (no copy).

Parameters:

Name Type Description Default
mp_arr Array

Shared array.

required

Returns:

Type Description

numpy.ndarray: A numpy view onto the shared buffer.

Source code in lelantos/utils.py
579
580
581
582
583
584
585
586
587
588
def mp_array_to_numpyarray(mp_arr):
    """View a multiprocessing shared array as a numpy array (no copy).

    Args:
        mp_arr (multiprocessing.Array): Shared array.

    Returns:
        numpy.ndarray: A numpy view onto the shared buffer.
    """
    return np.frombuffer(mp_arr.get_obj())

bin_ndarray

bin_ndarray(ndarray, new_shape, operation='mean')

From : https://stackoverflow.com/questions/8090229/resize-with-averaging-or-rebin-a-numpy-2d-array/29042041 Bins an ndarray in all axes based on the target shape, by summing or averaging. Number of output dimensions must match number of input dimensions. Example


m = np.arange(0,100,1).reshape((10,10)) n = bin_ndarray(m, new_shape=(5,5), operation='sum') print(n) [[ 22 30 38 46 54][102 110 118 126 134] [182 190 198 206 214][262 270 278 286 294] [342 350 358 366 374]]

Source code in lelantos/utils.py
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
def bin_ndarray(ndarray, new_shape, operation="mean"):
    """
    From : https://stackoverflow.com/questions/8090229/resize-with-averaging-or-rebin-a-numpy-2d-array/29042041
    Bins an ndarray in all axes based on the target shape, by summing or
    averaging.
    Number of output dimensions must match number of input dimensions.
    Example
    -------
    >>> m = np.arange(0,100,1).reshape((10,10))
    >>> n = bin_ndarray(m, new_shape=(5,5), operation='sum')
    >>> print(n)
    [[ 22  30  38  46  54]
    [102 110 118 126 134]
    [182 190 198 206 214]
    [262 270 278 286 294]
    [342 350 358 366 374]]
    """
    if not operation.lower() in ["sum", "mean", "average", "avg", "gauss"]:
        raise ValueError("Operation {} not supported.".format(operation))
    if ndarray.ndim != len(new_shape):
        raise ValueError("Shape mismatch: {} -> {}".format(ndarray.shape, new_shape))
    compression_pairs = [(d, c // d) for d, c in zip(new_shape, ndarray.shape)]
    flattened = [l for p in compression_pairs for l in p]
    ndarray = ndarray.reshape(flattened)
    for i in range(len(new_shape)):
        if operation.lower() == "sum":
            ndarray = ndarray.sum(-1 * (i + 1))
        elif operation.lower() in ["mean", "average", "avg"]:
            ndarray = ndarray.mean(-1 * (i + 1))
        elif operation.lower() in ["gauss"]:
            if i != 0:
                raise KeyError("gaussian mean is not available for dim higher than 1")
            from scipy import signal

            newndarray = np.zeros(new_shape)
            gaussian_weights = signal.gaussian(
                int(ndarray.shape[1]), int(ndarray.shape[1]) / 4
            )
            for j in range(len(ndarray)):
                newndarray[j] = np.average(ndarray[j], axis=0, weights=gaussian_weights)
            ndarray = newndarray
    return ndarray

interpolate_map

interpolate_map(interpolation_method, map_array, coord)

Sample a 3D map at 3D-gridded coordinates.

Parameters:

Name Type Description Default
interpolation_method str

"NEAREST", "LINEAR" or "SPLINE".

required
map_array ndarray

The 3D map to sample.

required
coord ndarray

Coordinate grid of shape (a, b, c, 3).

required

Returns:

Type Description

numpy.ndarray: Sampled values of shape (a, b, c).

Raises:

Type Description
ValueError

If interpolation_method is not supported.

Source code in lelantos/utils.py
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
def interpolate_map(interpolation_method, map_array, coord):
    """Sample a 3D map at 3D-gridded coordinates.

    Args:
        interpolation_method (str): ``"NEAREST"``, ``"LINEAR"`` or ``"SPLINE"``.
        map_array (numpy.ndarray): The 3D map to sample.
        coord (numpy.ndarray): Coordinate grid of shape ``(a, b, c, 3)``.

    Returns:
        numpy.ndarray: Sampled values of shape ``(a, b, c)``.

    Raises:
        ValueError: If ``interpolation_method`` is not supported.
    """
    if interpolation_method.upper() == "NEAREST":
        coord = np.around(coord, decimals=0).astype(int)
        DM_map = map_array[coord[:, :, :, 0], coord[:, :, :, 1], coord[:, :, :, 2]]
    elif interpolation_method.upper() == "LINEAR":
        points = coord.reshape(coord.shape[0] * coord.shape[1] * coord.shape[2], 3)
        DM_map = map_coordinates(map_array, np.transpose(points), order=1).reshape(
            (coord.shape[0], coord.shape[1], coord.shape[2])
        )
    elif interpolation_method.upper() == "SPLINE":
        points = coord.reshape(coord.shape[0] * coord.shape[1] * coord.shape[2], 3)
        DM_map = map_coordinates(map_array, np.transpose(points), order=2).reshape(
            (coord.shape[0], coord.shape[1], coord.shape[2])
        )
    else:
        raise ValueError(
            "Please select NEAREST, LINEAR or SPLINE as interpolation_method"
        )
    return DM_map

interpolate_and_fill_map

interpolate_and_fill_map(interpolation_method, map_array, coord)

Sample a 3D map at a flat list of 3D coordinates.

Parameters:

Name Type Description Default
interpolation_method str

"NEAREST", "LINEAR" or "SPLINE".

required
map_array ndarray

The 3D map to sample.

required
coord ndarray

Coordinates of shape (N, 3).

required

Returns:

Type Description

numpy.ndarray: Sampled values of length N.

Raises:

Type Description
ValueError

If interpolation_method is not supported.

Source code in lelantos/utils.py
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
def interpolate_and_fill_map(interpolation_method, map_array, coord):
    """Sample a 3D map at a flat list of 3D coordinates.

    Args:
        interpolation_method (str): ``"NEAREST"``, ``"LINEAR"`` or ``"SPLINE"``.
        map_array (numpy.ndarray): The 3D map to sample.
        coord (numpy.ndarray): Coordinates of shape ``(N, 3)``.

    Returns:
        numpy.ndarray: Sampled values of length ``N``.

    Raises:
        ValueError: If ``interpolation_method`` is not supported.
    """
    if interpolation_method.upper() == "NEAREST":
        coord_nearest = np.around(coord, decimals=0).astype(int)
        map_to_fill = map_array[
            coord_nearest[:, 0], coord_nearest[:, 1], coord_nearest[:, 2]
        ]
        del coord_nearest
    elif interpolation_method.upper() == "LINEAR":
        map_to_fill = map_coordinates(map_array, np.transpose(coord), order=1)
    elif interpolation_method.upper() == "SPLINE":
        map_to_fill = map_coordinates(map_array, np.transpose(coord), order=2)
    else:
        raise ValueError(
            "Please select NEAREST, LINEAR or SPLINE as interpolation_method"
        )
    return map_to_fill

gaussian_smoothing

gaussian_smoothing(mapdata, sigma)

Gaussian-smooth an array.

Parameters:

Name Type Description Default
mapdata ndarray

Input array.

required
sigma float | sequence

Gaussian kernel standard deviation.

required

Returns:

Type Description

numpy.ndarray: The smoothed array.

Source code in lelantos/utils.py
700
701
702
703
704
705
706
707
708
709
710
711
def gaussian_smoothing(mapdata, sigma):
    """Gaussian-smooth an array.

    Args:
        mapdata (numpy.ndarray): Input array.
        sigma (float | sequence): Gaussian kernel standard deviation.

    Returns:
        numpy.ndarray: The smoothed array.
    """
    gaussian_map = gaussian_filter(mapdata, sigma)
    return gaussian_map

create_log

create_log(log_level='info')

Create and configure a stream :class:Logger.

Parameters:

Name Type Description Default
log_level str

"info", "debug" or "warning".

'info'

Returns:

Name Type Description
Logger

A logger writing to the console.

Source code in lelantos/utils.py
833
834
835
836
837
838
839
840
841
842
843
844
def create_log(log_level="info"):
    """Create and configure a stream :class:`Logger`.

    Args:
        log_level (str, optional): ``"info"``, ``"debug"`` or ``"warning"``.

    Returns:
        Logger: A logger writing to the console.
    """
    log = Logger(log_level=log_level)
    log.setup_logging()
    return log

create_report_log

create_report_log(name='Python_Report', log_level='info')

Create and configure a file (report) :class:Logger.

Parameters:

Name Type Description Default
name str

Report file path. Defaults to "Python_Report".

'Python_Report'
log_level str

"info", "debug" or "warning".

'info'

Returns:

Name Type Description
Logger

A logger writing to name.

Source code in lelantos/utils.py
847
848
849
850
851
852
853
854
855
856
857
858
859
def create_report_log(name="Python_Report", log_level="info"):
    """Create and configure a file (report) :class:`Logger`.

    Args:
        name (str, optional): Report file path. Defaults to ``"Python_Report"``.
        log_level (str, optional): ``"info"``, ``"debug"`` or ``"warning"``.

    Returns:
        Logger: A logger writing to ``name``.
    """
    log = Logger(name=name, log_level=log_level)
    log.setup_report_logging()
    return log

latex_float

latex_float(float_input, decimals_input='{0:.2g}')

example use: import matplotlib.pyplot as plt plt.figure(),plt.clf() plt.plot(np.array([1,2.]),'ko-',label="$P_0="+latex_float(7.63e-5)+'$'), plt.legend()

Source code in lelantos/utils.py
974
975
976
977
978
979
980
981
982
983
984
985
986
987
def latex_float(float_input, decimals_input="{0:.2g}"):
    """
    example use:
    import matplotlib.pyplot as plt
    plt.figure(),plt.clf()
    plt.plot(np.array([1,2.]),'ko-',label="$P_0="+latex_float(7.63e-5)+'$'),
    plt.legend()
    """
    float_str = decimals_input.format(float_input)
    if "e" in float_str:
        base, exponent = float_str.split("e")
        return r"{0} \times 10^{{{1}}}".format(base, int(exponent))
    else:
        return float_str

return_key

return_key(dictionary, string, default_value)

Return dictionary[string] if present, else a default.

Parameters:

Name Type Description Default
dictionary dict

Source mapping.

required
string

Key to look up.

required
default_value

Value returned when the key is absent.

required

Returns:

Type Description

The value at string or default_value.

Source code in lelantos/utils.py
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
def return_key(dictionary, string, default_value):
    """Return ``dictionary[string]`` if present, else a default.

    Args:
        dictionary (dict): Source mapping.
        string: Key to look up.
        default_value: Value returned when the key is absent.

    Returns:
        The value at ``string`` or ``default_value``.
    """
    return dictionary[string] if string in dictionary.keys() else default_value

dump

dump(obj, file, protocol=4)

Pickle obj to file using protocol 4.

Parameters:

Name Type Description Default
obj

Object to serialise.

required
file

Writable binary file object.

required
protocol int

Pickle protocol. Defaults to 4.

4
Source code in lelantos/utils.py
1040
1041
1042
1043
1044
1045
1046
1047
1048
def dump(obj, file, protocol=4):
    """Pickle ``obj`` to ``file`` using protocol 4.

    Args:
        obj: Object to serialise.
        file: Writable binary file object.
        protocol (int, optional): Pickle protocol. Defaults to 4.
    """
    ForkingPickler4(file, protocol).dump(obj)

patch_mp_connection_bpo_17560

patch_mp_connection_bpo_17560(log=None)

Apply PR-10305 / bpo-17560 connection send/receive max size update

See the original issue at https://bugs.python.org/issue17560 and https://github.com/python/cpython/pull/10305 for the pull request.

This only supports Python versions 3.3 - 3.7, this function does nothing for Python versions outside of that range.

Source code in lelantos/utils.py
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
def patch_mp_connection_bpo_17560(log=None):
    """Apply PR-10305 / bpo-17560 connection send/receive max size update

    See the original issue at https://bugs.python.org/issue17560 and
    https://github.com/python/cpython/pull/10305 for the pull request.

    This only supports Python versions 3.3 - 3.7, this function
    does nothing for Python versions outside of that range.

    """
    patchname = "Multiprocessing connection patch for bpo-17560"
    if not (3, 3) < sys.version_info < (3, 8):
        if log is not None:
            log.add(
                patchname + " not applied, not an applicable Python version: %s",
                sys.version,
            )
        return

    from multiprocessing.connection import Connection

    orig_send_bytes = Connection._send_bytes
    orig_recv_bytes = Connection._recv_bytes
    if (
        orig_send_bytes.__code__.co_filename == __file__
        and orig_recv_bytes.__code__.co_filename == __file__
    ):
        if log is not None:
            log.add(patchname + " already applied, skipping")
        return

    @functools.wraps(orig_send_bytes)
    def send_bytes(self, buf):
        n = len(buf)
        if n > 0x7FFFFFFF:
            pre_header = struct.pack("!i", -1)
            header = struct.pack("!Q", n)
            self._send(pre_header)
            self._send(header)
            self._send(buf)
        else:
            orig_send_bytes(self, buf)

    @functools.wraps(orig_recv_bytes)
    def recv_bytes(self, maxsize=None):
        buf = self._recv(4)
        (size,) = struct.unpack("!i", buf.getvalue())
        if size == -1:
            buf = self._recv(8)
            (size,) = struct.unpack("!Q", buf.getvalue())
        if maxsize is not None and size > maxsize:
            return None
        return self._recv(size)

    Connection._send_bytes = send_bytes
    Connection._recv_bytes = recv_bytes

    if log is not None:
        log.add(patchname + " applied")

hist_profile

hist_profile(x, y, bins, range_x, range_y, outlier_insensitive=False)

Binned mean (or median) profile of y versus x with errors.

Parameters:

Name Type Description Default
x array - like

Values binned along the x-axis.

required
y array - like

Values averaged within each x-bin.

required
bins int

Number of x-bins.

required
range_x sequence

(xmin, xmax) binning range.

required
range_y sequence

(ymin, ymax) pre-selection on y.

required
outlier_insensitive bool

Use median and a percentile-based spread instead of mean and standard deviation.

False

Returns:

Name Type Description
tuple

(bin_centers, means, errors).

Source code in lelantos/utils.py
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
def hist_profile(x, y, bins, range_x, range_y, outlier_insensitive=False):
    """Binned mean (or median) profile of ``y`` versus ``x`` with errors.

    Args:
        x (array-like): Values binned along the x-axis.
        y (array-like): Values averaged within each x-bin.
        bins (int): Number of x-bins.
        range_x (sequence): ``(xmin, xmax)`` binning range.
        range_y (sequence): ``(ymin, ymax)`` pre-selection on ``y``.
        outlier_insensitive (bool, optional): Use median and a percentile-based
            spread instead of mean and standard deviation.

    Returns:
        tuple: ``(bin_centers, means, errors)``.
    """
    w = (y > range_y[0]) & (y < range_y[1])
    if outlier_insensitive:
        means_result = binned_statistic(
            x[w], y[w], bins=bins, range=range_x, statistic="median"
        )
        outlier_insensitive_std = (
            lambda x: (
                np.nanpercentile(x, 84.135, axis=0)
                - np.nanpercentile(x, 15.865, axis=0)
            )
            / 2
        )
        std_result = binned_statistic(
            x[w], y[w], bins=bins, range=range_x, statistic=outlier_insensitive_std
        )
        nb_entries_result = binned_statistic(
            x[w], y[w], bins=bins, range=range_x, statistic="count"
        )

    else:
        means_result = binned_statistic(
            x[w], y[w], bins=bins, range=range_x, statistic="mean"
        )
        std_result = binned_statistic(
            x[w], y[w], bins=bins, range=range_x, statistic="std"
        )
        nb_entries_result = binned_statistic(
            x[w], y[w], bins=bins, range=range_x, statistic="count"
        )

    means = means_result.statistic
    std = std_result.statistic
    nb_entries = nb_entries_result.statistic

    errors = std / np.sqrt(nb_entries)

    bin_edges = means_result.bin_edges
    bin_centers = (bin_edges[:-1] + bin_edges[1:]) / 2.0
    return (bin_centers, means, errors)

plot_histo

plot_histo(value, value_name, name, dotted=False, **kwargs)

Draw a histogram of value on the current axes.

Binning, colour, normalisation, etc. are read from kwargs keys prefixed by value_name (see the plot_args config dicts).

Parameters:

Name Type Description Default
value array - like

Values to histogram.

required
value_name str

Prefix used to look up styling in kwargs.

required
name str

Base output name (suffixed for norm/cumulative).

required
dotted bool

Draw a dashed outline-only histogram.

False
**kwargs

Styling options ({value_name}_bins, _color ...).

{}

Returns:

Name Type Description
tuple

(name, n, bins, patches) — updated name and matplotlib

histogram outputs.

Source code in lelantos/utils.py
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
def plot_histo(value, value_name, name, dotted=False, **kwargs):
    """Draw a histogram of ``value`` on the current axes.

    Binning, colour, normalisation, etc. are read from ``kwargs`` keys prefixed
    by ``value_name`` (see the ``plot_args`` config dicts).

    Args:
        value (array-like): Values to histogram.
        value_name (str): Prefix used to look up styling in ``kwargs``.
        name (str): Base output name (suffixed for norm/cumulative).
        dotted (bool, optional): Draw a dashed outline-only histogram.
        **kwargs: Styling options (``{value_name}_bins``, ``_color`` ...).

    Returns:
        tuple: ``(name, n, bins, patches)`` — updated name and matplotlib
        histogram outputs.
    """
    nb_bins = return_key(kwargs, f"{value_name}_bins", 50)
    value_min = return_key(kwargs, f"{value_name}_value_min", np.min(value))
    value_max = return_key(kwargs, f"{value_name}_value_max", np.max(value))
    alpha = return_key(kwargs, f"{value_name}_alpha", 1.0)
    histtype = return_key(kwargs, f"{value_name}_histtype", "bar")
    linestyle = return_key(kwargs, f"{value_name}_linestyle", None)
    lw = return_key(kwargs, f"{value_name}_linewidth", 0)
    ec = return_key(kwargs, f"{value_name}_edgecolor", None)
    color = return_key(kwargs, f"{value_name}_color", None)
    if dotted:
        linestyle = "dashed"
        color = None
        facecolor = "None"
        lw = 2
        ec = "k"

    norm = return_key(kwargs, f"{value_name}_norm", False)
    cumulative = return_key(kwargs, f"{value_name}_cumulative", False)
    log = return_key(kwargs, f"{value_name}_log", False)

    if norm:
        name = name + "_normalized"
    if cumulative:
        name = name + "_cumulative"

    if (value_min is None) | (value_min is None):
        bins = nb_bins
    else:
        bins = np.linspace(value_min, value_max, nb_bins)
    if dotted:
        (n, bins, patches) = plt.hist(
            value,
            bins,
            alpha=alpha,
            histtype=histtype,
            linestyle=linestyle,
            ec=ec,
            density=norm,
            cumulative=cumulative,
            facecolor=facecolor,
            log=log,
            color=color,
            lw=lw,
        )
    else:
        (n, bins, patches) = plt.hist(
            value,
            bins,
            alpha=alpha,
            histtype=histtype,
            linestyle=linestyle,
            ec=ec,
            density=norm,
            cumulative=cumulative,
            log=log,
            color=color,
            lw=lw,
        )
    return (name, n, bins, patches)

save_histo

save_histo(pwd, value, value_name, name, comparison=None, comparison_legend=None, **kwargs)

Plot and save a histogram (with optional comparison series) as a PDF.

Parameters:

Name Type Description Default
pwd str

Output directory.

required
value array - like

Values to histogram.

required
value_name str

Quantity name (styling prefix + axis label).

required
name str

Base output name.

required
comparison list[array - like]

Extra series to overplot.

None
comparison_legend list[str]

Legend labels.

None
**kwargs

Styling options.

{}
Source code in lelantos/utils.py
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
def save_histo(
    pwd, value, value_name, name, comparison=None, comparison_legend=None, **kwargs
):
    """Plot and save a histogram (with optional comparison series) as a PDF.

    Args:
        pwd (str): Output directory.
        value (array-like): Values to histogram.
        value_name (str): Quantity name (styling prefix + axis label).
        name (str): Base output name.
        comparison (list[array-like], optional): Extra series to overplot.
        comparison_legend (list[str], optional): Legend labels.
        **kwargs: Styling options.
    """
    xlabel = return_key(kwargs, f"{value_name}_xlabel", value_name)
    ylabel = return_key(kwargs, f"{value_name}_ylabel", "#")
    min_lim = return_key(kwargs, f"{value_name}_min_lim", np.min(value))
    max_lim = return_key(kwargs, f"{value_name}_max_lim", np.max(value))
    fontsize = return_key(kwargs, f"{value_name}_fontsize", 14)
    fontsize_scale = return_key(kwargs, f"{value_name}_fontscalesize", 14)
    figsize = return_key(kwargs, f"{value_name}_figsize", (8, 5))
    comparison_dotted = return_key(kwargs, f"{value_name}_comparison_dotted", None)
    plt.figure(figsize=figsize)
    name_out, n, bins, patches = plot_histo(value, value_name, name, **kwargs)
    if comparison is not None:
        for i in range(len(comparison)):
            dotted = False
            if comparison_dotted is not None:
                if comparison_dotted == i:
                    dotted = True
            plot_histo(comparison[i], value_name, name, dotted=dotted, **kwargs)
        if comparison_legend is not None:
            plt.legend(comparison_legend, fontsize=fontsize)
    plt.ylabel(ylabel, fontsize=fontsize)
    plt.xlabel(xlabel, fontsize=fontsize)
    ax = plt.gca()
    ax.tick_params(axis="x", labelsize=fontsize_scale)
    ax.tick_params(axis="y", labelsize=fontsize_scale)

    if (min_lim is not None) & (max_lim is not None):
        plt.xlim([min_lim, max_lim])

    plt.tight_layout()
    plt.savefig(os.path.join(pwd, f"{name_out}_histo_{value_name}.pdf"), format="pdf")

plot_mean_redshift_dependence

plot_mean_redshift_dependence(value, redshift, value_name, name, **kwargs)

Plot the binned mean of value versus redshift (or wavelength).

The x-axis can be converted to observed or rest-frame Lyman-alpha wavelength via the {value_name}_lambda_obs / _lambda_rest kwargs.

Parameters:

Name Type Description Default
value array - like

Quantity to average.

required
redshift array - like

Redshift of each value.

required
value_name str

Styling/label prefix.

required
name str

Base output name.

required
**kwargs

Binning/labelling options.

{}

Returns:

Name Type Description
str

The (possibly suffixed) output name.

Source code in lelantos/utils.py
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
def plot_mean_redshift_dependence(value, redshift, value_name, name, **kwargs):
    """Plot the binned mean of ``value`` versus redshift (or wavelength).

    The x-axis can be converted to observed or rest-frame Lyman-alpha
    wavelength via the ``{value_name}_lambda_obs`` / ``_lambda_rest`` kwargs.

    Args:
        value (array-like): Quantity to average.
        redshift (array-like): Redshift of each value.
        value_name (str): Styling/label prefix.
        name (str): Base output name.
        **kwargs: Binning/labelling options.

    Returns:
        str: The (possibly suffixed) output name.
    """
    ax = return_key(kwargs, f"{value_name}_ax", None)
    nb_bins = return_key(kwargs, f"{value_name}_z_bins", 50)
    ls = return_key(kwargs, f"{value_name}_linestyle", None)
    color = return_key(kwargs, f"{value_name}_color", None)
    marker = return_key(kwargs, f"{value_name}_marker", ".")
    lambda_obs = return_key(kwargs, f"{value_name}_lambda_obs", False)
    lambda_rest = return_key(kwargs, f"{value_name}_lambda_rest", False)
    multiplicative_coef = return_key(kwargs, f"{value_name}_multiplicative_coef", None)

    outlier_insensitive = return_key(kwargs, f"{value_name}_outlier_insensitive", False)

    if ax is None:
        ax = plt.gca()

    if multiplicative_coef is not None:
        value = value * multiplicative_coef

    if lambda_obs:
        redshift = (1 + redshift) * lambdaLy

    elif lambda_rest:
        redshift_qso = return_key(kwargs, f"{value_name}_redshift_qso", None)
        if redshift_qso is None:
            raise ValueError(
                """You have chosen to convert your mean redshift
                                dependence plot rest frame wavelength but no
                                QSO redshift was provided"""
            )
        redshift = ((1 + redshift) / (1 + redshift_qso)) * lambdaLy

    z_min = return_key(kwargs, f"{value_name}_zmin", np.min(redshift))
    z_max = return_key(kwargs, f"{value_name}_zmax", np.max(redshift))
    range_x = np.array([z_min, z_max])

    bin_centers, means, errors = hist_profile(
        redshift,
        value,
        nb_bins,
        range_x,
        [np.min(value), np.max(value)],
        outlier_insensitive=outlier_insensitive,
    )

    ax.errorbar(bin_centers, means, errors, color=color, ls=ls, marker=marker)

    if outlier_insensitive:
        name = name + "_outlier_insensitive"

    return name

save_mean_redshift_dependence

save_mean_redshift_dependence(pwd, value, redshift, value_name, name, comparison=None, comparison_redshift=None, comparison_legend=None, **kwargs)

Plot and save the mean-vs-redshift dependence (with comparisons) as PDF.

Parameters:

Name Type Description Default
pwd str

Output directory.

required
value array - like

Quantity to average.

required
redshift array - like

Redshift of each value.

required
value_name str

Styling/label prefix.

required
name str

Base output name.

required
comparison list[array - like]

Extra series to overplot.

None
comparison_redshift list[array - like]

Redshifts of the comparison series.

None
comparison_legend list[str]

Legend labels.

None
**kwargs

Binning/labelling options.

{}

Raises:

Type Description
ValueError

If both observed- and rest-frame wavelength are requested.

Source code in lelantos/utils.py
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
def save_mean_redshift_dependence(
    pwd,
    value,
    redshift,
    value_name,
    name,
    comparison=None,
    comparison_redshift=None,
    comparison_legend=None,
    **kwargs,
):
    """Plot and save the mean-vs-redshift dependence (with comparisons) as PDF.

    Args:
        pwd (str): Output directory.
        value (array-like): Quantity to average.
        redshift (array-like): Redshift of each value.
        value_name (str): Styling/label prefix.
        name (str): Base output name.
        comparison (list[array-like], optional): Extra series to overplot.
        comparison_redshift (list[array-like], optional): Redshifts of the
            comparison series.
        comparison_legend (list[str], optional): Legend labels.
        **kwargs: Binning/labelling options.

    Raises:
        ValueError: If both observed- and rest-frame wavelength are requested.
    """
    ylabel = return_key(kwargs, f"{value_name}_xlabel", value_name)
    lambda_obs = return_key(kwargs, f"{value_name}_lambda_obs", False)
    lambda_rest = return_key(kwargs, f"{value_name}_lambda_rest", False)
    if (lambda_obs) & (lambda_rest):
        raise ValueError(
            f"""You have chosen to convert your mean redshift
                             dependence plot to both rest frame and observed
                             wavelength. Please choose {value_name}_lambda_obs
                             or {value_name}_lambda_rest"""
        )
    if lambda_obs:
        default_xlabel = "observed wavelength"
    elif lambda_rest:
        default_xlabel = "rest frame wavelength"
    else:
        default_xlabel = "redshift"
    xlabel = return_key(kwargs, f"{value_name}_ylabel", default_xlabel)

    plt.figure()
    name_out = plot_mean_redshift_dependence(
        value, redshift, value_name, name, **kwargs
    )
    if comparison is not None:
        for i in range(len(comparison)):
            plot_mean_redshift_dependence(
                comparison[i], comparison_redshift[i], value_name, name, **kwargs
            )
        if comparison_legend is not None:
            plt.legend(comparison_legend)
    plt.ylabel(ylabel)
    plt.xlabel(xlabel)
    plt.savefig(
        os.path.join(pwd, f"{name_out}_mean_redshift_dependence_{value_name}.pdf"),
        format="pdf",
    )

plot_redshift_dependence

plot_redshift_dependence(value, redshift, value_name, name, **kwargs)

Scatter value versus redshift over a redshift window.

Parameters:

Name Type Description Default
value array - like

Quantity to plot.

required
redshift array - like

Redshift of each value.

required
value_name str

Styling/label prefix.

required
name str

Base output name.

required
**kwargs

{value_name}_zmin / _zmax window options.

{}

Returns:

Name Type Description
str

The output name.

Source code in lelantos/utils.py
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
def plot_redshift_dependence(value, redshift, value_name, name, **kwargs):
    """Scatter ``value`` versus redshift over a redshift window.

    Args:
        value (array-like): Quantity to plot.
        redshift (array-like): Redshift of each value.
        value_name (str): Styling/label prefix.
        name (str): Base output name.
        **kwargs: ``{value_name}_zmin`` / ``_zmax`` window options.

    Returns:
        str: The output name.
    """
    z_min = return_key(kwargs, f"{value_name}_zmin", np.min(redshift))
    z_max = return_key(kwargs, f"{value_name}_zmax", np.max(redshift))

    mask = (redshift >= z_min) & (redshift < z_max)
    plt.scatter(redshift[mask], value[mask])
    return name

save_redshift_dependence

save_redshift_dependence(pwd, value, redshift, value_name, name, comparison=None, comparison_redshift=None, comparison_legend=None, **kwargs)

Plot and save the value-vs-redshift scatter (with comparisons) as PDF.

Parameters:

Name Type Description Default
pwd str

Output directory.

required
value array - like

Quantity to plot.

required
redshift array - like

Redshift of each value.

required
value_name str

Styling/label prefix.

required
name str

Base output name.

required
comparison list[array - like]

Extra series to overplot.

None
comparison_redshift list[array - like]

Redshifts of the comparison series.

None
comparison_legend list[str]

Legend labels.

None
**kwargs

Plot options.

{}
Source code in lelantos/utils.py
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
def save_redshift_dependence(
    pwd,
    value,
    redshift,
    value_name,
    name,
    comparison=None,
    comparison_redshift=None,
    comparison_legend=None,
    **kwargs,
):
    """Plot and save the value-vs-redshift scatter (with comparisons) as PDF.

    Args:
        pwd (str): Output directory.
        value (array-like): Quantity to plot.
        redshift (array-like): Redshift of each value.
        value_name (str): Styling/label prefix.
        name (str): Base output name.
        comparison (list[array-like], optional): Extra series to overplot.
        comparison_redshift (list[array-like], optional): Redshifts of the
            comparison series.
        comparison_legend (list[str], optional): Legend labels.
        **kwargs: Plot options.
    """
    ylabel = return_key(kwargs, f"{value_name}_xlabel", value_name)
    xlabel = return_key(kwargs, f"{value_name}_ylabel", "redshift")

    plt.figure()
    name_out = plot_redshift_dependence(value, redshift, value_name, name, **kwargs)
    if comparison is not None:
        for i in range(len(comparison)):
            plot_redshift_dependence(
                comparison[i], comparison_redshift[i], value_name, name, **kwargs
            )
        if comparison_legend is not None:
            plt.legend(comparison_legend)
    plt.ylabel(ylabel)
    plt.xlabel(xlabel)
    plt.savefig(
        os.path.join(pwd, f"{name_out}_redshift_dependence_{value_name}.pdf"),
        format="pdf",
    )

plot_ra_dec

plot_ra_dec(ra, dec, name, **kwargs)

Scatter objects in the RA/Dec plane, optionally outlining RA sub-cuts.

Parameters:

Name Type Description Default
ra, dec array - like

Object sky angles.

required
name str

Base output name.

required
**kwargs

nb_cut (number of RA sub-regions to outline) and figure options.

{}

Returns:

Name Type Description
str

The output name.

Source code in lelantos/utils.py
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
def plot_ra_dec(ra, dec, name, **kwargs):
    """Scatter objects in the RA/Dec plane, optionally outlining RA sub-cuts.

    Args:
        ra, dec (array-like): Object sky angles.
        name (str): Base output name.
        **kwargs: ``nb_cut`` (number of RA sub-regions to outline) and figure
            options.

    Returns:
        str: The output name.
    """
    nb_cut = return_key(kwargs, "nb_cut", None)
    figsize = return_key(kwargs, "ra_dec_figsize", (7, 3.5))
    plt.figure(figsize=figsize)

    if nb_cut is not None:
        ramax, ramin, decmax, decmin = np.max(ra), np.min(ra), np.max(dec), np.min(dec)
        interval_ra_array = []
        for cut in range(nb_cut):
            interval_ra_array.append(
                [
                    ((cut) / (nb_cut)) * (ramax - ramin) + ramin,
                    ((cut + 1) / (nb_cut)) * (ramax - ramin) + ramin,
                ]
            )
        for i in range(len(interval_ra_array)):
            plt.plot(
                [interval_ra_array[i][0], interval_ra_array[i][1]],
                [decmin, decmin],
                color="orange",
                linewidth=2,
            )
            plt.plot(
                [interval_ra_array[i][0], interval_ra_array[i][1]],
                [decmax, decmax],
                color="orange",
                linewidth=2,
            )
            plt.plot(
                [interval_ra_array[i][0], interval_ra_array[i][0]],
                [decmin, decmax],
                color="orange",
                linewidth=2,
            )
            plt.plot(
                [interval_ra_array[i][1], interval_ra_array[i][1]],
                [decmin, decmax],
                color="orange",
                linewidth=2,
            )

    plt.plot(ra, dec, "b.", markersize=1.5)
    return name

save_ra_dec

save_ra_dec(pwd, ra, dec, name, comparison_ra=None, comparison_dec=None, comparison_legend=None, **kwargs)

Plot and save the RA/Dec diagram (with optional comparison) as a PDF.

Parameters:

Name Type Description Default
pwd str

Output directory.

required
ra, dec array - like

Object sky angles.

required
name str

Base output name.

required
comparison_ra list[array - like]

Comparison RA series.

None
comparison_dec list[array - like]

Comparison Dec series.

None
comparison_legend list[str]

Legend labels.

None
**kwargs

Axis-limit / label / styling options.

{}
Source code in lelantos/utils.py
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
def save_ra_dec(
    pwd,
    ra,
    dec,
    name,
    comparison_ra=None,
    comparison_dec=None,
    comparison_legend=None,
    **kwargs,
):
    """Plot and save the RA/Dec diagram (with optional comparison) as a PDF.

    Args:
        pwd (str): Output directory.
        ra, dec (array-like): Object sky angles.
        name (str): Base output name.
        comparison_ra (list[array-like], optional): Comparison RA series.
        comparison_dec (list[array-like], optional): Comparison Dec series.
        comparison_legend (list[str], optional): Legend labels.
        **kwargs: Axis-limit / label / styling options.
    """
    grid = return_key(kwargs, "ra_dec_grid", True)
    fontsize = return_key(kwargs, "ra_dec_fontsize", 13)
    fontsize_scale = return_key(kwargs, "ra_dec_fontscalesize", 13)
    ra_min_lim = return_key(kwargs, "ra_dec_ra_min_lim", np.min(ra))
    ra_max_lim = return_key(kwargs, "ra_dec_ra_max_lim", np.max(ra))
    dec_min_lim = return_key(kwargs, "ra_dec_dec_min_lim", np.min(dec))
    dec_max_lim = return_key(kwargs, "ra_dec_dec_max_lim", np.max(dec))
    deg = return_key(kwargs, "deg", True)
    if deg:
        label_angle = "deg"
    else:
        label_angle = "rad"
    ylabel = return_key(kwargs, "ra_dec_ylabel", f"DEC [{label_angle}] (J2000)")
    xlabel = return_key(kwargs, "ra_dec_xlabel", f"RA [{label_angle}] (J2000)")

    name_out = plot_ra_dec(ra, dec, name, **kwargs)
    if comparison_ra is not None:
        for i in range(len(comparison_ra)):
            plot_redshift_dependence(
                comparison_ra[i], comparison_dec[i], name, **kwargs
            )
        if comparison_legend is not None:
            plt.legend(comparison_legend)
    plt.xlabel(xlabel, fontsize=fontsize)
    plt.ylabel(ylabel, fontsize=fontsize)
    ax = plt.gca()
    ax.tick_params(axis="x", labelsize=fontsize_scale)
    ax.tick_params(axis="y", labelsize=fontsize_scale)
    plt.xlim([ra_min_lim, ra_max_lim])
    plt.ylim([dec_min_lim, dec_max_lim])
    if grid:
        plt.grid()
    plt.tight_layout()
    plt.savefig(os.path.join(pwd, f"{name_out}_RA-DEC_diagram.pdf"), format="pdf")