pept.Pixels#
- class pept.Pixels(pixels_array, xlim, ylim, **kwargs)[source]#
Bases:
object
A class managing a 2D pixel space with physical dimensions, including tools for pixel manipulation and visualisation.
The .pixels attribute is simply a numpy.ndarray[ndim=2, dtype=float64]. If you think of Pixels as an image, the origin is the top left corner, the X-dimension is the left edge and the Y-dimension is the top edge, so that it can be indexed as .pixels[ix, iy].
The .attrs dictionary can be used to store extra information.
See also
konigcell.Voxels
A class managing a physical 3D voxel space.
konigcell.dynamic2d
Rasterize moving particles’ trajectories.
konigcell.static2d
Rasterize static particles’ positions.
konigcell.dynamic_prob2d
2D probability distribution of a quantity.
Notes
The class saves pixels as a contiguous numpy array for efficient access in C / Cython functions. The inner data can be mutated, but do not change the shape of the array after instantiating the class.
Examples
Create a zeroed 4x4 Pixels grid:
>>> import konigcell as kc >>> pixels = kc.Pixels.zeros((4, 4), xlim = [0, 10], ylim = [0, 5]) >>> pixels Pixels ------ xlim = [ 0. 10.] ylim = [0. 5.] pixels = (shape: (4, 4)) [[0. 0. 0. 0.] [0. 0. 0. 0.] [0. 0. 0. 0.] [0. 0. 0. 0.]] attrs = {}
Or create a Pixels instance from another array (e.g. an image or matrix):
>>> import numpy as np >>> matrix = np.ones((3, 3)) >>> pixels = kc.Pixels(matrix, xlim = [0, 10], ylim = [-5, 5]) >>> pixels Pixels ------ xlim = [ 0. 10.] ylim = [-5. 5.] pixels = (shape: (3, 3)) [[1. 1. 1.] [1. 1. 1.] [1. 1. 1.]] attrs = {}
Access pixels’ properties directly:
>>> pixels.xlim # ndarray[xmin, xmax] >>> pixels.ylim # ndarray[ymin, ymax] >>> pixels.pixel_size # ndarray[xsize, ysize] >>> pixels.pixels.shape # pixels resolution - tuple[nx, ny]
You can save extra attributes about the pixels instance in the attrs dictionary:
>>> pixels.attrs["dpi"] = 300 >>> pixels Pixels ------ xlim = [ 0. 10.] ylim = [-5. 5.] pixels = (shape: (3, 3)) [[1. 1. 1.] [1. 1. 1.] [1. 1. 1.]] attrs = { 'dpi': 300 }
The lower left and upper right corners of the pixel grid, in physical coordinates (the ones given by xlim and ylim):
>>> pixels.lower array([ 0., -5.])
>>> pixels.upper array([10., 5.])
You can access the underlying NumPy array directly:
>>> pixels.pixels array([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]])
Indexing is forwarded to the NumPy array:
>>> pixels[:, :] array([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]])
Transform physical units into pixel indices:
>>> pixels.from_physical([5, 0]) # pixel centres array([1., 1.])
>>> pixels.from_physical([5, 0], corner = True) # lower left corners array([1.5, 1.5])
Transform pixel indices into physical units:
>>> pixels.to_physical([0, 0]) # pixels centres array([ 1.66666667, -3.33333333])
>>> pixels.to_physical([0, 0], corner = True) # lower left corners array([ 0., -5.])
Save Pixels instance to disk, as a binary archive:
>>> pixels.save("pixels.pickle") >>> pixels = kc.load("pixels.pickle")
Create deep copy of a Pixels instance:
>>> Pixels.copy()
Matplotlib plotting (optional, if Matplotlib is installed):
>>> fig, ax = pixels.plot() >>> fig.show()
Plotly trace (optional, if Plotly is installed):
>>> import plotly.graph_objs as go >>> fig = go.Figure() >>> fig.add_trace(pixels.heatmap_trace()) >>> fig.show()
- Attributes
- pixels(
M
,N
)np.ndarray
[ndim=2, dtype=float64] The 2D numpy array containing the pixel values. This class assumes a uniform grid of pixels - that is, the pixel size in each dimension is constant, but can vary from one dimension to another.
- xlim(2,)
np.ndarray
[ndim=1, dtype=float64] The lower and upper boundaries of the pixellised volume in the x-dimension, formatted as [x_min, x_max].
- ylim(2,)
np.ndarray
[ndim=1, dtype=float64] The lower and upper boundaries of the pixellised volume in the y-dimension, formatted as [y_min, y_max].
- pixel_size(2,)
np.ndarray
[ndim=1, dtype=float64] The lengths of a pixel in the x- and y-dimensions, respectively.
- pixel_grids
list
[(M+1,)np.ndarray
, (N+1,)np.ndarray
] A list containing the pixel gridlines in the x- and y-dimensions. Each dimension’s gridlines are stored as a numpy of the pixel delimitations, such that it has length (M + 1), where M is the number of pixels in a given dimension.
- lower(2,)
np.ndarray
[ndim=1, dtype=float64] The lower left corner of the pixel rectangle; corresponds to [xlim[0], ylim[0]].
- upper(2,)
np.ndarray
[ndim=1, dtype=float64] The upper right corner of the pixel rectangle; corresponds to [xlim[1], ylim[1]].
- attrs
dict
[Any
,Any
] A dictionary storing any other user-defined information.
- pixels(
- __init__(pixels_array, xlim, ylim, **kwargs)[source]#
Pixels class constructor.
- Parameters
- pixels_array3D
numpy.ndarray
A 3D numpy array, corresponding to a pre-defined pixel space.
- xlim(2,)
numpy.ndarray
The lower and upper boundaries of the pixellised volume in the x-dimension, formatted as [x_min, x_max].
- ylim(2,)
numpy.ndarray
The lower and upper boundaries of the pixellised volume in the y-dimension, formatted as [y_min, y_max].
- **kwargs
extra
keyword
arguments
Extra user-defined attributes to be saved in .attrs.
- pixels_array3D
- Raises
ValueError
If pixels_array does not have exactly 2 dimensions or if xlim or ylim do not have exactly 2 values each.
Notes
No copies are made if pixels_array, xlim and ylim are contiguous NumPy arrays with dtype=float64.
Methods
__init__
(pixels_array, xlim, ylim, **kwargs)Pixels class constructor.
add_lines
(lines[, verbose])Pixellise a sample of lines, adding 1 to each pixel traversed, for each line in the sample.
copy
([pixels_array, xlim, ylim])Create a copy of the current Pixels instance, optionally with new pixels_array, xlim and / or ylim.
from_lines
(lines, number_of_pixels[, xlim, ...])Create a pixel space and traverse / pixellise a given sample of lines.
from_physical
(locations[, corner])Transform locations from physical dimensions to pixel indices.
heatmap_trace
([colorscale, transpose, xgap, ...])Create and return a Plotly Heatmap trace of the pixels.
load
(filepath)Load a saved / pickled Pixels object from filepath.
plot
([ax])Plot pixels as a heatmap using Matplotlib.
save
(filepath)Save a Pixels instance as a binary pickle object.
to_physical
(indices[, corner])Transform indices from pixel indices to physical dimensions.
zeros
(shape, xlim, ylim, **kwargs)Attributes
- property pixels#
- property xlim#
- property ylim#
- property attrs#
- property pixel_size#
- property pixel_grids#
- property lower#
- property upper#
- save(filepath)[source]#
Save a Pixels instance as a binary pickle object.
Saves the full object state, including the inner .pixels NumPy array, xlim, etc. in a fast, portable binary format. Load back the object using the load method.
- Parameters
- filepath
filename
orfile
handle
If filepath is a path (rather than file handle), it is relative to where python is called.
- filepath
Examples
Save a Pixels instance, then load it back:
>>> import numpy as np >>> import konigcell as kc >>> >>> grid = np.zeros((640, 480)) >>> pixels = kc.Pixels(grid, [0, 20], [0, 10]) >>> pixels.save("pixels.pickle")
>>> pixels_reloaded = kc.Pixels.load("pixels.pickle")
- static load(filepath)[source]#
Load a saved / pickled Pixels object from filepath.
Most often the full object state was saved using the .save method.
- Parameters
- filepath
filename
orfile
handle
If filepath is a path (rather than file handle), it is relative to where python is called.
- filepath
- Returns
pept.Pixels
The loaded pept.Pixels instance.
Examples
Save a Pixels instance, then load it back:
>>> import numpy as np >>> import konigcell as kc >>> >>> grid = np.zeros((640, 480)) >>> pixels = kc.Pixels(grid, [0, 20], [0, 10]) >>> pixels.save("pixels.pickle")
>>> pixels_reloaded = kc.Pixels.load("pixels.pickle")
- copy(pixels_array=None, xlim=None, ylim=None, **kwargs)[source]#
Create a copy of the current Pixels instance, optionally with new pixels_array, xlim and / or ylim.
The extra attributes in .attrs are propagated too. Pass new attributes as extra keyword arguments.
- from_physical(locations, corner=False)[source]#
Transform locations from physical dimensions to pixel indices. If corner = True, return the index of the bottom left corner of each pixel; otherwise, use the pixel centres.
Examples
Create a simple konigcell.Pixels grid, spanning [-5, 5] mm in the X-dimension and [10, 20] mm in the Y-dimension:
>>> import konigcell as kc >>> pixels = kc.Pixels.zeros((5, 5), xlim=[-5, 5], ylim=[10, 20]) >>> pixels Pixels ------ xlim = [-5. 5.] ylim = [10. 20.] pixels = (shape: (5, 5)) [[0. 0. ... 0. 0.] [0. 0. ... 0. 0.] ... [0. 0. ... 0. 0.] [0. 0. ... 0. 0.]] attrs = {}
>>> pixels.pixel_size array([2., 2.])
Transform physical coordinates to pixel coordinates:
>>> pixels.from_physical([-5, 10], corner = True) array([0., 0.])
>>> pixels.from_physical([-5, 10]) array([-0.5, -0.5])
The pixel coordinates are returned exactly, as real numbers. For pixel indices, round them into values:
>>> pixels.from_physical([0, 15]).astype(int) array([2, 2])
Multiple coordinates can be given as a 2D array / list of lists:
>>> pixels.from_physical([[0, 15], [5, 20]]) array([[2. , 2. ], [4.5, 4.5]])
- to_physical(indices, corner=False)[source]#
Transform indices from pixel indices to physical dimensions. If corner = True, return the coordinates of the bottom left corner of each pixel; otherwise, use the pixel centres.
Examples
Create a simple konigcell.Pixels grid, spanning [-5, 5] mm in the X-dimension and [10, 20] mm in the Y-dimension:
>>> import konigcell as kc >>> pixels = kc.Pixels.zeros((5, 5), xlim=[-5, 5], ylim=[10, 20]) >>> pixels Pixels ------ xlim = [-5. 5.] ylim = [10. 20.] pixels = (shape: (5, 5)) [[0. 0. ... 0. 0.] [0. 0. ... 0. 0.] ... [0. 0. ... 0. 0.] [0. 0. ... 0. 0.]] attrs = {}
>>> pixels.pixel_size array([2., 2.])
Transform physical coordinates to pixel coordinates:
>>> pixels.to_physical([0, 0], corner = True) array([-5., 10.])
>>> pixels.to_physical([0, 0]) array([-4., 11.])
Multiple coordinates can be given as a 2D array / list of lists:
>>> pixels.to_physical([[0, 0], [4, 3]]) array([[-4., 11.], [ 4., 17.]])
- heatmap_trace(colorscale='Magma', transpose=True, xgap=0.0, ygap=0.0)[source]#
Create and return a Plotly Heatmap trace of the pixels.
- Parameters
- colorscale
str
,default
“Magma” The Plotly scheme for color-coding the pixel values in the input data. Typical ones include “Cividis”, “Viridis” and “Magma”. A full list is given at plotly.com/python/builtin-colorscales/. Only has an effect if colorbar = True and color is not set.
- transposebool,
default
True
Transpose the heatmap (i.e. flip it across its diagonal).
- colorscale
Examples
Create a Pixels array and plot it as a heatmap using Plotly:
>>> import konigcell as kc >>> import numpy as np >>> import plotly.graph_objs as go
>>> pixels_raw = np.arange(150).reshape(10, 15) >>> pixels = kc.Pixels(pixels_raw, [-5, 5], [-5, 10])
>>> fig = go.Figure() >>> fig.add_trace(pixels.heatmap_trace()) >>> fig.show()
- plot(ax=None)[source]#
Plot pixels as a heatmap using Matplotlib.
Returns matplotlib figure and axes objects containing the pixel values colour-coded in a Matplotlib image (i.e. heatmap).
- Parameters
- ax
mpl_toolkits.mplot3D.Axes3D
object
, optional The 3D matplotlib-based axis for plotting. If undefined, new Matplotlib figure and axis objects are created.
- ax
- Returns
fig
,ax
Matplotlib figure and axes objects.
Examples
Pixellise an array of lines and plot them with Matplotlib:
>>> lines = np.array(...) # shape (N, M >= 7) >>> lines2d = lines[:, [0, 1, 2, 4, 5]] # select x, y of lines >>> number_of_pixels = [10, 10] >>> pixels = pept.Pixels.from_lines(lines2d, number_of_pixels)
>>> fig, ax = pixels.plot() >>> fig.show()
- add_lines(lines, verbose=False)#
Pixellise a sample of lines, adding 1 to each pixel traversed, for each line in the sample.
- Parameters
- lines(
M
,N
>= 5)numpy.ndarray
The sample of 2D lines to pixellise. Each line is defined as a timestamp followed by two 2D points, such that the data columns are [time, x1, y1, x2, y2, …]. Note that there can be extra data columns which will be ignored.
- verbosebool,
default
False
Time the pixel traversal and print it to the terminal.
- lines(
- Raises
ValueError
If lines has fewer than 5 columns.
- static from_lines(lines, number_of_pixels, xlim=None, ylim=None, verbose=True)#
Create a pixel space and traverse / pixellise a given sample of lines.
The number_of_pixels in each dimension must be defined. If the pixel space boundaries xlim or ylim are not defined, they are inferred as the boundaries of the lines.
- Parameters
- lines(
M
, N>=5)numpy.ndarray
The lines that will be pixellised, each defined by a timestamp and two 2D points, so that the data columns are [time, x1, y1, x2, y2]. Note that extra columns are ignored.
- number_of_pixels(2,)
list
[int
] The number of pixels in the x- and y-dimensions, respectively.
- xlim(2,)
list
[float
], optional The lower and upper boundaries of the pixellised volume in the x-dimension, formatted as [x_min, x_max]. If undefined, it is inferred from the boundaries of lines.
- ylim(2,)
list
[float
], optional The lower and upper boundaries of the pixellised volume in the y-dimension, formatted as [y_min, y_max]. If undefined, it is inferred from the boundaries of lines.
- lines(
- Returns
pept.Pixels
A new Pixels object with the pixels through which the lines were traversed.
- Raises
ValueError
If the input lines does not have the shape (M, N>=5). If the number_of_pixels is not a 1D list with exactly 2 elements, or any dimension has fewer than 2 pixels.