Network analysis

[1]:
import movekit as mkit
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.spatial import Voronoi, voronoi_plot_2d, convex_hull_plot_2d, delaunay_plot_2d
import networkx as nx
import collections
[2]:
path = "datasets/fish-5-cleaned.csv"
data = mkit.read_data(path)
data = mkit.extract_features(data)
data.head()
Extracting all absolute features: 100%|██████████| 100.0/100 [00:01<00:00, 61.85it/s]
[2]:
time animal_id x y distance direction turning average_speed average_acceleration stopped
0 1 312 405.29 417.76 0.0 (0.0, 0.0) 0.0 0.210217 -0.006079 1
1 1 511 369.99 428.78 0.0 (0.0, 0.0) 0.0 0.020944 0.000041 1
2 1 607 390.33 405.89 0.0 (0.0, 0.0) 0.0 0.070235 0.000344 1
3 1 811 445.15 411.94 0.0 (0.0, 0.0) 0.0 0.370500 0.007092 1
4 1 905 366.06 451.76 0.0 (0.0, 0.0) 0.0 0.118000 -0.003975 1

Obtaining a list of graphs, based on delaunay triangulations

Caclulate a network list for each timestep based on delaunay. trinangulation. Each timestep carries the respective graph with data attached to nodes, edges and graph. Just insert time and animal specific x and y coordinate data.

[3]:
#Calculates a network list for each timestep based on delaunay triangulation (currently only one available)
graphs = mkit.network_time_graphlist(data)
Calculating spatial objects: 100%|██████████| 1000/1000 [00:12<00:00, 82.05it/s]
Computing euclidean distance: 100%|██████████| 1000/1000 [00:03<00:00, 263.66it/s]
Extracting all absolute features: 100%|██████████| 100.0/100 [00:01<00:00, 75.25it/s]
Calculating centroid distances: 100%|██████████| 1000/1000 [00:05<00:00, 182.21it/s]
Calculating centroid distances: 100%|██████████| 1000/1000 [00:06<00:00, 162.88it/s]
Calculating centroid distances: 100%|██████████| 1000/1000 [00:04<00:00, 210.44it/s]
Computing centroid direction: 100%|██████████| 100.0/100 [00:00<00:00, 709.71it/s]
Calculating network list: 100%|██████████| 1000/1000 [00:04<00:00, 226.92it/s]
[4]:
# Visualizing the graph for time step '3'-

pos = nx.spring_layout(graphs[2])

nx.draw(graphs[2], pos)
node_labels = nx.get_node_attributes(graphs[2], 'animal_id')
nx.draw_networkx_labels(graphs[2], pos=pos, labels=node_labels)

edge_labels = nx.get_edge_attributes(graphs[2], 'distance')
nx.draw_networkx_edge_labels(graphs[2], pos=pos, edge_labels=edge_labels)
plt.show()
../_images/examples_05_network_analysis_5_0.png
[5]:
# Display all graph attributes at time 3
graphs[2].graph
[5]:
{'time': 3,
 'x_centroid': 395.392,
 'y_centroid': 423.234,
 'medoid': 312,
 'polarization': 0.30008793109871296,
 'total_dist': 1.0251553045775692,
 'mean_speed': 0.15561007599508753,
 'mean_acceleration': 0.0018184129934008715,
 'mean_distance_centroid': 29.691399999999998,
 'centroid_direction': (0.01, 0.014)}
[6]:
# Display all edges at time 3
graphs[2].edges
[6]:
EdgeView([(312, 811), (312, 607), (312, 511), (312, 905), (811, 905), (811, 607), (607, 511)])
[7]:
# Display the distance of one node pair at time 3
graphs[2].edges[312, 811]
[7]:
{'distance': 40.70507585056191}
[8]:
# Display all attributes of node 312 at time 3
graphs[2].nodes[312]
[8]:
{'time': 3,
 'animal_id': 312,
 'x': 405.31,
 'y': 417.07,
 'distance': 0.30000000000001137,
 'direction': (0.0, -0.3),
 'turning': 0.9986876634765885,
 'average_speed': 0.17472339975245438,
 'average_acceleration': -0.004658902224371936,
 'stopped': 1,
 'x_centroid': 395.392,
 'y_centroid': 423.234,
 'medoid': 312,
 'distance_to_centroid': 11.677}

Network analysis

The networkx package enables to analyze the extracted graphs over time. See doc: https://networkx.org/documentation/stable/index.html

[9]:
len(graphs)
[9]:
1000
[10]:
# Plot number of nodes over time
num_edges = []
for G in graphs:
    num_edges.append(nx.number_of_edges(G))

plt.plot(num_edges)
plt.show()
../_images/examples_05_network_analysis_12_0.png
[11]:
# Plot clustering coefficient over time
avg_cluster = []
for G in graphs:
    avg_cluster.append(nx.average_clustering(G))

plt.plot(avg_cluster)
plt.show()
../_images/examples_05_network_analysis_13_0.png
[12]:
# Plot density over time
dens = []
for G in graphs:
    dens.append(nx.density(G))

plt.plot(dens)
plt.show()
../_images/examples_05_network_analysis_14_0.png
[13]:
# Plot transitivity over time
trans = []
for G in graphs:
    trans.append(nx.transitivity(G))

plt.plot(trans)
plt.show()
../_images/examples_05_network_analysis_15_0.png

Compute features for individiual nodes

[14]:
# Pick the first graph
G = graphs[0]
[15]:
# Degree
dict(G.degree())
[15]:
{312: 4, 811: 3, 905: 2, 607: 3, 511: 2}
[16]:
# Degree centraility
nx.degree_centrality(G)
[16]:
{312: 1.0, 811: 0.75, 905: 0.5, 607: 0.75, 511: 0.5}
[17]:
# Clustering coefficient
nx.clustering(G)
[17]:
{312: 0.5,
 811: 0.6666666666666666,
 905: 1.0,
 607: 0.6666666666666666,
 511: 1.0}
[18]:
# Degree rank
degree_sequence = sorted([d for n, d in G.degree()], reverse=True)
dmax = max(degree_sequence)

plt.loglog(degree_sequence, "b-", marker="o")
plt.title("Degree rank plot")
plt.ylabel("degree")
plt.xlabel("rank")
plt.show()
../_images/examples_05_network_analysis_21_0.png

For more methods please check the networkX doc: https://networkx.org/documentation/stable/index.html

[ ]: