schrodinger.analysis.visanalysis package


Molecular structures reside in a three-dimensional world and naturally enough give rise to three-dimensional data. Much of this data can be represented on a three-dimensional grid of points and visualised, either via isosurfaces, or more recently by advanced volumetric rendering options built into packages such as PyMol and Maestro. Currently however, the Schrodinger Python APIs do not provide an easy method of generating or handling such data. This library seeks to address this deficiency by providing a simple method of creating and handling three-dimensional ‘volumetric-data’ as well as code to allow such data to be exported to packages such as PyMol and Maestro for visualisation.

Handling Three-Dimensional Data

Three-dimensional arrays are trivially handled in most programming languages, Python is no exception to this, with the Numpy array class providing all of the basic functionality that we require in terms of low-level data allocation and manipulation. However, like most implementations, the Numpy array class only allows data points to reside on zero-based, integer indices, something which is inconvenient when we need to be able to manipulate data in terms of real-world coordinates, which will frequently involve fractional values. Consequently we need to generate the concept of world-coordinates and array-coordinates, with their associated coordinate-frames.

Array Coordinates

Array-coordinates are integer coordinates specifying a given offset in the array. The set of valid array coordinates is bounded by zero at the lower end and the size of the array at the upper end. The size of the array is denoted as N throughout the code.

World Coordinates

World-coordinates are floating-point coordinates representing a position in space. The set of valid world coordinates is not bound by anything, however, only a certain fraction of world-coordinates will correspond to a valid array-coordinate. In reality there are three classes of world-coordinate specification:

1. Directly mappable world-coordinate. A directly mappable world-coordinate corresponds precisely to a valid location in array-coordinates. The value of the data at this location can be found by reading the underlying array directly. 2. Interpolatable world-coordinate. An interpolatable world-coordinate corresponds to a location that is in the bounds of the array-coordinates, but which does not correspond to a valid array coordinate, i.e. it lies between valid array-coordinates. A value cannot be retrieved directly from the underlying array in this case, however a valid value may be found via interpolation. 3. Invalid world-coordinate. An invalid world-coordinate corresponds to a location that lies outside of the bounds of the array-coordinates. A value cannot be retrieved directly from the underlying array in this case, additionally no value can be found via interpolation. Such situations may be handled by returning a default value (frequently zero) or by raising an error condition.

Converting Between Coordinate-Frames

Naturally it will be necessary to convert between the array-coordinate frame and the world-coordinate frame (and back again). Fortunately this is very simple as naturally enough there is a linear relationship between them:

world = resolution * array + origin

array = ( world - origin ) / resolution

Of course in creating these conversions we have introduced the notion of resolution and the origin. These concepts are simple enough, the resolution specifies how quickly the world-coordinate changes for a change in the array-coordinate, while the origin moves the array-coordinate around the world-coordinate frame.