konigcell.Pixels#

class konigcell.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_gridslist[(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]].

attrsdict[Any, Any]

A dictionary storing any other user-defined information.

__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].

**kwargsextra keyword arguments

Extra user-defined attributes to be saved in .attrs.

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.

copy([pixels_array, xlim, ylim])

Create a copy of the current Pixels instance, optionally with new pixels_array, xlim and / or ylim.

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

attrs

lower

pixel_grids

pixel_size

pixels

upper

xlim

ylim

property pixels#
property xlim#
property ylim#
property attrs#
property pixel_size#
property pixel_grids#
property lower#
property upper#
static zeros(shape, xlim, ylim, **kwargs)[source]#
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:
filepathfilename or file handle

If filepath is a path (rather than file handle), it is relative to where python is called.

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:
filepathfilename or file handle

If filepath is a path (rather than file handle), it is relative to where python is called.

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:
colorscalestr, 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).

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:
axmpl_toolkits.mplot3D.Axes3D object, optional

The 3D matplotlib-based axis for plotting. If undefined, new Matplotlib figure and axis objects are created.

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()