Newer
Older
# Contributor(s): Eric Debreuve (since 2018), Morgane Nadal (2020)
#
# eric.debreuve@cnrs.fr
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
# skl_fgraph=Skeleton graph with computable features; Derived from base skeleton graph.
NADAL Morgane
committed
from sklgraph.skl_graph import skl_graph_t as skl_nfgraph_t # nf=no feature
from typing import Callable, Iterable, List, Tuple # , SupportsFloat
import numpy as np_
class skl_graph_t(skl_nfgraph_t):
#
@property
def n_nodes(self) -> int:
return self.number_of_nodes()
@property
def n_edges(self) -> int:
return self.number_of_edges()
@property
def max_degree(self) -> int:
return max(degree for node, degree in self.degree if "S" not in node)
@property
def std_degree(self) -> int:
return np_.std(list(degree for node, degree in self.degree if "S" not in node and degree != 1))
def max_degree_except_leaves_an_roots(self) -> int:
try:
return max(degree for node, degree in self.degree if "S" not in node and degree > 2)
except:
return 1
def min_degree_except_leaves_and_roots(self) -> int:
try:
return min(degree for node, degree in self.degree if "S" not in node and degree > 2)
except:
return 1
def mean_degree_except_leaves_and_roots(self) -> int:
try:
return np_.mean(list(degree for node, degree in self.degree if "S" not in node and degree > 2))
except:
return 1
def median_degree_except_leaves_and_roots(self) -> int:
try:
return np_.median(list(degree for node, degree in self.degree if "S" not in node and degree > 2))
except:
return 1
def std_degree_except_leaves_and_roots(self) -> int:
try:
return np_.std(list(degree for node, degree in self.degree if "S" not in node and degree > 2))
except:
return 0
@property
def edge_lengths(self) -> Tuple[float, ...]:
#
return tuple(
edge.lengths.length for ___, ___, edge in self.edges.data("as_edge_t") if edge is not None
)
@property
def length(self) -> float:
#
return sum(self.edge_lengths)
@property
def min_length(self) -> float:
#
return min(self.edge_lengths)
@property
def max_length(self) -> float:
#
return max(self.edge_lengths)
@property
def mean_length(self) -> float:
#
return np_.mean(self.edge_lengths)
@property
def median_length(self) -> float:
#
return np_.median(self.edge_lengths)
@property
def std_length(self) -> float:
#
return np_.std(self.edge_lengths)
@property
def edge_ww_lengths(self) -> Tuple[float, ...]:
#
return tuple(
edge.lengths.ww_length for ___, ___, edge in self.edges.data("as_edge_t") if edge is not None
)
@property
def ww_length(self) -> float:
#
return sum(self.edge_ww_lengths)
def edge_reduced_widths(
self, reduce_fct: Callable[[Iterable[float]], float] = np_.mean
reduce_fct(edge.widths) for ___, ___, edge in self.edges.data("as_edge_t") if edge is not None
self, reduce_fct: Callable[[Iterable[float]], float] = np_.mean
) -> float:
#
all_widths = []
for ___, ___, edge in self.edges.data("as_edge_t"):
if edge is not None:
all_widths.extend(edge.widths)
return reduce_fct(all_widths)
def heterogeneous_reduced_width(
self,
edge_reduce_fct: Callable[[Iterable[float]], float] = np_.mean,
final_reduce_fct: Callable[[Iterable[float]], float] = np_.mean,
) -> float:
#
return final_reduce_fct(self.edge_reduced_widths(edge_reduce_fct))
def primary_edge_lengths(self, soma) -> Tuple[float, ...]:
#
return tuple(edge.lengths.length for node1_id, node2_id, edge in self.edges.data("as_edge_t") if(edge is not None) and ((node1_id in soma.graph_roots.values()) or (node2_id in soma.graph_roots.values())))
def secondary_edge_lengths(self, soma) -> Tuple[float, ...]:
#
return tuple(edge.lengths.length for node1_id, node2_id, edge in self.edges.data("as_edge_t") if (node1_id not in soma.graph_roots.values()) and (node2_id not in soma.graph_roots.values()))
def highest_degree_w_nodes(self, soma) -> Tuple[int, List[str]]:
#
max_degree = 1
at_nodes = None
for node, degree in self.degree:
if "S" not in node:
if degree > 2:
if degree > max_degree:
max_degree = degree
at_nodes = [node]
elif degree == max_degree:
at_nodes.append(node)
return max_degree, at_nodes