Source code for pyfibre.model.analysers.metric_analyser
from abc import ABC, abstractmethod
import logging
from functools import partial
import numpy as np
import pandas as pd
from pyfibre.model.tools.metrics import (
SHAPE_METRICS, STRUCTURE_METRICS, TEXTURE_METRICS,
FIBRE_METRICS, NETWORK_METRICS,
fibre_network_metrics, segment_metrics
)
from pyfibre.utilities import nanmean
logger = logging.getLogger(__name__)
[docs]def metric_averaging(database, metrics, weights=None):
"""Create new pandas database from mean of selected
metrics in existing database"""
average_database = pd.Series(dtype=object)
if weights is not None:
if isinstance(weights, list):
weights = np.array(weights)
if weights.size != database.shape[0]:
raise ValueError(
'Weights array must have same shape as '
'database columns')
for metric in metrics:
if metric in database:
average_database[metric] = nanmean(
database[metric], weights
)
return average_database
[docs]class MetricAnalyser(ABC):
def __init__(
self, image=None, filename=None, networks=None,
segments=None, sigma=0.0001):
self.filename = filename
self.image = image
self.networks = networks
self.segments = segments
self.sigma = sigma
self.local_metrics = None
self.global_metrics = None
def _global_averaging(self, local_metrics, segment_tag, image_tag,
weight_metric=None):
shape_metrics = [
f'{segment_tag} Segment {metric}'
for metric in SHAPE_METRICS]
texture_metrics = [
f'{segment_tag} Segment {image_tag} {metric}'
for metric in STRUCTURE_METRICS + TEXTURE_METRICS]
fibre_metrics = [
f'Mean {segment_tag} {metric}' for metric in
FIBRE_METRICS]
network_metrics = [
f'{segment_tag} Network {metric}' for metric in
NETWORK_METRICS]
if weight_metric is None:
weights = None
else:
weights = local_metrics[weight_metric].values
global_metrics = metric_averaging(
local_metrics,
shape_metrics + texture_metrics +
fibre_metrics + network_metrics,
weights
)
return global_metrics
def _get_metrics(self, attr, metric_function, tag):
logger.debug(f'Performing metrics for {tag}')
# Analyse individual segments
metrics = metric_function(attr)
filenames = pd.Series(
['{}_{}'.format(self.filename, tag)] * len(attr),
name='File')
metrics = pd.concat((filenames, metrics), axis=1)
return metrics
def _get_network_metrics(self):
return self._get_metrics(
self.networks, fibre_network_metrics, 'fibre_networks.json')
def _get_segment_metrics(self, image_tag, tag):
metric_func = partial(
segment_metrics,
image=self.image, image_tag=image_tag,
sigma=self.sigma)
return self._get_metrics(
self.segments, metric_func, tag)
[docs] @abstractmethod
def analyse(self):
"""Perform metric analysis, returning list of pandas
DataFrame instances"""