Skip to content

Coordinates

This module contains a series of functions which are used to calculate coordinate arrays, apply transformations to coordinate arrays, and convert between Cartesian and polar coordinates.

pixel_coords

Returns a paraxial set of 2d coordinates for each pixel center.

Parameters:

Name Type Description Default
npixels int

The output size of the coordinates array to generate.

required
diameter float

The diameter of the coordinates array to generate.

required
polar bool = False

Output the coordinates in polar (r, phi) coordinates.

False

Returns:

Name Type Description
coordinates Array

The array of pixel center coordinates.

Source code in src/dLux/utils/coordinates.py
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
def pixel_coords(npixels: int, diameter: float, polar: bool = False) -> Array:
    """
    Returns a paraxial set of 2d coordinates for each pixel center.

    Parameters
    ----------
    npixels : int
        The output size of the coordinates array to generate.
    diameter : float
        The diameter of the coordinates array to generate.
    polar : bool = False
        Output the coordinates in polar (r, phi) coordinates.

    Returns
    -------
    coordinates : Array
        The array of pixel center coordinates.
    """
    coords = nd_coords((npixels,) * 2, (diameter / npixels,) * 2)
    if polar:
        return cart2polar(coords)
    return coords

nd_coords

Returns a set of nd pixel center coordinates, with an optional offset. Each dimension can have a different number of pixels, pixel scale and offset by passing in tuples of values: nd_coords((10, 10), (1, 2), (0, 1)). pixel scale and offset can also be passed in as floats to apply those values to all dimensions, ie: nd_coords((10, 10), 1, 0).

The indexing argument is the same as in numpy.meshgrid., i.e.: Giving the string ‘ij’ returns a meshgrid with matrix indexing, while ‘xy’ returns a meshgrid with Cartesian indexing. In the 2-D case with inputs of length M and N, the outputs are of shape (N, M) for ‘xy’ indexing and (M, N) for ‘ij’ indexing. In the 3-D case with inputs of length M, N and P, outputs are of shape (N, M, P) for ‘xy’ indexing and (M, N, P) for ‘ij’ indexing.

Parameters:

Name Type Description Default
npixels Union[int, tuple]

The number of pixels in each dimension.

required
pixel_scales Union[tuple, float] = 1.

The pixel_scales of each dimension. If a tuple, the length of the tuple must match the number of dimensions. If a float, the same scale is applied to all dimensions.

1.0
offsets Union[tuple, float] = 0.

The offset of the pixel centers in each dimension. If a tuple, the length of the tuple must match the number of dimensions. If a float, the same offset is applied to all dimensions. set to 0.

0.0
indexing str = 'xy'

The indexing of the output. Default is 'xy'. See numpy.meshgrid for more details.

'xy'

Returns:

Name Type Description
coordinates Array

The positions of the pixel centers in the given dimensions.

Source code in src/dLux/utils/coordinates.py
167
168
169
170
171
172
173
174
175
176
177
178
179
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
def nd_coords(
    npixels: Union[int, tuple],
    pixel_scales: Union[tuple, float] = 1.0,
    offsets: Union[tuple, float] = 0.0,
    indexing: str = "xy",
) -> Array:
    """
    Returns a set of nd pixel center coordinates, with an optional offset. Each
    dimension can have a different number of pixels, pixel scale and offset by passing
    in tuples of values: `nd_coords((10, 10), (1, 2), (0, 1))`. pixel scale and offset
    can also be passed in as floats to apply those values to all dimensions, ie:
    `nd_coords((10, 10), 1, 0)`.

    The indexing argument is the same as in numpy.meshgrid., i.e.: Giving the
    string ‘ij’ returns a meshgrid with matrix indexing, while ‘xy’ returns a
    meshgrid with Cartesian indexing. In the 2-D case with inputs of length M
    and N, the outputs are of shape (N, M) for ‘xy’ indexing and (M, N) for
    ‘ij’ indexing. In the 3-D case with inputs of length M, N and P, outputs
    are of shape (N, M, P) for ‘xy’ indexing and (M, N, P) for ‘ij’ indexing.

    Parameters
    ----------
    npixels : Union[int, tuple]
        The number of pixels in each dimension.
    pixel_scales : Union[tuple, float] = 1.
        The pixel_scales of each dimension. If a tuple, the length
        of the tuple must match the number of dimensions. If a float, the same
        scale is applied to all dimensions.
    offsets : Union[tuple, float] = 0.
        The offset of the pixel centers in each dimension. If a tuple, the
        length of the tuple must match the number of dimensions. If a float,
        the same offset is applied to all dimensions.
        set to 0.
    indexing : str = 'xy'
        The indexing of the output. Default is 'xy'. See numpy.meshgrid for
        more details.

    Returns
    -------
    coordinates : Array
        The positions of the pixel centers in the given dimensions.
    """
    if indexing not in ["xy", "ij"]:
        raise ValueError("indexing must be either 'xy' or 'ij'.")

    # Promote npixels to tuple to handle 1d case
    if not isinstance(npixels, tuple):
        npixels = (npixels,)

    # Assume equal pixel scales if not given
    if not isinstance(pixel_scales, tuple):
        pixel_scales = (pixel_scales,) * len(npixels)

    # Assume no offset if not given
    if not isinstance(offsets, tuple):
        offsets = (offsets,) * len(npixels)

    def pixel_fn(n, offset, scale):
        # TODO: calculate the start and end points first and then use linspace
        # so that ops are done on floats not arrays
        # scale = diam / n
        pix = np.arange(n) - (n - 1) / 2.0
        pix *= scale
        pix -= offset
        return pix

    # Generate the linear edges of each axes
    # TODO: tree_flatten()[0] to avoid squeeze?
    lin_pixels = tree_map(pixel_fn, npixels, offsets, pixel_scales)

    # output (x, y) for 2d, else in order
    positions = np.array(np.meshgrid(*lin_pixels, indexing=indexing))

    # Squeeze for empty axis removal in 1d case
    return np.squeeze(positions)

