<jupyter_start><jupyter_text>Dynamic Network Classes  Table of Contents1. [Creating a simple graph](creating)  *   [Using a snapshot representation](sn)  *  [Using an interval graph representation](ig) 2. [Visualization](vizu)3. [Conversion between snapshots and interval graphs](conversion)4. [Aggregation/Slicing](aggregation)  *   [Slicing](aggregation)  *   [Cumulated graphs](aggregation)  *   [Resampling](aggregation) If tnerwork library is not installed, you need to install it, for instance using the following command<jupyter_code>#%%capture #avoid printing output
#!pip install --upgrade git+https://github.com/Yquetzal/tnetwork.git
%load_ext autoreload
%autoreload 2
import tnetwork as tn<jupyter_output><empty_output><jupyter_text>Creating simple dynamic graphs and accessing their propertiesWe will represent a graph with similar properties using snapshots and interval graphs  Using a snapshot representation`DynGraphSN` is the class used to represent dynamic networks with snapshots (SN). By default, **each snapshot last until the next**. The last snapshot has a duration equal to the min of all the snapshots.<jupyter_code>dg_sn = tn.DynGraphSN()
dg_sn
dg_sn.add_node_presence("a",1) #add node a in snapshot 1
dg_sn.add_nodes_presence_from(["a","b","c"],2) #add nodes a,b,c in snapshot 2
dg_sn.add_nodes_presence_from("d",[2,5]) #add node in snapshots 2 & 5

dg_sn.add_interaction("a","b",2) #link a and b in snapshot 2
dg_sn.add_interactions_from(("b","d"),[2,3,4]) #link b and d in snapshots 2, 3 and 4<jupyter_output><empty_output><jupyter_text>Using an interval graph representation.`DynGraphIG` is the class used to represent dynamic networks with Interval Graphs (IG)Note the similarity between the functions used.Both graphs are very similar if we consider that the snapshots of `dg_sn` have a duration of 1.<jupyter_code>dg_ig = tn.DynGraphIG()

dg_ig.add_node_presence("a",(1,2)) #add node a from time 1 to 2
dg_ig.add_nodes_presence_from(["a","b","c"],(2,3)) # add ndoes a,b,c from 2 to 3
dg_ig.add_nodes_presence_from("d",(2,6)) #add node from 2 to 6

