Data Types ========== Data loaded into Pingwyn can be represented in a multitude of ways. To support this, Pingwyn has a number of data types in which data is stored and manipulated. Some operations can only be performed on specific data types, whilst others can be performed on any data. Below, we will briefly go over the data types present in Pingwyn. .. note:: Generally, Pingwyn objects are created by calling :func:`pingwyn.open` or :func:`pingwyn.open_all`. However, it is possible to create Pingwyn objects by hand, by creating a new instance of an object, such as ``im = pg.Image(data, metadata)``. ``data`` has to be a Numpy array of appropriate dimensions, which can be found in the reference for each data type. Images ------ Two-dimensional SPM data, such as topographies, are represented using :class:`pingwyn.Image` objects. Image objects are 2D-numpy arrays, with additional metadata (:attr:`pingwyn.Image.metadata`) to store information about the image. Unlike computer graphics, where image data is stored as x,y-coordinates, Pingwyn images use matrix notation (i.e. row, column or i,j-indices). Furthermore, image coordinates follow mathematics rules, i.e. the origin is located at the bottom-left of the axis. .. important:: As Pingwyn stores data differently compared to regular computer graphics, the image might be rotated or flipped along different axes when a Pingwyn image is parsed by another library, such as OpenCV of scikit-image. Curves ------ Individual spectroscopy data, such as a current-voltage or a force-distance measurement, are stored in :class:`pingwyn.Curve` objects. Curve objects are 2 by N dimensional numpy arrays, with the 0th row storing the x-axis and the 1st row storing the y-axis. Like other Pingwyn types, a curve houses :attr:`pingwyn.Curve.metadata` about its setpoints, as well as spatial information on where it was taken in reference to a pingwyn Image. .. hint:: It is sometimes useful to filter curves such that you are left with those that only correspond to a specific image. This can be achieved using the :func:`pingwyn.Image.filter_referenced_curves` function. Profiles -------- Multiple curves can be combined into a profile, such as when spectroscopy is performed along a line. In this case, the :class:`pingwyn.Profile` data type is used. Profiles are 2D-numpy arrays, where the rows are the different curves and the columns are the data of said curves. As with other data types, profiles have a :attr:`pingwyn.Profile.metadata` field. Additionally, a profile stores the x-axis under :attr:`pingwyn.Profile.x`. .. note:: Whilst it is possible, you generally do not want to create profiles by hand. If you have multiple curves that are part of a profile, you can convert these by using :func:`pingwyn.curves_to_profiles`. This function will automatically determine which curves belong on a profile, and how many profiles are present. .. hint:: Currently, there is no function to convert profiles back into curves or to extract a single curve. However, a profile stores all information readily: ``curve = pg.Curve(np.array([profile.x, profile[curve_index_of_interest, :]]), metadata)``. Grids ----- Three-dimensional data or volume data is stored as the :class:`pingwyn.Grid` data type. Grids can be seen as a combination between an image and a profile. A grid is a 3D-numpy array, where axis 0 and axis 1 (i and j) are spatial indices, and axis 2 (k) is used to store the 3rd dimension (such as an I(V) or F(Z) measurement). Grids have a :attr:`pingwyn.Grid.metadata` field for the metadata, as well as :attr:`pingwyn.Grid.z` to store the x-axis (which is the z-axis in volume space) of each curve. .. hint:: A single curve can be readily extracted from a grid using ``curve = pg.Curve(np.array([grid.z, grid[i, j, :]]), metadata)``. DataContainer ------------- A :class:`pingwyn.DataContainer` is, as the name suggests, a generic container for data. All other pingwyn data types extend this class. Generally, you should not need to use this data type, unless you require a custom way to store data.