cart2polar

Converts the input (x, y) Cartesian coordinates into (r, phi) polar coordinates.

Parameters:

Name Type Description Default
coordinates Array

The (x, y) Cartesian coordinates to be converted into polar coordinates.

required

Returns:

Name Type Description
coordinates Array

The input Cartesian coordinates converted into (r, phi) polar coordinates.

Source code in src/dLux/utils/coordinates.py
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
def cart2polar(coordinates: Array) -> Array:
    """
    Converts the input (x, y) Cartesian coordinates into (r, phi) polar
    coordinates.

    Parameters
    ----------
    coordinates : Array
        The (x, y) Cartesian coordinates to be converted into polar
        coordinates.

    Returns
    -------
    coordinates : Array
        The input Cartesian coordinates converted into (r, phi) polar
        coordinates.
    """
    x, y = coordinates
    return np.array([np.hypot(x, y), np.arctan2(y, x)])

polar2cart

Converts the input (r, phi) polar coordinates into (x, y) Cartesian coordinates.

Parameters:

Name Type Description Default
coordinates Array

The (r, phi) polar coordinates to be converted into Cartesian coordinates.

required

Returns:

Name Type Description
coordinates Array

The input polar coordinates converted into (x, y) Cartesian coordinates.

Source code in src/dLux/utils/coordinates.py
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
def polar2cart(coordinates: Array) -> Array:
    """
    Converts the input (r, phi) polar coordinates into (x, y) Cartesian
    coordinates.

    Parameters
    ----------
    coordinates : Array
        The (r, phi) polar coordinates to be converted into Cartesian
        coordinates.

    Returns
    -------
    coordinates : Array
        The input polar coordinates converted into (x, y) Cartesian
        coordinates.
    """
    r, phi = coordinates
    return np.array([r * np.cos(phi), r * np.sin(phi)])


These remaining functions are primarily used as a back-end, and are not geared to be user-facing. For user-friendly coordinate transformations, use the dLux.CoordTransform class.

translate_coords

Translates the coordinates by to a new centre. Translation must have shape (2,).

Parameters:

Name Type Description Default
coords Array

The input coordinates to translate.

required
translation Array

The translation to apply to the coordinates.

required

Returns:

Name Type Description
coords Array

The translated coordinates.

Source code in src/dLux/utils/coordinates.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def translate_coords(coords: Array, translation: Array) -> Array:
    """
    Translates the coordinates by to a new centre. Translation must have shape (2,).

    Parameters
    ----------
    coords : Array
        The input coordinates to translate.
    translation : Array
        The translation to apply to the coordinates.

    Returns
    -------
    coords : Array
        The translated coordinates.
    """
    return coords - translation[:, None, None]

compress_coords

Compresses the coordinates by a given factor. Compress must have shape (2,).

Parameters:

Name Type Description Default
coords Array

The input coordinates to compress.

required
compress Array

The compression to apply to the coordinates.

required

Returns:

Name Type Description
coords Array

The compressed coordinates.

Source code in src/dLux/utils/coordinates.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
def compress_coords(coords: Array, compress: Array) -> Array:
    """
    Compresses the coordinates by a given factor. Compress must have shape (2,).

    Parameters
    ----------
    coords : Array
        The input coordinates to compress.
    compress : Array
        The compression to apply to the coordinates.

    Returns
    -------
    coords : Array
        The compressed coordinates.
    """
    return coords * compress[:, None, None]

shear_coords

Shears the coordinates by a given factor. Shear must have shape (2,).

Parameters:

Name Type Description Default
coords Array

The input coordinates to shear.

required
shear Array

The shear to apply to the coordinates.

required

Returns:

Name Type Description
coords Array

The sheared coordinates.

Source code in src/dLux/utils/coordinates.py
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
def shear_coords(coords: Array, shear: Array) -> Array:
    """
    Shears the coordinates by a given factor. Shear must have shape (2,).

    Parameters
    ----------
    coords : Array
        The input coordinates to shear.
    shear : Array
        The shear to apply to the coordinates.

    Returns
    -------
    coords : Array
        The sheared coordinates.
    """
    trans_coords = np.transpose(coords, (0, 2, 1))
    return coords + trans_coords * shear[:, None, None]

rotate_coords

Rotates the coordinates by a given angle.

Parameters:

Name Type Description Default
coords Array

The input coordinates to rotate.

required
rotation (float, radians)

The rotation to apply to the coordinates.

required

Returns:

Name Type Description
coords Array

The rotated coordinates.

Source code in src/dLux/utils/coordinates.py
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
def rotate_coords(coords: Array, rotation: float) -> Array:
    """
    Rotates the coordinates by a given angle.

    Parameters
    ----------
    coords : Array
        The input coordinates to rotate.
    rotation : float, radians
        The rotation to apply to the coordinates.

    Returns
    -------
    coords : Array
        The rotated coordinates.
    """

    x, y = coords
    new_x = np.cos(-rotation) * x + np.sin(-rotation) * y
    new_y = -np.sin(-rotation) * x + np.cos(-rotation) * y
    return np.array([new_x, new_y])