dg_ig.add_interaction("a","b",(2,3)) # link nodes a and b from 2 to 3 
dg_ig.add_interactions_from(("b","d"),(2,5)) # link nodes b and d from 2 to 5<jupyter_output><empty_output><jupyter_text>Accessing functionsUsing accessing functions, we can check that both graphs are very similar(Note that intervals are coded using the tnetwork.Intervals class, and are printed as \[start,end\[. Therefore, 2 snapshots of duration 1 at times 1 and 2 code a situation similar to an interval \[1,3[<jupyter_code>print(dg_sn.graph_at_time(2).edges)
print(dg_ig.graph_at_time(2).edges)
print(dg_sn.graph_at_time(3).edges)
print(dg_ig.graph_at_time(3).edges)
print(dg_sn.node_presence())
print(dg_ig.node_presence())<jupyter_output>{'a': [1, 2], 'b': [2, 3, 4], 'c': [2], 'd': [2, 3, 4, 5]}
{'a': [1,3[ , 'b': [2,5[ , 'c': [2,3[ , 'd': [2,6[ }<jupyter_text>VisualizationWe can use a basic visualization to compare nodes presence of both representation. See the notebook on visualization to see more possibilities.<jupyter_code>plot = tn.plot_longitudinal(dg_sn,height=200)
plot = tn.plot_longitudinal(dg_ig,height=200)<jupyter_output>/usr/local/lib/python3.7/site-packages/numpy/core/numeric.py:2327: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
  return bool(asarray(a1 == a2).all())<jupyter_text>It is also possible to plot the graph at any given time.<jupyter_code>plot = tn.plot_as_graph(dg_sn,ts=2,auto_show=True,width=300,height=300)
plot = tn.plot_as_graph(dg_ig,ts=[1.5,2.5,3.3],auto_show=True,width=200,height=200)<jupyter_output><empty_output><jupyter_text>Conversion between snapshots and interval graphsWe convert the snapshot representation into an interval graph representation, using a snapshot lenght of 1. We check that both graphs are now similar<jupyter_code>converted_to_IG = dg_sn.to_DynGraphIG(sn_duration=1)
print(converted_to_IG.node_presence())
print(dg_ig.node_presence())<jupyter_output>{'a': [1,3[ , 'b': [2,5[ , 'c': [2,3[ , 'd': [2,6[ }
{'a': [1,3[ , 'b': [2,5[ , 'c': [2,3[ , 'd': [2,6[ }<jupyter_text>Reciprocally, we transform the interval graph into a snapshot representation and check the similarity<jupyter_code>converted_to_SN = dg_ig.to_DynGraphSN(slices=1)
print(converted_to_SN.node_presence())
print(dg_sn.node_presence())<jupyter_output>{'a': [1, 2], 'b': [2, 3, 4], 'c': [2], 'd': [2, 3, 4, 5]}
{'a': [1, 2], 'b': [2, 3, 4], 'c': [2], 'd': [2, 3, 4, 5]}<jupyter_text>Aggregation/Slicing  SlicingOne can conserve only a chosen period using the slice function<jupyter_code>sliced_SN = dg_sn.slice(2,4) #Keep only the snapshots from 2 to 4
sliced_IG = dg_ig.slice(1.5,3.5) #keep only what happens between 1.5 and 3.5 in the interval graph

plot = tn.plot_longitudinal(sliced_SN,height=200)
plot = tn.plot_longitudinal(sliced_IG,height=200)<jupyter_output>[2,3[ 
[2,5[<jupyter_text>Creating cumulated graphsIt can be useful to create cumulated weighted graphs to summarize the presence of nodes and edges over a period<jupyter_code>import networkx as nx
%matplotlib inline
g_cumulated = dg_sn.cumulated_graph()

#Similarly for interval graphs: 
#g_cumulated = dg_ig.cumulated_graph()

#Draw with node size and edge width propotional to weights in the cumulated graph
nx.draw_networkx(g_cumulated,node_size=[g_cumulated.nodes[n]['weight']*100 for n in g_cumulated.nodes], width = [g_cumulated[u][v]['weight'] for u,v in g_cumulated.edges])<jupyter_output><empty_output><jupyter_text>Graphs can also be cumulated only over a specific period<jupyter_code>g_cumulated = dg_sn.cumulated_graph([1,2]) # create a static graph cumulating snapshots 
g_cumulated = dg_ig.cumulated_graph((1,3))<jupyter_output><empty_output><jupyter_text>ResamplingSometimes, it is useful to study dynamic network with a lesser temporal granularity than the original data.Several functions can be used to aggregate dynamic graphs, thus yielding snapshots covering larger periods.Do exemplify this usage, we use a dataset from the sociopatterns project (http://www.sociopatterns.org) that can be loaded in a single command<jupyter_code>sociopatterns = tn.DynGraphSN.graph_socioPatterns2012()<jupyter_output><empty_output><jupyter_text>For this original network loaded as a snapshot representation, we print the number of snapshots and the first and last dates (the dataset covers 9 days, including a week-end with no activity)<jupyter_code>from datetime import datetime
all_times = sociopatterns.snapshots_timesteps()
print("# snapshots:",len(all_times))
print("first date:",datetime.utcfromtimestamp(all_times[0])," laste date:",datetime.utcfromtimestamp(all_times[-1]))
#Be careful, the plot takes a few seconds to draw. 
to_plot_SN = tn.plot_longitudinal(sociopatterns,height=500,sn_duration=20,to_datetime=True)<jupyter_output><empty_output><jupyter_text>We then aggregate on fixed time periods using the `aggregate_time_period` function. Although there are several ways to call this function, the simplest one is using a string such as "day", "hour", "month", etc.Note how the beginning of the first snapshot is now on midnight of the day on which the first observation was made<jupyter_code>sociopatterns_Day = sociopatterns.aggregate_time_period("day")

all_times = sociopatterns_Day.snapshots_timesteps()
print("# snapshots:",len(all_times))
print("first date:",datetime.utcfromtimestamp(all_times[0])," laste date:",datetime.utcfromtimestamp(all_times[-1]))
to_plot_SN = tn.plot_longitudinal(sociopatterns_Day,height=800,to_datetime=True,sn_duration=24*60*60)<jupyter_output><empty_output><jupyter_text>Another way to aggregate is to use sliding windows. In this example, we use non-overlapping windows of one hour, but it is possible to have other parameters, such as overlapping windows.Note how, this time, the first snapshot starts exactly at the time of the first observation in the original data<jupyter_code>sociopatterns_hour_window = sociopatterns.aggregate_sliding_window(bin_size=60*60)
all_times = sociopatterns_hour_window.snapshots_timesteps()
print("# snapshots:",len(all_times))
print("first date:",datetime.utcfromtimestamp(all_times[0])," laste date:",datetime.utcfromtimestamp(all_times[-1]))
plot =tn.plot_longitudinal(sociopatterns_hour_window,height=800,to_datetime=True,sn_duration=60*60)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11420413990007137, 'fraction_numerical': 0.02462526766595289, 'mean_word_length': 7.3320118929633304, 'pattern_counts': {'":': 0, '<': 56, '<?xml version=': 0, '>': 56, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '15', 'dir': 'jupyter-structured-clean-dedup', 'id': '335839', 'license': 'BSD-2-Clause', 'n_tokens_mistral': 3012, 'n_tokens_neox': 2838, 'n_words': 808, 'path': 'demo_Network_Graph_classes-Copy1.ipynb', 'repo_name': 'Yquetzal/tnetwork', 'size': '8406'}