""" Top-level utility functions for pycellfit module."""
__author__ = "Nilai Vemula"
import os
import PIL.Image
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from shapely import geometry
from shapely import ops
[docs]def read_segmented_image(file_name, visualize=False):
"""Displays the segmented image using matplotlib
:param file_name: file name of a segmented image in .tif format
:type file_name: str
:param visualize: if true, then image will be plotted using matplotlib
:type visualize: bool
:raises TypeError: only accepts tif/tiff files as input
:return: array of pixel values
:rtype: numpy.ndarray
"""
extension = os.path.splitext(file_name)[1]
if not (extension == '.tif' or extension == '.tiff'):
raise TypeError("Invalid File Type. File must be a .tif or .tiff")
im = PIL.Image.open(file_name)
img_array = np.array(im)
if visualize:
plt.imshow(img_array, cmap='gray', origin='lower', interpolation="nearest")
return img_array
[docs]def contains_triple_junction(linestring, list_of_points):
"""helper function that tells you if a shapely LineString contains a triple junction
:param linestring: the LineString of interest
:type linestring: shapely.geometry.LineString
:param list_of_points: list containing a bunch of points of type :class:`shapely.geometry.Point`
:type list_of_points: list
:return: if the linestring contains a point in the list_of_points, the first point is returned; else, None.
:rtype: shapely.geometry.Point
"""
# iterates through each point in the list
for point in list_of_points:
# checks if line string of interest contains the point
if linestring.contains(point):
return point
return None
[docs]def make_segments(cell_boundary, list_of_triple_junctions):
"""recursive function that splits up a cell boundary based on triple junctions
:param cell_boundary: boundary of a cell that needs to be broken up into segments
:type cell_boundary: shapely.geometry.LineString
:param list_of_triple_junctions: list of all triple junctions (of type :class:`shapely.geometry.Point`) in the mesh
:type list_of_triple_junctions: list
:return results: list of segments (of type :class:`shapely.geometry.LineString`) that make up the cell boundary
:rtype: list
"""
results = []
triple_junction = contains_triple_junction(cell_boundary, list_of_triple_junctions)
if triple_junction:
if triple_junction == geometry.Point(list(cell_boundary.coords)[0]):
new_boundary = geometry.LineString(list(cell_boundary.coords)[1:])
triple_junction = contains_triple_junction(new_boundary, list_of_triple_junctions)
segments = ops.split(cell_boundary, triple_junction).geoms
for segment in segments:
results += make_segments(segment, list_of_triple_junctions)
else:
results.append(cell_boundary)
return results
[docs]def locate_triple_junctions(dataframe_of_cells, visualize=False):
"""generate list of triple junctions in mesh
:param visualize: boolean to indicate if plot of all points should be made or not
:type visualize: bool
:param dataframe_of_cells: a dataframe where each row contains a unique cell
:type dataframe_of_cells: geopandas dataframe
:return: list_of_tjs: list of all triple junctions in the mesh
:rtype: list
"""
list_of_all_points = extract_all_points(dataframe_of_cells, visualize)
nparray = np.empty((len(list_of_all_points), len(dataframe_of_cells.geometry)))
for j, cell in enumerate(dataframe_of_cells.geometry):
line = geometry.LineString(cell.exterior)
for i, point in enumerate(list_of_all_points):
nparray[i, j] = (line.contains(point))
num_of_junctions = nparray.sum(axis=1).tolist()
df = pd.DataFrame(list(zip(list_of_all_points, num_of_junctions)), columns=['Points', 'Number of Junctions'])
df = df.assign(is_tj=(df['Number of Junctions'] == 3))
tjs = df.query('is_tj == True')
list_of_tjs = tjs.Points.tolist()
if visualize:
# Visualize all points
xs = [point.x for point in list_of_tjs]
ys = [point.y for point in list_of_tjs]
plt.scatter(xs, ys)
plt.show()
return list_of_tjs