Source code for topostats.tracing.dnacurvature

"""Module for calculating curvature statistics."""

import logging

# from pathlib import Path
import numpy as np

from topostats.logs.logs import LOGGER_NAME

LOGGER = logging.getLogger(LOGGER_NAME)

# Disable white space before colon
# black and flake8 conflict https://black.readthedocs.io/en/stable/faq.html#why-are-flake8-s-e203-and-w503-violated
# noqa: E203


[docs] class Curvature: """ Class for determining the curvature of molecules. Parameters ---------- molecule_coordinates : np.ndarray Coordinates of the simplified splined trace of a molecule. These are returned by dnaTracing. circular : bool Whether the image is circular or not. """ def __init__( self, molecule_coordinates: np.ndarray, circular: bool, ): """ Initialise the class. Parameters ---------- molecule_coordinates : np.ndarray Coordinates of the simplified splined trace of a molecule. These are returned by dnaTracing. circular : bool Whether the image is circular or not. """ self.molecule_coordinates = molecule_coordinates self.circular = circular self.n_points = len(molecule_coordinates) self.first_derivative = None self.second_derivative = None self.local_curvature = None
[docs] def calculate_derivatives(self, edge_order: int = 1) -> None: """ Find the curvature for an individual molecule. Parameters ---------- edge_order : int Gradient is passed to numpy.gradient and Gradient is calculated using N-th order accurate differences at boundaries. Also used to expand the array by the necessary number of coordinates at either end to form a loop for the calculations. """ # If circular we need gradients correctly calculated at the start and end and so the array has the number of # points used in np.gradient(edge_order) from the end attached to the start and the same from the start attached # to the end. edge_order_boundary = edge_order + 1 if self.circular: coordinates = np.vstack( ( self.molecule_coordinates[-edge_order_boundary:], self.molecule_coordinates, self.molecule_coordinates[:edge_order_boundary], ) ) else: coordinates = self.molecule_coordinates self.first_derivative = np.gradient(coordinates, edge_order, axis=0) self.second_derivative = np.gradient(self.first_derivative, edge_order, axis=0) # Now trim the arrays back to the appropriate size if self.circular: self.first_derivative = self.first_derivative[edge_order_boundary:-edge_order_boundary] self.second_derivative = self.second_derivative[edge_order_boundary:-edge_order_boundary]
# def _extract_coordinates(molecule) -> np.ndarray: # """Extract the coordinates for the points""" # curve = [] # contour = 0 # # for i in len(molecule): # pass
[docs] def _calculate_local_curvature(self) -> float: """Calculate the local curvature between points.""" self.local_curvature = ( (self.second_derivative[:, 0] * self.first_derivative[:, 1]) - (self.first_derivative[:, 0] * self.second_derivative[:, 1]) ) / ((self.first_derivative[:, 0] ** 2) + (self.first_derivative[:, 1] ** 2)) ** 1.5