.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/plot_02_real_network.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_plot_02_real_network.py: Mouse contact network (empirical data) ======================================= This example loads the mouse proximity-contact dataset published by `König (2021) `_ and analyses it as a continuous-time temporal network using :class:`~tempnet.ContTempNetwork`. The dataset records pairwise contact events (start time, end time, source mouse, target mouse) collected over several days. The example walks through the duration distribution, the aggregated static adjacency matrix and network, node and event activity over time, the raw contact timeline. and finally the forward transition matrices at several time scales. .. GENERATED FROM PYTHON SOURCE LINES 18-20 Load libraries -------------- .. GENERATED FROM PYTHON SOURCE LINES 20-35 .. code-block:: Python import tempfile from functools import reduce from pathlib import Path import numpy as np import pandas as pd import networkx as nx import seaborn as sns from matplotlib import pyplot as plt from matplotlib.colors import LogNorm from zenodo_get import download import tempnet as tn .. GENERATED FROM PYTHON SOURCE LINES 36-40 Download and load the dataset ----------------------------- We fetch the contact sequence from Zenodo and directly convert it to a DataFrame. .. GENERATED FROM PYTHON SOURCE LINES 40-52 .. code-block:: Python RECORD_ID = "4725155" FILE_NAME = "mice_contact_sequence.csv.gz" with tempfile.TemporaryDirectory() as tmpdir: download( record_or_doi=RECORD_ID, output_dir=tmpdir, file_glob=FILE_NAME, ) event_table = pd.read_csv(Path(tmpdir) / FILE_NAME, compression="gzip") .. rst-class:: sphx-glr-script-out .. code-block:: none 2026-06-16 12:03:17.324 | INFO | zenodo_get.zget:_zenodo_download_logic:328 - Output directory: /tmp/tmp6z78j4p1 2026-06-16 12:03:17.842 | INFO | zenodo_get.zget:_zenodo_download_logic:426 - Title: Temporal contact network of a free-ranging house mice population 2026-06-16 12:03:17.842 | INFO | zenodo_get.zget:_zenodo_download_logic:438 - Total size: 53.7 MB 2026-06-16 12:03:17.842 | INFO | zenodo_get.zget:_zenodo_download_logic:439 - Number of files: 1 Files: 0%| | 0/1 [00:00 with 414 nodes and 132034 events .. GENERATED FROM PYTHON SOURCE LINES 82-83 We can also access the variables directly from the object: .. GENERATED FROM PYTHON SOURCE LINES 83-87 .. code-block:: Python print('Number of mice', tempo.num_nodes) print('Number of events', tempo.num_events) .. rst-class:: sphx-glr-script-out .. code-block:: none Number of mice 414 Number of events 132034 .. GENERATED FROM PYTHON SOURCE LINES 88-91 Event-duration distribution --------------------------- Histogram of contact durations on log-linear and log-log axes. .. GENERATED FROM PYTHON SOURCE LINES 91-104 .. code-block:: Python fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(12, 4), dpi=200) sns.histplot(data=tempo.events_table, x='durations', ax=ax[0], log_scale=(True, False)) sns.histplot(data=tempo.events_table, x='durations', ax=ax[1], log_scale=(True, True)) ax[0].axvline(0.25, color='k', linestyle='--') ax[0].axvline(2, color='k', linestyle='--') ax[0].axvline(200, color='k', linestyle='--') plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_plot_02_real_network_001.png :alt: plot 02 real network :srcset: /auto_examples/images/sphx_glr_plot_02_real_network_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 105-109 Static aggregated adjacency matrix ---------------------------------- We aggregate the temporal network into a static weighted adjacency matrix and display it on linear and logarithmic colour scales. .. GENERATED FROM PYTHON SOURCE LINES 109-135 .. code-block:: Python A = tempo.compute_static_adjacency_matrix() A_dense = A.toarray() fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, dpi=200, figsize=(12, 5)) sns.heatmap(A_dense, ax=ax1, cbar_kws={'label': 'Weight'}, cmap='Greys') ax1.set_xlabel('Nodes') ax1.set_ylabel('Nodes') ax1.set_xticks([]) ax1.set_yticks([]) ax1.set_title('Adjacency Matrix (Linear Scale)') A_log = A_dense.copy() A_log[A_log == 0] = np.nan sns.heatmap(A_log, ax=ax2, norm=LogNorm(), cbar_kws={'label': 'Weight'}, cmap='Greys') ax2.set_xlabel('Nodes') ax2.set_ylabel('Nodes') ax2.set_xticks([]) ax2.set_yticks([]) ax2.set_title('Adjacency Matrix (Log Scale)') plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_plot_02_real_network_002.png :alt: Adjacency Matrix (Linear Scale), Adjacency Matrix (Log Scale) :srcset: /auto_examples/images/sphx_glr_plot_02_real_network_002.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 136-140 Convert to a NetworkX graph --------------------------- We then transform it into a NetworkX object to visualise and perform other algorithms and measure computation. .. GENERATED FROM PYTHON SOURCE LINES 140-143 .. code-block:: Python static = nx.from_numpy_array(A.toarray()) .. GENERATED FROM PYTHON SOURCE LINES 144-145 Check whether the aggregated network is connected. .. GENERATED FROM PYTHON SOURCE LINES 145-148 .. code-block:: Python print(nx.is_connected(static)) .. rst-class:: sphx-glr-script-out .. code-block:: none False .. GENERATED FROM PYTHON SOURCE LINES 149-150 Draw the aggregated static network, with edge widths scaled by weight. .. GENERATED FROM PYTHON SOURCE LINES 150-164 .. code-block:: Python fig, ax = plt.subplots(nrows=1, ncols=1, dpi=200) pos = nx.spring_layout(static, seed=412) weights = [static[u][v]["weight"] for u, v in static.edges()] max_w = max(weights) widths = [2 * np.log10(w) / np.log10(max_w) for w in weights] nx.draw(static, pos, with_labels=False, width=widths, node_color="teal", node_size=5) plt.title("Aggregated Static Network") plt.show() .. image-sg:: /auto_examples/images/sphx_glr_plot_02_real_network_003.png :alt: Aggregated Static Network :srcset: /auto_examples/images/sphx_glr_plot_02_real_network_003.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 165-170 The network is not connected, and it is clearly modular. To find the start and end of the temporal network -- equivalently, the minimum start time and maximum end time -- we can query the network directly: .. GENERATED FROM PYTHON SOURCE LINES 170-174 .. code-block:: Python print("Start:", tempo.start_time) print("End:", tempo.end_time) .. rst-class:: sphx-glr-script-out .. code-block:: none Start: 11.13 End: 86391.0 .. GENERATED FROM PYTHON SOURCE LINES 175-178 Active nodes over time ---------------------- Number of active nodes in each one-hour window across a full day. .. GENERATED FROM PYTHON SOURCE LINES 178-190 .. code-block:: Python t = np.arange(0, 24 * 3600 + 1, 3600) n_active = [tempo.num_active_nodes(t[i], t[i + 1]) for i in range(len(t) - 1)] fig, ax = plt.subplots(nrows=1, ncols=1) ax.plot(t[:-1], n_active, marker='.') ax.set_xticks(t) ax.set_xticklabels([i // 3600 for i in t], rotation=90) ax.set_xlabel('Time (Hour)') ax.set_ylabel('Number of active nodes') plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_plot_02_real_network_004.png :alt: plot 02 real network :srcset: /auto_examples/images/sphx_glr_plot_02_real_network_004.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 191-194 Active events over time ----------------------- Number of active edges/events in each one-hour window. .. GENERATED FROM PYTHON SOURCE LINES 194-208 .. code-block:: Python t = np.arange(0, 24 * 3600 + 1, 3600) n_edge_active = [tempo.num_active_edges(t[i], t[i + 1]) for i in range(len(t) - 1)] fig, ax = plt.subplots(nrows=1, ncols=1) ax.plot(t[:-1], n_edge_active, marker='.') ax.set_xticks(t) ax.set_xticklabels([i // 3600 for i in t], rotation=90) ax.set_xlabel('Time (Hour)') ax.set_ylabel('Number of active events') plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_plot_02_real_network_005.png :alt: plot 02 real network :srcset: /auto_examples/images/sphx_glr_plot_02_real_network_005.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 209-215 Mouse contact timeline --------------------------- The activity of events and nodes depends on the time of day. We can also investigate the network in the first hour. Each contact is drawn as a horizontal bar; rows correspond to individual mice. .. GENERATED FROM PYTHON SOURCE LINES 215-231 .. code-block:: Python fig, ax = plt.subplots(figsize=(10, 5)) et = tempo.events_table et = et[et['ending_times'] <= 3600] for _, row in et.iterrows(): tgt = row[tempo._TARGETS] t0 = row[tempo._STARTS] t1 = row[tempo._ENDINGS] ax.barh(tgt, t1 - t0, left=t0, height=0.6, color='steelblue', alpha=0.6) ax.set_xlabel('Time (s)') ax.set_ylabel('Mouse ID') ax.set_title('Mouse contact timeline — first 1 hour') plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_plot_02_real_network_006.png :alt: Mouse contact timeline — first 1 hour :srcset: /auto_examples/images/sphx_glr_plot_02_real_network_006.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 232-237 Forward transition matrices ----------------------- Now we want to compute the forward transition matrices by first computing the Laplacians for the 1st hour to keep the example fast enough. .. GENERATED FROM PYTHON SOURCE LINES 237-241 .. code-block:: Python tempo = tn.ContTempNetwork(events_table=et) tempo.compute_laplacian_matrices() .. GENERATED FROM PYTHON SOURCE LINES 242-244 We then proceed to computing the forward transition matrix for 3 time scales. It may take few minutes to run this. .. GENERATED FROM PYTHON SOURCE LINES 244-253 .. code-block:: Python scales = [1e-6, 1] for i, s in enumerate(scales): tempo.compute_inter_transition_matrices(lamda=s) forward_transition_matrices = [ reduce(lambda a, b: a @ b, tempo.inter_T[s]) for s in scales ] .. GENERATED FROM PYTHON SOURCE LINES 254-255 Visualise the forward transition matrices for each time scale. .. GENERATED FROM PYTHON SOURCE LINES 255-268 .. code-block:: Python norm = LogNorm(vmin=1e-6, vmax=1) fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(9, 4)) for i, (lamda, matrix) in enumerate(zip(scales, forward_transition_matrices)): sns.heatmap(matrix.toarray(), ax=ax[i], square=True, cbar=False, norm=norm) ax[i].set_title(rf'$\lambda$={lamda}') ax[i].set_xticks([]) ax[i].set_yticks([]) fig.colorbar(ax[0].collections[0], ax=ax, label='Transition probability', fraction=0.046, pad=0.04) plt.show() .. image-sg:: /auto_examples/images/sphx_glr_plot_02_real_network_007.png :alt: $\lambda$=1e-06, $\lambda$=1 :srcset: /auto_examples/images/sphx_glr_plot_02_real_network_007.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (1 minutes 56.954 seconds) .. _sphx_glr_download_auto_examples_plot_02_real_network.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_02_real_network.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_02_real_network.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_02_real_network.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_