From 3c7e3fc018df2b74648ea40592d16540a62d2df4 Mon Sep 17 00:00:00 2001 From: luc Date: Fri, 28 Aug 2026 14:06:08 +0200 Subject: [PATCH] graph-inspect/*: add --- graph-inspect/inspect-graph-comparison.ipynb | 425 ++++++++++++ graph-inspect/inspect-graph-user.ipynb | 335 +++++++++ graph-inspect/inspect-graph.ipynb | 671 +++++++++++++++++++ 3 files changed, 1431 insertions(+) create mode 100644 graph-inspect/inspect-graph-comparison.ipynb create mode 100644 graph-inspect/inspect-graph-user.ipynb create mode 100644 graph-inspect/inspect-graph.ipynb diff --git a/graph-inspect/inspect-graph-comparison.ipynb b/graph-inspect/inspect-graph-comparison.ipynb new file mode 100644 index 0000000..ea582af --- /dev/null +++ b/graph-inspect/inspect-graph-comparison.ipynb @@ -0,0 +1,425 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Compare interactions graphs\n", + "\n", + "Inspecting interaction and comparing graphs by counting the components, determining the connectivity, clustering and various other metrics. " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Import the graphs." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import networkx as nx\n", + "\n", + "casename1 = '...'\n", + "case1 = '...'\n", + "\n", + "casename2 = '...'\n", + "case2 = '...'\n", + "\n", + "# Import the graph\n", + "G1 = nx.read_graphml(f'../datasets/{case1}-dtc-graph.graphml')\n", + "G2 = nx.read_graphml(f'../datasets/{case2}-dtc-graph.graphml')\n", + "\n", + "# Print nodes, edges and density of the graphs\n", + "print(f'G1:\\nNodes: {G1.number_of_nodes()}\\nEdges: {G1.number_of_edges()}\\nDensity: {nx.density(G1):.5f}')\n", + "print(f'G2:\\nNodes: {G2.number_of_nodes()}\\nEdges: {G2.number_of_edges()}\\nDensity: {nx.density(G2):.5f}')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Remove isolated nodes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "G1.remove_nodes_from(list(nx.isolates(G1)))\n", + "G2.remove_nodes_from(list(nx.isolates(G2)))\n", + "\n", + "# Print nodes, edges and density of the graphs\n", + "print(f'G1:\\nNodes: {G1.number_of_nodes()}\\nEdges: {G1.number_of_edges()}\\nDensity: {nx.density(G1):.5f}')\n", + "print(f'G2:\\nNodes: {G2.number_of_nodes()}\\nEdges: {G2.number_of_edges()}\\nDensity: {nx.density(G2):.5f}')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Compute average degree, connectivity, clustering and degree_assortivity. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "components1 = list(nx.connected_components(G1))\n", + "\n", + "component_metrics1 = []\n", + "\n", + "for component in components1:\n", + "\n", + " subG = G1.subgraph(component)\n", + "\n", + " num_nodes = subG.number_of_nodes()\n", + " num_edges = subG.number_of_edges()\n", + " average_degree = (2 * num_edges) / num_nodes\n", + " connectivity = nx.node_connectivity(subG)\n", + " clustering = nx.average_clustering(subG)\n", + " degree_assortivity = nx.degree_assortativity_coefficient(subG)\n", + "\n", + " metrics = {\n", + " 'num_nodes': num_nodes,\n", + " 'num_edges': num_edges,\n", + " 'average_degree': average_degree,\n", + " 'connectivity': connectivity,\n", + " 'clustering': clustering,\n", + " 'degree_assortivity': degree_assortivity,\n", + " }\n", + "\n", + " component_metrics1.append(metrics)\n", + "\n", + "df_metric1 = pd.DataFrame(component_metrics1)\n", + "df_metric1.describe()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "components2 = list(nx.connected_components(G2))\n", + "\n", + "component_metrics2 = []\n", + "\n", + "for component in components2:\n", + "\n", + " subG = G2.subgraph(component)\n", + "\n", + " num_nodes = subG.number_of_nodes()\n", + " num_edges = subG.number_of_edges()\n", + " average_degree = (2 * num_edges) / num_nodes\n", + " connectivity = nx.node_connectivity(subG)\n", + " clustering = nx.average_clustering(subG)\n", + " degree_assortivity = nx.degree_assortativity_coefficient(subG)\n", + "\n", + " metrics = {\n", + " 'num_nodes': num_nodes,\n", + " 'num_edges': num_edges,\n", + " 'average_degree': average_degree,\n", + " 'connectivity': connectivity,\n", + " 'clustering': clustering,\n", + " 'degree_assortivity': degree_assortivity,\n", + " }\n", + "\n", + " component_metrics2.append(metrics)\n", + "\n", + "df_metric2 = pd.DataFrame(component_metrics2)\n", + "df_metric2.describe()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Filter out the outliers in the dataframe, based on number of edges." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df_metric1_ro = df_metric1[(df_metric1['num_edges'] < 400) & (df_metric1['num_nodes'] > 10)]\n", + "\n", + "df_metric1_ro.describe()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df_metric2_ro = df_metric2[(df_metric2['num_edges'] < 400) & (df_metric2['num_nodes'] > 10)]\n", + "\n", + "df_metric2_ro.describe()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot the distributions of average degree." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "import numpy as np\n", + "\n", + "plt.figure(figsize=(8, 6))\n", + "\n", + "upper_limit = 1e3\n", + "\n", + "# Define the number of bins\n", + "num_bins = 20\n", + "\n", + "# Calculate the combined range for both datasets\n", + "min_value = min(df_metric1_ro['average_degree'].min(), df_metric2_ro['average_degree'].min())\n", + "max_value = max(df_metric1_ro['average_degree'].max(), df_metric2_ro['average_degree'].max())\n", + "\n", + "# Create bin edges\n", + "bins = np.linspace(min_value, max_value, num_bins + 1)\n", + "\n", + "# Create a single plot\n", + "sns.histplot(df_metric1_ro['average_degree'], bins=bins, color='blue', alpha=0.5, label=f'{casename1.title()} case')\n", + "sns.histplot(df_metric2_ro['average_degree'], bins=bins, color='orange', alpha=0.5, label=f'{casename2.title()} case')\n", + "\n", + "# Set y-axis to logarithmic scale\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "\n", + "# Set titles and labels\n", + "plt.title('Distribution of average degree (nodes > 10, edges < 400)', fontsize=16)\n", + "plt.xlabel('Average degree')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in', top=True, right=True)\n", + "\n", + "# Add a legend\n", + "plt.legend()\n", + "\n", + "# Show the plot\n", + "plt.tight_layout(rect=[0, 0, 1, 0.99])\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot the distributions of connectivity." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "import numpy as np\n", + "\n", + "plt.figure(figsize=(8, 6))\n", + "\n", + "upper_limit = 1e3\n", + "\n", + "# Define the number of bins\n", + "num_bins = 20\n", + "\n", + "# Calculate the combined range for both datasets\n", + "min_value = min(df_metric1_ro['connectivity'].min(), df_metric2_ro['connectivity'].min())\n", + "max_value = max(df_metric1_ro['connectivity'].max(), df_metric2_ro['connectivity'].max())\n", + "\n", + "# Create bin edges\n", + "bins = np.linspace(min_value, max_value, num_bins + 1)\n", + "\n", + "# Create a single plot\n", + "sns.histplot(df_metric1_ro['connectivity'], bins=bins, color='blue', alpha=0.5, label=f'{casename1.title()} case')\n", + "sns.histplot(df_metric2_ro['connectivity'], bins=bins, color='orange', alpha=0.5, label=f'{casename2.title()} case')\n", + "\n", + "# Set y-axis to logarithmic scale\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "\n", + "# Set titles and labels\n", + "plt.title('Distribution of connectivity (nodes > 10, edges < 400)', fontsize=16)\n", + "plt.xlabel('Connectivity')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in', top=True, right=True)\n", + "\n", + "# Add a legend\n", + "plt.legend()\n", + "\n", + "# Show the plot\n", + "plt.tight_layout(rect=[0, 0, 1, 0.99])\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot the distributions of clustering." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "import numpy as np\n", + "\n", + "plt.figure(figsize=(8, 6))\n", + "\n", + "upper_limit = 1e3\n", + "\n", + "# Define the number of bins\n", + "num_bins = 20\n", + "\n", + "# Calculate the combined range for both datasets\n", + "min_value = min(df_metric1_ro['clustering'].min(), df_metric2_ro['clustering'].min())\n", + "max_value = max(df_metric1_ro['clustering'].max(), df_metric2_ro['clustering'].max())\n", + "\n", + "# Create bin edges\n", + "bins = np.linspace(min_value, max_value, num_bins + 1)\n", + "\n", + "# Create a single plot\n", + "sns.histplot(df_metric1_ro['clustering'], bins=bins, color='blue', alpha=0.5, label=f'{casename1.title()} case')\n", + "sns.histplot(df_metric2_ro['clustering'], bins=bins, color='orange', alpha=0.5, label=f'{casename2.title()} case')\n", + "\n", + "# Set y-axis to logarithmic scale\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "\n", + "# Set titles and labels\n", + "plt.title('Distribution of clustering (nodes > 10, edges < 400)', fontsize=16)\n", + "plt.xlabel('Clustering')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in', top=True, right=True)\n", + "\n", + "# Add a legend\n", + "plt.legend()\n", + "\n", + "# Show the plot\n", + "plt.tight_layout(rect=[0, 0, 1, 0.99])\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot the distributions of degree assortivity." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "import numpy as np\n", + "\n", + "plt.figure(figsize=(8, 6))\n", + "\n", + "upper_limit = 1e3\n", + "\n", + "# Define the number of bins\n", + "num_bins = 20\n", + "\n", + "# Calculate the combined range for both datasets\n", + "min_value = min(df_metric1_ro['degree_assortivity'].min(), df_metric2_ro['degree_assortivity'].min())\n", + "max_value = max(df_metric1_ro['degree_assortivity'].max(), df_metric2_ro['degree_assortivity'].max())\n", + "\n", + "# Create bin edges\n", + "bins = np.linspace(min_value, max_value, num_bins + 1)\n", + "\n", + "# Create a single plot\n", + "sns.histplot(df_metric1_ro['degree_assortivity'], bins=bins, color='blue', alpha=0.5, label=f'{casename1.title()} case')\n", + "sns.histplot(df_metric2_ro['degree_assortivity'], bins=bins, color='orange', alpha=0.5, label=f'{casename2.title()} case')\n", + "\n", + "# Set y-axis to logarithmic scale\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "\n", + "# Set titles and labels\n", + "plt.title('Distribution of degree assortivity (nodes > 10, edges < 400)', fontsize=16)\n", + "plt.xlabel('Degree assortivity')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in', top=True, right=True)\n", + "\n", + "# Add a legend\n", + "plt.legend()\n", + "\n", + "# Show the plot\n", + "plt.tight_layout(rect=[0, 0, 1, 0.99])\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.14.6" + }, + "vscode": { + "interpreter": { + "hash": "8c75c0fdd1a718867cdcb84b32adcfdbeaad00b3a4e00a59385211aeed084d4c" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/graph-inspect/inspect-graph-user.ipynb b/graph-inspect/inspect-graph-user.ipynb new file mode 100644 index 0000000..c251f17 --- /dev/null +++ b/graph-inspect/inspect-graph-user.ipynb @@ -0,0 +1,335 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Inspect user interactions\n", + "\n", + "Inspecting the user interactions obtained from the NN, DTC and TC graphs." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Import the dataset." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "casename = '...'\n", + "case = '...'\n", + "\n", + "df_data = pd.read_csv(f'../datasets/{case}-closed-s-users.csv')\n", + "\n", + "df_data.describe()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot the distributions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "\n", + "plt.figure(figsize=(15, 10))\n", + "\n", + "plt.subplot(2,3,1)\n", + "sns.histplot(df_data['nn-count'], bins=20)\n", + "plt.yscale('log')\n", + "plt.title('Distribution of NN interactions')\n", + "plt.xlabel('NN interactions')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(2,3,2)\n", + "sns.histplot(df_data['dtc-count'], bins=20)\n", + "plt.yscale('log')\n", + "plt.title('Distribution of DTC interactions')\n", + "plt.xlabel('DTC interactions')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(2,3,3)\n", + "sns.histplot(df_data['tc-count'], bins=20)\n", + "plt.yscale('log')\n", + "plt.title('Distribution of TC interactions')\n", + "plt.xlabel('TC interactions')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(2,3,4)\n", + "sns.histplot(df_data['post-count'], bins=20)\n", + "plt.yscale('log')\n", + "plt.title('Distribution of posts')\n", + "plt.xlabel('Number of posts')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(2,3,5)\n", + "sns.histplot(df_data['mean-sentiment'], bins=20, kde=True)\n", + "plt.title('Distribution of mean sentiment')\n", + "plt.xlabel('Mean sentiment')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(2,3,6)\n", + "sns.histplot(df_data['std-sentiment'], bins=20, kde=True)\n", + "plt.title('Distribution of SD sentiment')\n", + "plt.xlabel('SD sentiment')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.suptitle(f'Distribution of user metrics {casename} case', fontsize=16)\n", + "plt.tight_layout(rect=[0, 0, 1, 0.99])\n", + "\n", + "plt.savefig(f'../datasets/{case}-user-metrics.png')\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot interaction count against mean sentiment, SD sentiment and post count." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import seaborn as sns\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# Define the pairs of variables for the subplots\n", + "variables = [\n", + " (\"nn-count\", \"mean-sentiment\"),\n", + " (\"dtc-count\", \"mean-sentiment\"),\n", + " (\"tc-count\", \"mean-sentiment\"),\n", + " (\"nn-count\", \"std-sentiment\"),\n", + " (\"dtc-count\", \"std-sentiment\"),\n", + " (\"tc-count\", \"std-sentiment\"),\n", + " (\"nn-count\", \"post-count\"),\n", + " (\"dtc-count\", \"post-count\"),\n", + " (\"tc-count\", \"post-count\"),\n", + "]\n", + "\n", + "# Create the figure\n", + "plt.figure(figsize=(15, 15))\n", + "\n", + "# Loop through the variables and create subplots\n", + "for i, (x_var, y_var) in enumerate(variables):\n", + " plt.subplot(3, 3, i + 1)\n", + " \n", + " # Drop NaN values for the current pair of variables\n", + " df_nonan = df_data.dropna(subset=[x_var, y_var])\n", + " \n", + " # Create scatter plot\n", + " sns.scatterplot(x=x_var, y=y_var, data=df_nonan, alpha=0.4, color=\"black\", edgecolor=None)\n", + " \n", + " # Create Lowess regression plot\n", + " sns.regplot(x=x_var, y=y_var, data=df_nonan, scatter=False, lowess=True, line_kws={'color': 'blue', 'linewidth': 2}, label=\"Lowess fit\")\n", + " \n", + " # Set logarithmic scale for x-axis\n", + " plt.xscale(\"log\")\n", + " \n", + " # Set labels and grid\n", + " plt.xlabel(x_var.replace('-', ' '))\n", + " plt.ylabel(y_var.replace('-', ' '))\n", + " plt.grid()\n", + " plt.legend()\n", + " plt.tick_params(axis='both', direction='in', top=True, right=True)\n", + "\n", + "# Set the overall title and layout\n", + "plt.suptitle(f'Scatter plot of user metrics against interaction count {casename} case', fontsize=16)\n", + "plt.tight_layout(rect=[0, 0, 1, 0.99])\n", + "\n", + "# Save the figure\n", + "plt.savefig(f'../datasets/{case}-user-interaction-scatter.png')\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot (simplified) interaction count against mean sentiment, SD sentiment and post count. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import seaborn as sns\n", + "import matplotlib.pyplot as plt\n", + "from scipy import stats\n", + "\n", + "# Assuming df_data is your DataFrame and casename and case are defined\n", + "plt.figure(figsize=(15, 15))\n", + "\n", + "# Define the pairs of variables for the subplots\n", + "variables = [\n", + " (\"nn-count\", \"mean-sentiment\"),\n", + " (\"dtc-count\", \"mean-sentiment\"),\n", + " (\"tc-count\", \"mean-sentiment\"),\n", + " (\"nn-count\", \"std-sentiment\"),\n", + " (\"dtc-count\", \"std-sentiment\"),\n", + " (\"tc-count\", \"std-sentiment\"),\n", + " (\"nn-count\", \"post-count\"),\n", + " (\"dtc-count\", \"post-count\"),\n", + " (\"tc-count\", \"post-count\"),\n", + "]\n", + "\n", + "# Loop through the variables and create subplots\n", + "for i, (x_var, y_var) in enumerate(variables):\n", + " plt.subplot(3, 3, i + 1)\n", + " \n", + " # Drop NaN values for the current pair of variables\n", + " df_nonan = df_data.dropna(subset=[x_var, y_var])\n", + " \n", + " # Create the regression plot\n", + " sns.regplot(x=x_var, y=y_var, data=df_nonan, scatter=False, ci=68, line_kws={'color': 'blue', 'linewidth': 2})\n", + " \n", + " # Fit the regression model and get r and p values\n", + " slope, intercept, r_value, p_value, std_err = stats.linregress(df_nonan[x_var], df_nonan[y_var])\n", + " \n", + " # Add labels and grid\n", + " plt.xlabel(x_var.replace('-', ' '))\n", + " plt.ylabel(y_var.replace('-', ' '))\n", + " plt.grid()\n", + " plt.tick_params(axis='both', direction='in', top=True, right=True)\n", + " \n", + " # Add text annotation for r and p values\n", + " plt.text(0.05, 0.95, f'r = {r_value:.4f}\\np = {max(p_value, 0.0001):.4f}', transform=plt.gca().transAxes, fontsize=12, verticalalignment='top', bbox=dict(facecolor='white', alpha=0.5))\n", + "\n", + "# Set the overall title and layout\n", + "plt.suptitle(f'Regression plot of user metrics against interaction count {casename} case', fontsize=16)\n", + "plt.tight_layout(rect=[0, 0, 1, 0.99])\n", + "\n", + "# Save the figure\n", + "plt.savefig(f'../datasets/{case}-user-interaction-regression.png')\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Take out change in sentiment regressions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import seaborn as sns\n", + "import matplotlib.pyplot as plt\n", + "from scipy import stats\n", + "\n", + "# Assuming df_data is your DataFrame and casename and case are defined\n", + "fig, axes = plt.subplots(1, 3, figsize=(15, 6), sharey=True)\n", + "\n", + "# Define the variables for std-sentiment plots\n", + "variables = [\n", + " (\"nn-count\", \"std-sentiment\"),\n", + " (\"dtc-count\", \"std-sentiment\"),\n", + " (\"tc-count\", \"std-sentiment\"),\n", + "]\n", + "\n", + "# Loop through the variables and create subplots\n", + "for i, (ax, (x_var, y_var)) in enumerate(zip(axes, variables)):\n", + " # Drop NaN values for the current pair of variables\n", + " df_nonan = df_data.dropna(subset=[x_var, y_var])\n", + " \n", + " # Create the regression plot\n", + " sns.regplot(x=x_var, y=y_var, data=df_nonan, scatter=False, ci=68, line_kws={'color': 'blue', 'linewidth': 2}, ax=ax)\n", + " \n", + " # Fit the regression model and get r and p values\n", + " slope, intercept, r_value, p_value, std_err = stats.linregress(df_nonan[x_var], df_nonan[y_var])\n", + " \n", + " # Add labels and grid\n", + " ax.set_xlabel(x_var.replace('-', ' '))\n", + " if i == 0:\n", + " ax.set_ylabel(y_var.replace('-', ' '))\n", + " else:\n", + " ax.set_ylabel('')\n", + " ax.grid()\n", + " ax.tick_params(axis='both', direction='in', top=True, right=True)\n", + " \n", + " # Add text annotation for r and p values\n", + " ax.text(0.05, 0.95, f'r = {r_value:.4f}\\np = {max(p_value, 0.0001):.4f}', transform=ax.transAxes, fontsize=12, verticalalignment='top', bbox=dict(facecolor='white', alpha=0.5))\n", + "\n", + "# Set the overall title and layout\n", + "plt.suptitle(f'Regression plot of standard deviation of sentiment against interaction count {casename} case', fontsize=16)\n", + "plt.tight_layout(rect=[0, 0, 1, 0.95])\n", + "\n", + "# Save the figure\n", + "plt.savefig(f'../datasets/{case}-user-std-sentiment-regression.png')\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.14.6" + }, + "vscode": { + "interpreter": { + "hash": "8c75c0fdd1a718867cdcb84b32adcfdbeaad00b3a4e00a59385211aeed084d4c" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/graph-inspect/inspect-graph.ipynb b/graph-inspect/inspect-graph.ipynb new file mode 100644 index 0000000..aa838d8 --- /dev/null +++ b/graph-inspect/inspect-graph.ipynb @@ -0,0 +1,671 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Inspect interaction graphs\n", + "\n", + "Inspecting interaction graphs by counting the components, determining the connectivity, clustering and various other metrics. " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Import the graph." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import networkx as nx\n", + "\n", + "casename = '...'\n", + "case = '...'\n", + "\n", + "# Import the graph\n", + "G = nx.read_graphml(f'../datasets/{case}-dtc-graph.graphml')\n", + "\n", + "# Print nodes, edges and density of the graph\n", + "print(f'Nodes: {G.number_of_nodes()}\\nEdges: {G.number_of_edges()}\\nDensity: {nx.density(G):.5f}')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Remove isolated nodes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "G.remove_nodes_from(list(nx.isolates(G)))\n", + "print(f'Nodes: {G.number_of_nodes()}\\nEdges: {G.number_of_edges()}\\nDensity: {nx.density(G):.5f}')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Compute number of connected components." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nx.number_connected_components(G)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Compute metrics of each component." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "components = list(nx.connected_components(G))\n", + "\n", + "component_metrics = []\n", + "\n", + "for component in components:\n", + "\n", + " subG = G.subgraph(component)\n", + "\n", + " num_nodes = subG.number_of_nodes()\n", + " num_edges = subG.number_of_edges()\n", + " diameter = nx.diameter(subG)\n", + " average_degree = (2 * num_edges) / num_nodes\n", + " density = nx.density(subG)\n", + " connectivity = nx.node_connectivity(subG)\n", + " clustering = nx.average_clustering(subG)\n", + " degree_assortivity = nx.degree_assortativity_coefficient(subG)\n", + " sentiment_assortivity = nx.numeric_assortativity_coefficient(subG, 'sentiment')\n", + "\n", + " metrics = {\n", + " 'num_nodes': num_nodes,\n", + " 'num_edges': num_edges,\n", + " 'diameter': diameter,\n", + " 'average_degree': average_degree,\n", + " 'density': density,\n", + " 'connectivity': connectivity,\n", + " 'clustering': clustering,\n", + " 'degree_assortivity': degree_assortivity,\n", + " 'sentiment_assortivity': sentiment_assortivity\n", + " }\n", + "\n", + " component_metrics.append(metrics)\n", + "\n", + "df_metric = pd.DataFrame(component_metrics)\n", + "df_metric.describe()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot the distribution of the metrics." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "\n", + "plt.figure(figsize=(15, 15))\n", + "\n", + "upper_limit = 1e5\n", + "\n", + "plt.subplot(3, 3, 1)\n", + "sns.histplot(df_metric['num_nodes'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of nodes')\n", + "plt.xlabel('Number of nodes')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 2)\n", + "sns.histplot(df_metric['num_edges'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of edges')\n", + "plt.xlabel('Number of edges')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 3)\n", + "sns.histplot(df_metric['diameter'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of diameter')\n", + "plt.xlabel('Diameter')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 4)\n", + "sns.histplot(df_metric['average_degree'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of average degree')\n", + "plt.xlabel('Average degree')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 5)\n", + "sns.histplot(df_metric['density'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(1e1, upper_limit)\n", + "plt.title('Distribution of density')\n", + "plt.xlabel('Density')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 6)\n", + "sns.histplot(df_metric['connectivity'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of connectivity')\n", + "plt.xlabel('Connectivity')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 7)\n", + "sns.histplot(df_metric['clustering'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of clustering')\n", + "plt.xlabel('Clustering')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 8)\n", + "sns.histplot(df_metric['degree_assortivity'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of degree assortivity')\n", + "plt.xlabel('Degree assortivity')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 9)\n", + "sns.histplot(df_metric['sentiment_assortivity'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of sentiment assortivity')\n", + "plt.xlabel('Sentiment assortivity')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.suptitle(f'Metrics {casename} case', fontsize=16)\n", + "plt.tight_layout(rect=[0, 0, 1, 0.99])\n", + "\n", + "plt.savefig(f'../datasets/{case}-metrics.png')\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Filter out the outliers in the dataframe, based on number of edges." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df_metric_ro = df_metric[df_metric['num_edges'] < 400]\n", + "\n", + "df_metric_ro.describe()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot the distribution of the metrics of the outlier filtered dataframe." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Set up the matplotlib figure\n", + "plt.figure(figsize=(15, 15))\n", + "\n", + "upper_limit = 1e5\n", + "\n", + "# Plot distributions\n", + "plt.subplot(3, 3, 1)\n", + "sns.histplot(df_metric_ro['num_nodes'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of nodes')\n", + "plt.xlabel('Number of nodes')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 2)\n", + "sns.histplot(df_metric_ro['num_edges'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of edges')\n", + "plt.xlabel('Number of edges')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 3)\n", + "sns.histplot(df_metric_ro['diameter'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of diameter')\n", + "plt.xlabel('Diameter')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 4)\n", + "sns.histplot(df_metric_ro['average_degree'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of average degree')\n", + "plt.xlabel('Average degree')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 5)\n", + "sns.histplot(df_metric_ro['density'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(1e1, upper_limit)\n", + "plt.title('Distribution of density')\n", + "plt.xlabel('Density')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 6)\n", + "sns.histplot(df_metric_ro['connectivity'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of connectivity')\n", + "plt.xlabel('Connectivity')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 7)\n", + "sns.histplot(df_metric_ro['clustering'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of clustering')\n", + "plt.xlabel('Clustering')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 8)\n", + "sns.histplot(df_metric_ro['degree_assortivity'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of degree assortivity')\n", + "plt.xlabel('Degree assortivity')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 9)\n", + "sns.histplot(df_metric_ro['sentiment_assortivity'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of sentiment assortivity')\n", + "plt.xlabel('Sentiment assortivity')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.suptitle(f'Metrics (edges < 400) {casename} case', fontsize=16)\n", + "plt.tight_layout(rect=[0, 0, 1, 0.99])\n", + "\n", + "plt.savefig(f'../datasets/{case}-metrics-ro.png')\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Filter metrics on number of nodes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df_metric_ls = df_metric[df_metric['num_nodes'] > 10]\n", + "\n", + "df_metric_ls.describe()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot the distribution of the metrics of the large structures set." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Set up the matplotlib figure\n", + "plt.figure(figsize=(15, 15))\n", + "\n", + "upper_limit = 1e3\n", + "\n", + "# Plot distributions\n", + "plt.subplot(3, 3, 1)\n", + "sns.histplot(df_metric_ls['num_nodes'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of nodes')\n", + "plt.xlabel('Number of nodes')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 2)\n", + "sns.histplot(df_metric_ls['num_edges'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of edges')\n", + "plt.xlabel('Number of edges')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 3)\n", + "sns.histplot(df_metric_ls['diameter'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of diameter')\n", + "plt.xlabel('Diameter')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 4)\n", + "sns.histplot(df_metric_ls['average_degree'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of average degree')\n", + "plt.xlabel('Average degree')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 5)\n", + "sns.histplot(df_metric_ls['density'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(1e1, upper_limit)\n", + "plt.title('Distribution of density')\n", + "plt.xlabel('Density')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 6)\n", + "sns.histplot(df_metric_ls['connectivity'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of connectivity')\n", + "plt.xlabel('Connectivity')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 7)\n", + "sns.histplot(df_metric_ls['clustering'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of clustering')\n", + "plt.xlabel('Clustering')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 8)\n", + "sns.histplot(df_metric_ls['degree_assortivity'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of degree assortivity')\n", + "plt.xlabel('Degree assortivity')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 9)\n", + "sns.histplot(df_metric_ls['sentiment_assortivity'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of sentiment assortivity')\n", + "plt.xlabel('Sentiment assortivity')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.suptitle(f'Metrics (nodes > 10) {casename} case', fontsize=16)\n", + "plt.tight_layout(rect=[0, 0, 1, 0.99])\n", + "\n", + "plt.savefig(f'../datasets/{case}-metrics-ls.png')\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Filter out the outliers in the large structures dataset, based on number of edges." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df_metric_ls_ro = df_metric_ls[df_metric_ls['num_edges'] < 400]\n", + "\n", + "df_metric_ls_ro.describe()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Set up the matplotlib figure\n", + "plt.figure(figsize=(15, 15))\n", + "\n", + "upper_limit = 1e3\n", + "\n", + "# Plot distributions\n", + "plt.subplot(3, 3, 1)\n", + "sns.histplot(df_metric_ls_ro['num_nodes'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of nodes')\n", + "plt.xlabel('Number of nodes')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 2)\n", + "sns.histplot(df_metric_ls_ro['num_edges'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of edges')\n", + "plt.xlabel('Number of edges')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 3)\n", + "sns.histplot(df_metric_ls_ro['diameter'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of diameter')\n", + "plt.xlabel('Diameter')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 4)\n", + "sns.histplot(df_metric_ls_ro['average_degree'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of average degree')\n", + "plt.xlabel('Average degree')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 5)\n", + "sns.histplot(df_metric_ls_ro['density'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(1e1, upper_limit)\n", + "plt.title('Distribution of density')\n", + "plt.xlabel('Density')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 6)\n", + "sns.histplot(df_metric_ls_ro['connectivity'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of connectivity')\n", + "plt.xlabel('Connectivity')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 7)\n", + "sns.histplot(df_metric_ls_ro['clustering'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of clustering')\n", + "plt.xlabel('Clustering')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 8)\n", + "sns.histplot(df_metric_ls_ro['degree_assortivity'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of degree assortivity')\n", + "plt.xlabel('Degree assortivity')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.subplot(3, 3, 9)\n", + "sns.histplot(df_metric_ls_ro['sentiment_assortivity'], bins=20)\n", + "plt.yscale('log')\n", + "plt.ylim(0.9, upper_limit)\n", + "plt.title('Distribution of sentiment assortivity')\n", + "plt.xlabel('Sentiment assortivity')\n", + "plt.ylabel('Count')\n", + "plt.grid()\n", + "plt.tick_params(axis='both', direction='in',top=True, right=True)\n", + "\n", + "plt.suptitle(f'Metrics (nodes > 10, edges < 400) {casename} case', fontsize=16)\n", + "plt.tight_layout(rect=[0, 0, 1, 0.99])\n", + "\n", + "plt.savefig(f'../datasets/{case}-metrics-ls-ro.png')\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.14.6" + }, + "vscode": { + "interpreter": { + "hash": "8c75c0fdd1a718867cdcb84b32adcfdbeaad00b3a4e00a59385211aeed084d4c" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}