diff --git a/notebooks/lang_main_config.toml b/notebooks/lang_main_config.toml
index e83d210..ad3247a 100644
--- a/notebooks/lang_main_config.toml
+++ b/notebooks/lang_main_config.toml
@@ -2,12 +2,10 @@
[paths]
inputs = './inputs/'
-results = '../scripts/results/test_20240619/'
+# results = './results/dummy_N_1000/'
+# dataset = '../data/Dummy_Dataset_N_1000.csv'
+results = './results/'
dataset = '../data/02_202307/Export4.csv'
-#results = './results/Export7/'
-#dataset = './01_03_Rohdaten_202403/Export7_59499_Zeilen.csv'
-#results = './results/Export7_trunc/'
-#dataset = './01_03_Rohdaten_202403/Export7_trunc.csv'
# only debugging features, production-ready pipelines should always
# be fully executed
@@ -19,21 +17,18 @@ graph_rescaling_skip = false
graph_static_rendering_skip = false
time_analysis_skip = true
-#[export_filenames]
-#filename_cossim_filter_candidates = 'CosSim-FilterCandidates'
-
[preprocess]
-filename_cossim_filter_candidates = 'CosSim-FilterCandidates'
date_cols = [
- "VorgangsDatum",
- "ErledigungsDatum",
- "Arbeitsbeginn",
+ "VorgangsDatum",
+ "ErledigungsDatum",
+ "Arbeitsbeginn",
"ErstellungsDatum",
]
threshold_amount_characters = 5
threshold_similarity = 0.8
[graph_postprocessing]
+threshold_edge_number = 300
threshold_edge_weight = 150
[time_analysis.uniqueness]
@@ -41,6 +36,10 @@ threshold_unique_texts = 4
criterion_feature = 'HObjektText'
feature_name_obj_id = 'ObjektID'
+[time_analysis.preparation]
+name_delta_feat_to_repair = 'Zeitspanne bis zur Behebung [Tage]'
+name_delta_feat_to_next_failure = 'Zeitspanne bis zum nächsten Ereignis [Tage]'
+
[time_analysis.model_input]
# input_features = [
# 'VorgangsTypName',
diff --git a/notebooks/misc.ipynb b/notebooks/misc.ipynb
index 93f47dc..1a3e8dd 100644
--- a/notebooks/misc.ipynb
+++ b/notebooks/misc.ipynb
@@ -104,7 +104,7 @@
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": 9,
"id": "af118d77-d87a-4687-be5b-e810a24c403e",
"metadata": {
"scrolled": true
@@ -122,7 +122,21 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "2024-08-07 07:36:54 +0000 | io:INFO | Loaded TOML config file successfully.\n"
+ "2024-09-12 12:20:04 +0000 | lang_main:io:INFO | Loaded TOML config file successfully.\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "A:\\Arbeitsaufgaben\\lang-main\\.venv\\Lib\\site-packages\\huggingface_hub\\file_download.py:1132: FutureWarning: `resume_download` is deprecated and will be removed in version 1.0.0. Downloads always resume when possible. If you want to force a new download, use `force_download=True`.\n",
+ " warnings.warn(\n",
+ "A:\\Arbeitsaufgaben\\lang-main\\.venv\\Lib\\site-packages\\transformers\\utils\\generic.py:309: UserWarning: torch.utils._pytree._register_pytree_node is deprecated. Please use torch.utils._pytree.register_pytree_node instead.\n",
+ " _torch_pytree._register_pytree_node(\n",
+ "A:\\Arbeitsaufgaben\\lang-main\\.venv\\Lib\\site-packages\\transformers\\utils\\generic.py:309: UserWarning: torch.utils._pytree._register_pytree_node is deprecated. Please use torch.utils._pytree.register_pytree_node instead.\n",
+ " _torch_pytree._register_pytree_node(\n",
+ "A:\\Arbeitsaufgaben\\lang-main\\.venv\\Lib\\site-packages\\huggingface_hub\\file_download.py:1132: FutureWarning: `resume_download` is deprecated and will be removed in version 1.0.0. Downloads always resume when possible. If you want to force a new download, use `force_download=True`.\n",
+ " warnings.warn(\n"
]
}
],
@@ -132,12 +146,16 @@
"from lang_main import model_loader\n",
"from lang_main.types import LanguageModels\n",
"from lang_main.constants import MODEL_LOADER_MAP\n",
+ "import lang_main.pipelines.predefined as pipes\n",
+ "import lang_main.render.cytoscape as cyto\n",
+ "from lang_main.analysis import graphs\n",
"\n",
"from pathlib import Path\n",
"import pickle\n",
"import base64\n",
"import os\n",
"from logging import NullHandler\n",
+ "import time\n",
"\n",
"import numpy as np\n",
"import networkx as nx\n",
@@ -154,45 +172,868 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 25,
"id": "59cbcf38-6fe1-403b-9c10-f107e28185f0",
"metadata": {},
"outputs": [],
+ "source": [
+ "results = r'A:\\Arbeitsaufgaben\\lang-main\\scripts\\results\\test_20240807'\n",
+ "p_res = Path(results)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "id": "a34650ae-286f-4539-97d1-98dbecd0dafc",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "prefilter = 'TK-GRAPH_POSTPROCESSING.pkl'\n",
+ "postfilter = 'TK-GRAPH_ANALYSIS.pkl'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "id": "313bd956-fc32-4425-9c47-daad3622528b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "p_pre = p_res / prefilter\n",
+ "p_post = p_res / postfilter"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "id": "b745044b-6152-4c69-8fab-016731d57532",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "assert p_pre.exists()\n",
+ "assert p_post.exists()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "id": "7bd52a09-0114-4514-905f-d01d357c6a60",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "2024-09-12 12:33:10 +0000 | lang_main:io:INFO | Loaded file successfully.\n",
+ "2024-09-12 12:33:10 +0000 | lang_main:io:INFO | Loaded file successfully.\n"
+ ]
+ }
+ ],
+ "source": [
+ "res_pre = io.load_pickle(p_pre)\n",
+ "res_post = io.load_pickle(p_post)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "id": "a2a9be43-9ca6-4410-93bf-1e528a8ce8b6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "tkg_pre = res_pre[0]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "id": "7255a466-b421-465b-92a6-27a5e135e083",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "tkg_post = res_post[0]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "id": "dc259aab-ca18-4ab0-bcd0-0d9779c17f2c",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "TokenGraph(name: TokenGraph, number of nodes: 7024, number of edges: 25600)\n",
+ "TokenGraph(name: TokenGraph, number of nodes: 227, number of edges: 330)\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(tkg_pre)\n",
+ "print(tkg_post)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "id": "2faca328-80bb-4e49-be79-6c480c6ef0c6",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "TokenGraph(name: TokenGraph, number of nodes: 351, number of edges: 603)"
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "BOUND = 30\n",
+ "tkg_filt = graphs.filter_graph_by_edge_weight(tkg_pre, bound_lower=BOUND, bound_upper=None)\n",
+ "tkg_filt = graphs.filter_graph_by_node_degree(tkg_filt, bound_lower=1, bound_upper=None)\n",
+ "tkg_filt"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "id": "2fc9c0d6-06d6-4716-821c-1e213d72eb38",
+ "metadata": {
+ "jupyter": {
+ "source_hidden": true
+ },
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "You are connected to Cytoscape!\n",
+ "Applying default style...\n",
+ "Applying preferred layout\n",
+ "Exec time whole was 9.541292 sec\n",
+ "Exec time import was 1.265542 sec\n",
+ "Exec time layout was 3.962870 sec\n",
+ "Exec time style was 4.312881 sec\n"
+ ]
+ }
+ ],
+ "source": [
+ "t1 = time.perf_counter_ns()\n",
+ "cyto.import_to_cytoscape(tkg_filt)\n",
+ "t2 = time.perf_counter_ns()\n",
+ "cyto.layout_network()\n",
+ "t3 = time.perf_counter_ns()\n",
+ "cyto.apply_style_to_network()\n",
+ "t4 = time.perf_counter_ns()\n",
+ "exec_time_whole = (t4 - t1) * 1e-9\n",
+ "exec_time_import = (t2 - t1) * 1e-9\n",
+ "exec_time_layout = (t3 - t2) * 1e-9\n",
+ "exec_time_style = (t4 - t3) * 1e-9\n",
+ "print(f'Exec time whole was {exec_time_whole:.6f} sec')\n",
+ "print(f'Exec time import was {exec_time_import:.6f} sec')\n",
+ "print(f'Exec time layout was {exec_time_layout:.6f} sec')\n",
+ "print(f'Exec time style was {exec_time_style:.6f} sec')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "id": "a68a0fb9-8cfe-4b27-9eb8-6c4895ae3f40",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "render_pipe = pipes.build_tk_graph_render_pipe(with_subgraphs=True, export_folder=Path.cwd())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "id": "f7fc4e3b-7470-4050-92d9-57cbc0f27f69",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "2024-09-12 12:21:28 +0000 | lang_main:base:INFO | Starting pipeline >>Graph_Static-Rendering<<...\n",
+ "You are connected to Cytoscape!\n",
+ "Applying default style...\n",
+ "Applying preferred layout\n",
+ "No nodes selected.\n",
+ "No nodes selected.\n",
+ "No nodes selected.\n",
+ "No nodes selected.\n",
+ "2024-09-12 12:21:42 +0000 | lang_main:io:INFO | Saved file successfully under A:\\Arbeitsaufgaben\\lang-main\\notebooks\\results\\Pipe-Graph_Static-Rendering_Step-6_build_subnetworks.pkl\n",
+ "2024-09-12 12:21:42 +0000 | lang_main:base:INFO | Processing pipeline >>Graph_Static-Rendering<< successfully ended after 6 steps.\n",
+ "Exec time whole was 13.943395 sec\n"
+ ]
+ }
+ ],
+ "source": [
+ "t1 = time.perf_counter_ns()\n",
+ "render_pipe.run((tkg_filt,))\n",
+ "t2 = time.perf_counter_ns()\n",
+ "exec_time_whole = (t2 - t1) * 1e-9\n",
+ "print(f'Exec time whole was {exec_time_whole:.6f} sec')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "46c18cbc-b7b7-427e-8001-f1db5a9679d3",
+ "metadata": {},
+ "outputs": [],
"source": []
},
{
"cell_type": "code",
- "execution_count": 1,
- "id": "a33cb410-f774-4cc9-b972-bf05df36d3d7",
+ "execution_count": 2,
+ "id": "f042d3d9-ea84-4b7e-baba-1d9f6e261277",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "import seaborn as sns\n",
+ "sns.set()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "f2e8f841-d577-4b98-8f72-dee9c908264b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "record1 = [\n",
+ " 168, 203, 262, 351, 465, 726, 1122,\n",
+ " 1368, 1709, 2928\n",
+ "]\n",
+ "record2 = [\n",
+ " 225, 293, 405, 603, 857,\n",
+ " 1317, 2191, 2802, 3765, 7149\n",
+ "]\n",
+ "record3 = [\n",
+ " 12.94, 12.96, 13.55, 14.45, 15.39,\n",
+ " 17.64, 22.90, 26.95, 33.82, 61.75\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "ab400322-4d3e-4502-88fe-d3c68a97d8a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "data = {\n",
+ " 'nodes_num': record1,\n",
+ " 'edges_num': record2,\n",
+ " 'time_sec': record3,\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "459f5450-167c-430c-bded-e47c33073584",
"metadata": {},
"outputs": [
{
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "A:\\Arbeitsaufgaben\\lang-main\\.venv\\Lib\\site-packages\\transformers\\utils\\generic.py:441: UserWarning: torch.utils._pytree._register_pytree_node is deprecated. Please use torch.utils._pytree.register_pytree_node instead.\n",
- " _torch_pytree._register_pytree_node(\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "spacy imports\n",
- "end\n",
- "Nothing\n",
- "2024-08-07 07:51:22 +0000 | io:INFO | Loaded TOML config file successfully.\n"
- ]
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " nodes_num | \n",
+ " edges_num | \n",
+ " time_sec | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 168 | \n",
+ " 225 | \n",
+ " 12.94 | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 203 | \n",
+ " 293 | \n",
+ " 12.96 | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 262 | \n",
+ " 405 | \n",
+ " 13.55 | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 351 | \n",
+ " 603 | \n",
+ " 14.45 | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 465 | \n",
+ " 857 | \n",
+ " 15.39 | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 726 | \n",
+ " 1317 | \n",
+ " 17.64 | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 1122 | \n",
+ " 2191 | \n",
+ " 22.90 | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " 1368 | \n",
+ " 2802 | \n",
+ " 26.95 | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " 1709 | \n",
+ " 3765 | \n",
+ " 33.82 | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " 2928 | \n",
+ " 7149 | \n",
+ " 61.75 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " nodes_num edges_num time_sec\n",
+ "0 168 225 12.94\n",
+ "1 203 293 12.96\n",
+ "2 262 405 13.55\n",
+ "3 351 603 14.45\n",
+ "4 465 857 15.39\n",
+ "5 726 1317 17.64\n",
+ "6 1122 2191 22.90\n",
+ "7 1368 2802 26.95\n",
+ "8 1709 3765 33.82\n",
+ "9 2928 7149 61.75"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
}
],
"source": [
- "from lang_main import __init__"
+ "df = pd.DataFrame.from_dict(data)\n",
+ "df"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "cf445f6c-1d52-4f2a-81df-aa1b1b7bf7cb",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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VPXr109t27ZV7969tW7dOq/tCwoKNG3aNHXp0kUJCQkaO3assrKyvNapaB81QUV9HDp0aJn34s/fr/TxnFOnTumPf/yjkpKSlJCQoIceekgHDx70jFebz0YD29qwYYNp06aNOXHihDl58qTnJy8vz2RlZZnOnTubSZMmmQMHDphVq1aZNm3amFWrVnm2nzt3runcubP5+9//bvbs2WOGDRtmevXqZQoKCgL4qqrG8uXLzbXXXmsGDRrkWWZFzy5kHzVJeX00xpg777zTzJkzx+t9eerUKc84fTRm6NChpk+fPmbbtm3m0KFDZtq0aSY+Pt4cPHjQHDhwwLRp08bMmTPHHDhwwCxatMhcd911ZtOmTZ7tJ06caHr27Gm2bdtmdu7caX73u9+ZgQMHesYvZB81wfn6aIwxXbp0MStWrPB6L2ZnZ3u2p4/nDBgwwNx1111m586d5sCBA+bhhx823bp1M7m5udXqs5HQY2MLFy40t99+e7lj8+fPN926dTNFRUWeZbNnzza9evUyxhhTUFBgEhISzNtvv+0Z//HHH018fLxZu3btxS08gI4fP25GjBhh2rVrZ3r37u31y9qKnlW0j5rifH0sKSkx7dq1M59++mm529JHY44cOWJiY2NNWlqaZ1lJSYnp2bOneemll8yUKVPMnXfe6bVNSkqKGTZsmDHmXP+vvfZas2HDBs/4oUOHTGxsrPniiy+MMabCfdQEFfUxMzPTxMbGmm+++abc7enjOadPnzYpKSlm3759nmV79uwxsbGxZufOndXqs5HDWza2b98+xcTElDuWlpamTp06yeVyeZYlJSXpyJEjyszM1N69e3X27Fl16dLFMx4VFaXrrrtO27Ztu+i1B8o333yj0NBQ/fWvf1Xbtm29xqzoWUX7qCnO18dvv/1Wubm5atasWbnb0kcpOjpaCxcuVJs2bTzLHA6HHA6HcnJylJaW5tUf6dzr3759u4wx2r59u2dZqaZNm6px48ZePTzfPmqCivq4b98+ORwONW3atNzt6eM5devW1ezZsxUbGytJysrK0pIlS9SkSRM1b968Wn02EnpsLD09XVlZWRo4cKCuv/563XPPPfrHP/4hSTp+/LiaNGnitX6jRo0kSceOHdPx48clSZdddlmZdUrHaqLk5GTNnTtXV155ZZkxK3pW0T5qivP1MT09XZK0bNkyJScn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RzVr1iydOHHC63mmTp2qV155RXfccYfmz5+v3r1765lnntFrr70m6VwoGjFihPLy8vTCCy9o3rx5uvTSSzVy5EgdPXq00q9r3Lhxat++vebPn68+ffpo0aJF+stf/lLp/Xz44YdKTU3VjBkzNHnyZKWmpmrQoEFaunSpJkyYoOnTp2vnzp2aPn16pfcNwH+uQBcAIHhERUVp3rx5cjqdks7NtsydO1fZ2dmaNWuWunXrptmzZ3vWT0xM1K233qrFixdr/PjxWrJkidxutxYuXKh69epJkpo2baq7777bs83hw4e1cuVKpaSk6KGHHpIkdevWTQ6HQwsWLNC9996r4uJiHTp0SKNGjdINN9wgSYqPj9err76qwsLCSr+uu+66S6NHj5YkdenSRevXr9eGDRv0+9//vlL7KS4u1quvvqq6detKkj799FP985//1Pr163XllVdKkr788kt98MEHla4RgP+Y6QFwwdq0aeMJPJLUpEkTSdL+/fuVkZGhPn36eK1/1VVXKSEhQVu3bpUkbd++Xe3atfMEHklq27atLr/8cs/jzZs3yxij5ORkFRcXe36Sk5NVUFCg7du3q0GDBmrevLmmTJmiCRMmaO3atSopKdGkSZPUokWLSr+uhIQEr8dNmjRRbm5upfcTExPjCTyS1KBBA0VHR3sCjyRdeuml+umnnyq9bwD+Y6YHwAULDw/3ehwScu7/m0qDUIMGDcps06BBA+3evVuS9OOPP+qKK64os07Dhg09fz99+rQk6bbbbiu3hhMnTsjhcOiNN97Q66+/rs8++0zvv/++QkND1bNnT02bNs0reFyIsLCwMq/LGFOpfUhSnTp1yiyLiIio9H4AXByEHgB+u/TSSyVJmZmZZcYyMjIUHR0tSYqOji53ndKgI507hCZJb731liIjI8usWzor1LhxY02dOlVPPfWU9u7dq48//lj/8z//o+joaD311FP+viQPh8MhSZ4Tm0v5MhMEILA4vAXAb7Vq1VLDhg314Ycfei3/7rvv9OWXXyoxMVGSlJSUpB07dniduHzgwAF99913nscdOnSQJGVnZ6tNmzaen6ysLL388ss6ffq0duzYoeuvv167du2Sw+FQy5Yt9fjjjys2Nlb//ve/LX1tpbM3P6+5qKhIu3btsvR5AFx8zPQA8JvD4VBKSoomTZqksWPH6o477lB2drbnpN6hQ4dKkoYMGaJVq1Zp+PDhevjhh+V2u/Xiiy8qNDTUs6+4uDjdcccdmjJlin744Qe1bt1ahw8f1osvvqgrrrhC11xzjYqLixUWFqbx48fr4YcfVoMGDbRp0ybt2bNH9913n6WvrW7dukpISNCyZct09dVXq27dulq6dKny8/M5dAUEGUIPAEv069dPkZGRWrBggUaPHq06deqoe/fuSklJ8ZyzEx0drXfeeUczZszQxIkTFRkZqQceeEAfffSR176effZZLViwQO+++66OHz+u+vXr69Zbb9Vjjz0mp9Mpp9OpN954Q7Nnz9aMGTOUk5Oja665RtOnT1e/fv0sf23PPfecnn76aT3xxBOqU6eO7rzzTrVv396ny9oBBI7D+HK2HgAAQJBhpgdAjeN2uyu8+srhcHhdfg+g5mOmB0CNk5ycrB9++OG863Tq1KnMrS0A1GyEHgA1zr59+yr8ZubIyEg1a9asiioCUB0QegAAgC3wPT0AAMAWCD0AAMAWCD0AAMAWCD0AAMAWCD0AAMAWCD0AAMAWCD0AAMAW/h8V1mSb3y5ZwgAAAABJRU5ErkJggg==",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "sns.scatterplot(data=df, x='nodes_num', y='time_sec')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "23d5d724-24eb-4f85-b195-b3c9e804f85a",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAG1CAYAAAAFuNXgAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA0iklEQVR4nO3deVyU9d7/8fcwg7IYRq7tCwaWAkKupWZk1snsHPSUp9TKpciljUyzstRuW9Uyy8yDS25lR7nt9njafHTsnDvFxEzvAnFDy1IRkUgBgeH7+8PfzGmCBIeBgYvX8/HgYfP9XnNdn/kA+fZ7XdeMzRhjBAAAYBEB/i4AAADAlwg3AADAUgg3AADAUgg3AADAUgg3AADAUgg3AADAUgg3AADAUgg3AADAUhz+LsAfjDEqL//99y4MCLCdcb4xoAf0QKIHLvSBHkj0QPJvDwICbLLZbNXatlGGm/Jyo7y8k5XOORwBCg8PVUFBocrKyuu4svqBHtADiR640Ad6INEDyf89OO+8UNnt1Qs3nJYCAACWQrgBAACWQrgBAACWQrgBAACWQrgBAACWQrgBAACWQrgBAACWQrgBAACWQrgBAACWQrgBAACWQrgBAACWQrgBAAA+YWw2FZaVK/dEiQrLymWq+UGXvtYoPzgTAAD4ltNm09zVO7Rt11H3WFxUK40ZGCO7qdtPEmflBgAA1IipJNhI0raso5qbuqPOV3AINwAAoEaKSp0Vgo3LtqyjKip11mk9hBsAAFAjhcVlNZr3NcINAACokZCgM1/CW9W8rxFuAABAjQQH2hUX1arSubioVgoOtNdpPYQbAABQIzZjNGZgTIWA47pbylbHd0txKzgAAKgxuzEaNzBGRaVOFRaXKSTIoeBAe50HG4lwAwAAfMRmjEIcAQpp1uT0gB+CjcRpKQAAYDH1ItysWbNGt956q6Kjo9W/f3999NFH7rmDBw8qKSlJ8fHx6tmzp15//XU5nXV7vzwAAGg4/B5uPvzwQz399NMaMmSI1q1bp9tuu03Jycnatm2bSktLNXLkSEnS+++/rylTpui9997TW2+95eeqAQBAfeXXa26MMZo9e7buueceDRkyRJI0evRopaen66uvvtKPP/6on376SR988IGaN2+uyMhIHTt2TK+88ooefPBBNWnSxJ/lAwCAesivKzfZ2dn68ccfNWDAAI/xBQsWKCkpSenp6erQoYOaN2/unuvevbtOnDihzMzMui4XAAA0AH5ducnOzpYkFRYWauTIkcrIyNBFF12k0aNHKyEhQYcPH1bbtm09ntO6dWtJ0qFDhxQbG+v1sR2OynOd3R7g8WdjRA/ogUQPXOgDPZDogdSweuDXcHPixAlJ0sSJEzVu3DiNHz9en3zyicaMGaNFixapuLhYYWFhHs9p2rSpJOnUqVNeHzcgwKbw8NAzbhMWFuz1/q2CHtADiR640Ad6INEDqWH0wK/hJjAwUJI0cuRIJSYmSpKuuuoqZWRkaNGiRQoKClJJSYnHc1yhJiQkxOvjlpcbFRQUVjpntwcoLCxYBQVFcjrLvT5GQ0YP6IFED1zoAz2Q6IHk/x6EhQVXe9XIr+GmTZs2kqTIyEiP8Xbt2mnDhg3q2rWrdu3a5TGXk5Pj8VxvlZWd+RvjdJZXuY3V0QN6INEDF/pADyR6IDWMHvj1xFmHDh0UGhqq7du3e4zv2rVLl1xyibp06aKMjAz36StJSktLU2hoqNq3b1/X5QIAgAbAr+EmKChIo0aN0ltvvaW///3v+v777/X222/ryy+/1PDhw9W3b1+1atVKjz76qHbu3Kn169dr1qxZGjFiBLeBAwCASvn9s6XGjBmj4OBgvfbaazpy5IgiIiI0Z84cdevWTZKUkpKiqVOn6s4771Tz5s119913a8yYMX6uGgAA1Fd+DzeSNHz4cA0fPrzSuUsvvVQLFy6s44oAAEBDVf9vVgcAADgLhBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAp9SLcHDlyRFFRURW+UlNTJUmZmZkaOnSoOnXqpISEBC1ZssTPFQMAgPrK4e8CJGnnzp1q2rSp1q9fL5vN5h4/55xzdPz4cQ0fPlwJCQmaOnWqvvnmG02dOlWhoaEaNGiQH6sGAAD1Ub0IN7t27dJll12m1q1bV5h79913FRgYqGnTpsnhcCgiIkIHDhzQ/PnzCTcAAKCCenFaKisrSxEREZXOpaenq2vXrnI4/pPDunfvrv379ys3N7euSgQAAA1EvVm5CQ8P15AhQ5Sdna1LL71Uo0ePVu/evXX48GFFRkZ6bO9a4Tl06JBatmzp1TEdjspznd0e4PFnY0QP6IFED1zoAz2Q6IHUsHrg93BTVlamffv2qV27dnryySfVrFkzrVu3Tg888IAWLVqk4uJiNWnSxOM5TZs2lSSdOnXKq2MGBNgUHh56xm3CwoK92reV0AN6INEDF/pADyR6IDWMHvg93DgcDm3evFl2u11BQUGSpI4dO2r37t1asGCBgoKCVFJS4vEcV6gJCQnx6pjl5UYFBYWVztntAQoLC1ZBQZGcznKv9t/Q0QN6INEDF/pADyR6IPm/B2FhwdVeNfJ7uJGk0NCKqyhXXnml/vd//1dt27ZVTk6Ox5zrcZs2bbw+ZlnZmb8xTmd5ldtYHT2gBxI9cKEP9ECiB1LD6IHfT5zt3r1b8fHx2rx5s8f4t99+q3bt2qlLly7aunWrnE6ney4tLU2XX365WrRoUdflAgCAes7v4SYiIkJXXHGFpk2bpvT0dO3du1cvvviivvnmG40ePVqDBg3SiRMn9PTTT2vPnj1KTU3V4sWLlZSU5O/SAQBAPeT301IBAQGaN2+eZs6cqUcffVQFBQW6+uqrtWjRIvddUikpKZo+fboSExPVqlUrTZgwQYmJiX6uHAAA1Ed+DzeS1LJlS7344ou/Ox8TE6OVK1fWYUUAAKCh8vtpKQAAAF8i3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEvxOtyUl5dr586d7sdHjx7VF198obKyMp8UBgAA4A2vws2RI0f0xz/+UePGjXOPZWRkKCkpSUOHDlV+fr6v6gMAADgrXoWbV155RSUlJZoxY4Z77Prrr1dqaqry8/M1c+ZMnxUIAABwNrwKNxs3btT48ePVqVMnj/Grr75ajzzyiP75z3/6ojYAAICz5lW4KSkpkd1ur3QuODhYJ0+erFFRAAAA3vIq3MTGxmrRokUqLS31GC8rK9OSJUsUExPjk+IAAADOlsObJz388MMaNmyYbrzxRvXu3VstWrRQXl6evvzySx07dkxLly71dZ0AAADV4lW46dSpk1auXKl58+Zpw4YNys/P1znnnKPOnTtrzJgxuuqqq3xdJwAAQLV4FW6k0xcPv/HGG76sRdnZ2Ro4cKAmT56sgQMHSpIyMzM1ffp0ffvttzrvvPN033336Z577vHpcQEAgHV4HW4k6YsvvtDGjRt19OhRPfbYY8rMzFSHDh104YUXnvW+SktLNX78eBUWFrrHjh8/ruHDhyshIUFTp07VN998o6lTpyo0NFSDBg2qSekAAMCivAo3RUVFGjt2rDZu3KhmzZrp5MmTGjlypN577z1lZGRo2bJluvLKK89qn3PmzFGzZs08xj744AMFBgZq2rRpcjgcioiI0IEDBzR//nzCDQAAqJRXd0vNmjVL3333nRYvXqy0tDQZYyRJL7/8stq0aaPZs2ef1f62bNmilStX6qWXXvIYT09PV9euXeVw/CeDde/eXfv371dubq43pQMAAIvzauXmo48+UnJysrp37y6n0+keb926tUaPHq1p06ZVe18FBQWaMGGCnnnmGZ1//vkec4cPH1ZkZKTHWOvWrSVJhw4dUsuWLb0pX5LkcFSe6+z2AI8/GyN6QA8keuBCH+iBRA+khtUDr8JNQUHB715X07x5c4/rZqoyZcoUxcXFacCAARXmiouL1aRJE4+xpk2bSpJOnTp1FhV7CgiwKTw89IzbhIUFe71/q6AH9ECiBy70gR5I9EBqGD3wKtxceeWVWrt2rXr27Flh7vPPP6/29TZr1qxRenq61q5dW+l8UFCQSkpKPMZcoSYkJOQsq/6P8nKjgoLKA5jdHqCwsGAVFBTJ6Sz3+hgNGT2gBxI9cKEP9ECiB5L/exAWFlztVSOvws3o0aM1btw45efn64YbbpDNZtOWLVuUmpqq999/v9ofnLl69WodO3ZMffr08Rh/7rnn9I9//ENt27ZVTk6Ox5zrcZs2bbwp3a2s7MzfGKezvMptrI4e0AOJHrjQB3og0QOpYfTAq3DTt29fvfrqq5o5c6a++OILSdJLL72kFi1aaMqUKbrllluqtZ8ZM2aouLjYY6xfv356+OGHdfvtt+vDDz/U+++/L6fT6f4sq7S0NF1++eVq0aKFN6UDAACL8/p9bgYMGKABAwZo3759ys/PV1hYmK644goFBFT/QqPfW31p0aKF2rRpo0GDBiklJUVPP/20Ro0apR07dmjx4sWaOnWqt2UDAACLq9Elz4WFhbriiisUHx+vvXv3asmSJdq/f7+PSjsdclJSUpSdna3ExES9+eabmjBhghITE312DAAAYC1erdzs27dPSUlJ6t+/vx599FG9/vrreuedd2SM0WuvvaaFCxfqmmuu8aqgrKwsj8cxMTFauXKlV/sCAACNj1crNzNmzJDD4dCNN96okpISrVixQn/4wx+Unp6uXr166fXXX/dxmQAAANXjVbhJT0/X448/rujoaH311Vf65ZdfNHjwYDVr1kx/+ctf9O233/q6TgAAgGrxKtyUlpYqLCxMkvSvf/1LwcHB7tNQTqfT4+MSAAAA6pJX4SYyMlKffvqpjh49qo8//lg9e/aUw+FQaWmpli9fXuEjEwAAAOqKV+Hm4Ycf1qpVq9S7d2/9/PPPuv/++yVJN998s9LS0jR27FifFgkAAFBdXp0/uu6667R27Vr93//9n2JjY92fM3Xvvfeqe/fuioqK8mmRAAAA1eX1xTEXX3yxLr74Yo+xe++91+Ox0+lUx44dtWrVKnXo0MHbQwEAAFRbrX9uuTGmtg8BAADgVuvhBgAAoC4RbgAAgKUQbgAAgKUQbgAAgKUQbgAAgKUQbgAAgKUQbgAAgKXUargJCAhQYmKiwsPDa/MwAAAAbl6/Q3FeXp4WLFigjRs36ujRo0pJSdH69evVvn179e3bV5Jks9n04osv+qxYAACAqni1cvPDDz/o9ttv1wcffKA2bdro2LFjcjqdys7O1sMPP6wNGzb4uEwAAIDq8Wrl5uWXX1aLFi20dOlShYSEqGPHjpKkmTNn6tSpU5o3b5769OnjyzoBAACqxauVm02bNmnMmDEKCwuTzWbzmBs8eLB2797tk+IAAADOltcXFDsclS/6lJSUVAg8AAAAdcWrcNO5c2e98847KiwsdI/ZbDaVl5frvffeU3x8vM8KBAAAOBteXXPz+OOP66677lK/fv3UrVs32Ww2LViwQHv37tWBAwe0YsUKX9cJAABQLV6t3ERGRmr16tXq1q2bNm/eLLvdro0bN+qSSy7R+++/r6uuusrXdQIAAFSL1+9zc9lll2nmzJm+rAUAAKDGvA43JSUl2rdvn3755ZdK57t06eJ1UQAAAN7yKtxs2rRJjz/+uI4fPy5jjHvcZrPJGCObzabMzEyfFQkAAFBdXoWbF154Qeedd56mTJmic88918clAQAAeM+rcPP9999r7ty5uu6663xdDwAAQI14dbdUVFSUDh065OtaAAAAasyrlZunnnpK48ePl91uV0xMjIKDgytsc8EFF9S4OAAAgLNVo7ulnnrqqd+d54JiAADgD16FmylTpsjhcCg5OVktW7b0dU0A4BPGZlNRqVOFxWUKCXIoONAu26/u8ARgTV6Fm3379umNN95Qnz59fFwOAPiG02bT3NU7tG3XUfdYXFQrjRkYIzsBB7A0ry4ovvTSSz0+NBMA6hNTSbCRpG1ZRzU3dYeMzeanygDUBa/CzSOPPKLXXntNX375pU6ePOnrmgCgRopKnRWCjcu2rKMqKnXWcUUA6pJXp6Vmzpyp3NxcjRo1qtJ5m82mjIyMGhUGAN4qLC6rcj6kWZM6qgZAXfMq3PTv39/XdQCAz4QEnfl/bVXNA2jYvPoNHzdunK/rAACfCQ60Ky6qlbZlVTw1FRfVSsGBdomLigHLqna42bJli66++mqFhoZqy5YtVW7Pp4ID8BebMRozMEZzU3d4BBzX3VLcDg5YW7XDzbBhw/TBBx8oJiZGw4YNc38C+K/xqeAA6gu7MRo3MIb3uQEaoWqHmyVLluiKK65w//eJEyfUrFmzCtsVFBTo1KlTvqsQALxkM0YhjoD/XDxMsAEahWqHm65du7r/+95779XKlSsVExNTYbu0tDQlJydz0TEAAPCLaoebiRMnuj8J3BijKVOmVLpys3//fj6SAQAA+E2138Tv5ptvljHG4zob12PXV0BAgDp16qQXX3yxVooFAACoSrVXbhISEpSQkCDp9MXFU6ZMUURERK0VBgAA4A2v3udm6dKlvq4DAADAJ7z6bCkAAID6inADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAspV6Em2PHjumJJ55Q9+7dFRcXpwceeEB79+51z2dmZmro0KHq1KmTEhIStGTJEj9WCwAA6rN6EW7Gjh2rAwcOaP78+Vq1apWCgoJ03333qaioSMePH9fw4cN1ySWXaPXq1Ro7dqxmzJih1atX+7tsAABQD3n1wZm+9PPPP+vCCy9UUlKSIiMjJUljxozRH//4R+3evVubNm1SYGCgpk2bJofDoYiICHcQGjRokJ+rBwAA9Y3fV26aN2+umTNnuoNNXl6eFi9erLZt26pdu3ZKT09X165d5XD8J4d1795d+/fvV25urr/KBgAA9ZTfV25+bfLkyfrggw/UpEkTvf322woJCdHhw4fdwceldevWkqRDhw6pZcuWXh3L4ag819ntAR5/Nkb0gB5I9MCFPtADiR5IDasH9Src3HvvvRo8eLCWL1+usWPHasWKFSouLlaTJk08tmvatKkk6dSpU14dJyDApvDw0DNuExYW7NW+rYQe0AOJHrjQB3og0QOpYfSgXoWbdu3aSZKmT5+u7du3a9myZQoKClJJSYnHdq5QExIS4tVxysuNCgoKK52z2wMUFhasgoIiOZ3lXu2/oaMH9ECiBy70gR5I9EDyfw/CwoKrvWrk93CTl5enTZs26eabb3ZfVxMQEKB27dopJydHbdu2VU5OjsdzXI/btGnj9XHLys78jXE6y6vcxuroAT2Q6IELfaAHEj2QGkYP/H7iLDc3V8nJydq0aZN7rLS0VBkZGYqIiFCXLl20detWOZ1O93xaWpouv/xytWjRwh8lAwCAeszv4SYyMlK9e/fWf/3Xf2nLli3atWuXnnzySRUUFOi+++7ToEGDdOLECT399NPas2ePUlNTtXjxYiUlJfm7dAAAUA/5PdxI0qxZs9SjRw899thjuuOOO5Sfn6/ly5frggsuUIsWLZSSkqLs7GwlJibqzTff1IQJE5SYmOjvsgEAQD1kM8YYfxdR15zOcuXlnax0zuEIUHh4qI4fP1nvzynWFnpADyR64EIf6IFEDyT/9+C880KrfUFxvVi5AQAA8BXCDQAAsBTCDQAAsBTCDQAAsBTCDQAAsBTCDQAAsBTCDQAAsBTCDQAAsBTCDQAAsBTCDQAAsBTCDdAIGJtNhWXlyj1RosKychmbzd8lAUCtcfi7AAC1y2mzae7qHdq266h7LC6qlcYMjJG98X20HIBGgJUbwMJMJcFGkrZlHdXc1B2s4ACwJMINYGFFpc4KwcZlW9ZRFZU667giAKh9hBvAwgqLy2o0DwANEeEGsLCQoDNfVlfVPAA0RIQbwMKCA+2Ki2pV6VxcVCsFB9rruCIAqH2EG8DCbMZozMCYCgHHdbeUjbulAFgQa9KAxdmN0biBMSoqdaqwuEwhQQ4FB9oJNgAsi3ADNAI2YxTiCFBIsyanBwg2ACyM01IAAMBSCDcAAMBSCDcAAMBSCDcAAMBSCDcAAMBSCDcAAMBSCDcAAMBSCDcAAMBSCDcAAMBSCDcAAMBSCDcAAMBSCDcAAMBSCDcAAMBSCDcAAMBSCDcAAMBSCDcAAMBSCDcAAMBSCDcAAMBSCDeADxibTYVl5co9UaLCsnIZm83fJQFAo+XwdwFAQ+e02TR39Q5t23XUPRYX1UpjBsbIbowfKwOAxomVG6AGTCXBRpK2ZR3V3NQdrOAAgB8QboAaKCp1Vgg2Ltuyjqqo1FnHFQEACDdADRQWl9VoHgDge4QboAZCgs582VpV8wAA3yPcADUQHGhXXFSrSufiolopONBexxUBAAg3QA3YjNGYgTEVAo7rbikbd0sBQJ1jzRyoIbsxGjcwRkWlThUWlykkyKHgQDvBBgD8hHAD+IDNGIU4AhTSrMnpAYINAPgNp6UAAIClEG4AAIClEG4AAIClEG4AAIClEG4AAIClEG4AAIClEG4AAIClEG4AAIClEG4AAICl1Itwk5+fr2effVa9e/dWfHy87rrrLqWnp7vnN23apIEDByo2Nla33HKL1q1b58dqAQBAfVYvwk1ycrK2bdumWbNmafXq1brqqqs0cuRI7du3T3v37lVSUpJ69eql1NRU3XHHHZowYYI2bdrk77IBAEA95PfPljpw4IC+/PJLrVixQtdcc40kafLkyfr3v/+ttWvX6tixY4qKitJjjz0mSYqIiFBGRoZSUlLUo0cPf5YOAADqIb+v3ISHh2v+/PmKjo52j9lsNtlsNhUUFCg9Pb1CiOnevbu2bt0qw4cTAgCA3/D7yk1YWJiuv/56j7FPPvlEBw4c0FNPPaX//u//Vtu2bT3mW7duraKiIh0/flznnXeeV8d1OCrPdXZ7gMefjRE9oAcSPXChD/RAogdSw+qB38PNb3399deaNGmS+vXrpz59+qi4uFhNmjTx2Mb1uKSkxKtjBATYFB4eesZtwsKCvdq3ldADeiDRAxf6QA8keiA1jB7Uq3Czfv16jR8/XvHx8ZoxY4YkqWnTphVCjOtxcLB3DS4vNyooKKx0zm4PUFhYsAoKiuR0lnu1/4aOHtADiR640Ad6INEDyf89CAsLrvaqUb0JN8uWLdP06dN1yy236OWXX3avzpx//vnKycnx2DYnJ0chISE655xzvD5eWdmZvzFOZ3mV21gdPaAHEj1woQ/0QKIHUsPoQb04cbZixQo9//zzGjJkiGbNmuVxGqpz58766quvPLZPS0tTfHy8AgLqRfkAAKAe8fvKTXZ2tl544QXddNNNSkpKUm5urnsuKChIw4YNU2JiombMmKHExER98cUX+vjjj5WSkuLHqgEAQH3l93DzySefqLS0VJ999pk+++wzj7nExES99NJLmjt3rl599VW9++67uuiii/Tqq6/yHjcAAKBSNtMI3yzG6SxXXt7JSuccjgCFh4fq+PGT9f6cYm2hB/RAogcu9IEeSPRA8n8PzjsvtNoXFHPRCgAAsBTCDQAAsBTCDQAAsBTCDQAAsBTCDQAAsBTCDWqdsdlUWFau3BMlKiwrl7HZ/F0SAMDC/P4+N7A2p82muat3aNuuo+6xuKhWGjMwRvbG9y4EAIA6wMoNao2pJNhI0raso5qbuoMVHABArSDcoNYUlTorBBuXbVlHVVTqrOOKAACNAeEGtaawuKxG8wAAeINwg1oTEnTmS7qqmgcAwBuEG9Sa4EC74qJaVToXF9VKwYH2Oq4IANAYEG5Qa2zGaMzAmAoBx3W3lI27pQAAtYDzAqhVdmM0bmCMikqdKiwuU0iQQ8GBdoINAKDWEG5Q62zGKMQRoJBmTU4PEGwAALWI01IAAMBSCDcAAMBSCDcAAMBSCDcAAMBSCDcAAMBSCDeNiLHZVFhWrtwTJSosK+eDKwEAlsSt4I2Es5JP6Ha9mZ6dW7MBABbCyk0jYCoJNtLpT+aem7qDFRwAgKUQbhqBolJnhWDjsi3rqIpKnXVcEQAAtYdw0wgUFpfVaB4AgIaEcNMIhASd+dKqquYBAGhICDeNQHCgvcInc7vERbVScKC9jisCAKD2EG4aiJrcxm0zRmMGxlQIOK67pfiEbgCAlXA+ogHwxW3cdmM0bmCMikqdKiwuU0iQQ8GBdoINAMByWLmp53x5G7fNGIU4AtSyWROFOAIINgAASyLc1HPcxg0AwNkh3NRz3MYNAMDZIdzUc9zGDQDA2SHc+MHZ3PnEbdwAAJwd/tlfx872zifXbdxzU3doW1bF53BRMAAAngg3daiqO5/G/U5Y4TZuAACqj3BTh6pz51OIo/Izha7buEOaNTk9QLABAKBSXHPjI7++jqbIWa7ygIAK19Vw5xMAALWPlRsf+PV1NEFN7HpiaGf9z7/3aftuz2tkRgzoeMb9cOcTAAA1x8pNDf32Oprbe0dUCDbS6dNOWQfyuPMJAIBaRripod9eR9P+0vAKwcYl5cNvlZTIB1gCAFCbOA9SQ7+9TqaktPx3ty0uceqXk6e48wkAgFpEuKmh314n0yTwzIthwU0d3PkEAEAt4rRUDf32HYR3Hjiu2Cu5rgYAAH8h3NSQ6x2EXQHnf/61V7f3uqJCwOG6GgAA6ganpXzgt+8gHBrs0EN3xKq4pIzragAAqGOEGx+pcB1NeTnX1QAA4AeclgIAAJZCuAEAAJZCuAEAAJZCuAEAAJZCuAEAAJZCuAEAAJZCuAEAAJZCuAEAAJZCuAEAAJZCuAEAAJZiM6bxfS6AMUbl5b//su32ADmd5XVYUf1DD+iBRA9c6AM9kOiB5N8eBATYZLPZqrVtoww3AADAujgtBQAALIVwAwAALIVwAwAALIVwAwAALIVwAwAALIVwAwAALIVwAwAALIVwAwAALIVwAwAALIVwAwAALIVwAwAALIVwAwAALIVwAwAALIVw8/+Vl5frjTfeUK9evdSpUyfdf//9+uGHH/xdls+88847GjZsmMdYZmamhg4dqk6dOikhIUFLlizxmK9OT6rah7/l5+fr2WefVe/evRUfH6+77rpL6enp7vlNmzZp4MCBio2N1S233KJ169Z5PP/UqVOaOnWqevToobi4OD3++OPKy8vz2KaqffjbsWPH9MQTT6h79+6Ki4vTAw88oL1797rnG8PPwa9lZ2crLi5Oqamp7rHG0IMjR44oKiqqwperD42hB5K0Zs0a3XrrrYqOjlb//v310UcfuecOHjyopKQkxcfHq2fPnnr99dfldDo9nr98+XLdeOONiomJ0d13362MjAyP+ersw582b95c6c9BVFSUbrzxRkkW6YOBMcaYOXPmmG7dupl//vOfJjMz04wYMcL069fPnDp1yt+l1diyZctM+/btzdChQ91jeXl5plu3bmbSpElmz549ZtWqVSY6OtqsWrXKvU1VPanOPvxt+PDh5rbbbjNbtmwx+/btM1OnTjUxMTFm7969Zs+ePSY6OtrMmjXL7Nmzx6SkpJirr77abNy40f38J5980vTt29ds2bLFbN++3fzpT38yQ4YMcc9XZx/+NnjwYHPHHXeY7du3mz179piHHnrI9OzZ0xQWFjaanwOXkpISM3DgQBMZGWlWr15tjGk8vwsbNmww0dHR5siRIyYnJ8f9VVRU1Gh6sGbNGnP11VebZcuWmQMHDpi5c+ea9u3bm6+//tqUlJSYfv36mQceeMBkZWWZzz77zHTt2tXMnj3b/fzU1FQTExNjPvzwQ7N7927zxBNPmK5du5pjx44ZY0y19uFvp06d8vj+5+TkmE8//dRERUWZVatWWaYPhBtz+psdFxdnli9f7h77+eefTUxMjFm7dq0fK6uZw4cPm6SkJNOpUydzyy23eISbefPmmZ49e5rS0lL32MyZM02/fv2MMdXrSVX78Lf9+/ebyMhIk56e7h4rLy83ffv2Na+//rqZPHmy+fOf/+zxnOTkZDNixAhjzOn+tW/f3mzYsME9v2/fPhMZGWm+/vprY4ypch/+lp+fb5KTk01WVpZ7LDMz00RGRprt27c3ip+DX5s5c6a55557PMJNY+nB/PnzzYABAyqdaww9KC8vNzfccIN56aWXPMZHjBhh5s2bZ9auXWs6duxo8vPz3XPvv/++iY+Pdwe4fv36mVdeecU9X1paaq6//nozb948Y4yp1j7qm5MnT5obbrjBPPnkk8aY6r2GhtAHTktJ2rlzp06ePKkePXq4x8LCwnT11Vdry5YtfqysZr777jsFBgbqf/7nfxQbG+sxl56erq5du8rhcLjHunfvrv379ys3N7daPalqH/4WHh6u+fPnKzo62j1ms9lks9lUUFCg9PR0j9cnna5/69atMsZo69at7jGXyy+/XG3atPHowZn2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/xcFAAAA+BDhBgAAWArhBgAAWArhBgAAWArhBgAAWArhBgAAWArhBgAAWArhBgAAWArhBkCtOXjwoKKiopSamurvUgA0IoQbAABgKYQbAABgKYQbANX2t7/9Tf3791fHjh3Vp08fzZkzR06n0z3/6aef6vbbb1dMTIwSExO1c+fOCvvYu3ev7r//fsXHx+vaa6/Va6+9pkmTJmnYsGHubcrLyzV//nzddNNN6tixo26++WYtXbrUYz/ff/+9HnzwQXXr1k2xsbEaPHiwvvjii7N6PZs3b1ZUVJQ2bdqkESNGKDY2Vtddd51effVV9+v6vVNrTz75pBISEtyPhw0bpmeffVZz585Vr169FBsbq/vvv1+5ublavXq1brrpJsXFxem+++7TwYMHz6pOAGfH4e8CADQM77zzjl577TUNHTpUkyZNUmZmpubMmaNDhw7phRde0Oeff66HH35YAwYM0BNPPKHMzEw98cQTHvvIy8vT0KFD1aJFC7344otyOp2aPXu2fvrpJ3Xq1Mm93ZQpU5SamqqkpCTFxcVpy5YteuGFF1RQUKCxY8eqvLxcSUlJat26tV555RU5HA4tWbJEo0eP1kcffaRLL730rF7b+PHjdffdd+v+++/Xhg0blJKSoosvvlh/+ctfzmo/f//739WhQwdNnz5dhw8f1rRp0zR06FA1bdpUEydOVFFRkZ599llNmzZN8+fPP6t9A6g+wg2AKv3yyy+aO3euBg8erGeeeUaS1LNnT5177rl65plnNHz4cL311luKiYnRq6++Kknq1auXJGnmzJnu/SxdulQnT57UmjVr1KZNG0lSbGysbr75Zvc22dnZ+uCDD5ScnKwHHnjAfSybzaZ33nlHd999t8rKyrRv3z6NGTNG119/vSQpJiZGb775pkpKSs769d1xxx0aO3asJKlHjx5av369NmzYcNbhpqysTG+++aaaN28u6fRK1r///W+tX79eF198sSTpm2++0YcffnjWNQKoPk5LAajStm3bVFxcrISEBJWVlbm/XKdlPv/8c3333Xe64YYbPJ73hz/8weNxWlqa4uLi3MFGki688ELFxcV5bGOMqfRYp06d0tatW9WyZUu1a9dOkydP1sSJE7V27VqVl5dr0qRJuvLKK8/69f36+JLUtm1bFRYWnvV+IiIi3MFGklq2bKnw8HB3sJGkc889V7/88stZ7xtA9bFyA6BK+fn5kuReSfmtgwcPyhij8PBwj/HWrVt7PM7Ly1OHDh0qPL9ly5bKzc31OFb//v0rPdaRI0dks9m0cOFCvf322/rss8+0Zs0aBQYGqm/fvpo6dapHwKiOoKAgj8cBAQEyxpzVPiSpWbNmFcZCQkLOej8AaoZwA6BKYWFhkqQZM2bosssuqzDfsmVLrVq1yh1QXFxBxaVt27YVtpGkY8eOVTjWu+++q9DQ0ArbXnDBBZKkNm3aaMqUKXruuee0c+dOffzxx/rrX/+q8PBwPffcc2f1+s7EZrNJkseF05K8WtkBUDc4LQWgSrGxsQoMDNSRI0cUHR3t/nI4HJo1a5YOHjyouLg4ffrppx4rHp9//rnHfrp06aJvvvlGR48edY/l5OTom2++cT/u3LmzJOn48eMex8rLy9Ps2bOVn5+vbdu26dprr9WOHTtks9l01VVX6bHHHlNkZKR++uknn75212rMkSNH3GOlpaXasWOHT48DwHdYuQFQpfDwcI0aNUqzZ8/WiRMn1K1bNx05ckSzZ8+WzWZT+/btlZycrHvvvVfjxo3T4MGDlZ2drXnz5nns55577tHy5cs1cuRI9wW8c+fOVWlpqXuFJCoqSrfffrsmT56sH3/8UR07dlR2drZee+01XXTRRbrssstUVlamoKAgTZgwQQ899JBatmypjRs3KjMzU/fcc49PX3vz5s0VFxenpUuX6tJLL1Xz5s21ZMkSFRcXc8oJqKcINwCq5dFHH1WrVq20YsUKpaSkqHnz5urRo4eSk5N1zjnnqHPnzvrrX/+qWbNmady4cbrooov0wgsv6MEHH3TvIywsTEuWLNH06dM1YcIEhYaG6u6771ZwcLBHUHjxxRf1zjvv6P3339fhw4fVokUL3XrrrXr00Udlt9tlt9u1cOFCzZw5U9OnT1dBQYEuu+wyTZs2TQMHDvT5a3/ppZf0/PPP65lnnlGzZs305z//Wddcc43+9re/+fxYAGrOZry5ag4AvLB9+3bl5+e7b9+WTt8+3adPH/Xv31+TJk3yY3UArIKVGwB15qefftJjjz2msWPHqmvXrioqKtLKlSv1yy+/6M477/TZcZxOZ5V3O9lsNtntdp8dE0D9wcoNgDr13nvvacWKFfrhhx8UGBio2NhYPfLII4qOjvbZMRISEvTjjz+ecZuuXbtW+EgHANZAuAFgOVlZWVW+U3FoaKiuuOKKOqoIQF0i3AAAAEvhfW4AAIClEG4AAIClEG4AAIClEG4AAIClEG4AAIClEG4AAIClEG4AAICl/D8hDB2aD+8mSwAAAABJRU5ErkJggg==",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "sns.scatterplot(data=df, x='edges_num', y='time_sec')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "id": "5bba09eb-566d-4e27-b48e-3fa56e3a3aa0",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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5ioyMtJ7KwQAAPATbt0c3qFDBy1btkwFBQXauHGj+vTpI0n65ptv9Prrr6tDhw5eXSQAAIA/cOuM0+9//3tlZ2frueee07XXXqthw4ZJklJTU1VaWqoxY8Z4dZEAAAD+wK0zTtddd50+/PBDnT59Wg0aNHBunzdvnlq1asVzmwAAwBXJ7ec4WSwWBQUF6eOPP1ZOTo7uuusuRUZGKigoyJvrAwAA8BtuF6cFCxZo0aJFKi4ulsViUUJCgubMmaP8/HwtW7aMG8QBAMAVx617nFasWKG5c+cqJSVFq1evlvF/T70dOHCgjh07pldffdWriwQAAPAHbhWnt99+W0OHDtXTTz+t1q1bO7ffcccdeuaZZ/iYFQAAcEVyqzj99NNP6tSpU4VjzZs3V25urkeLAgAA8EduFafGjRtr165dFY598803aty4sUeLAgAA8Edu3Rz+wAMPaO7cuQoJCVH37t0lSYWFhdq4caMWLVqklJQUb64RAADAL7hVnIYMGaLjx48rLS1NaWlpkqTHHntMknTvvfcqNTXVeysEAADwE24VJ4vFomnTpiklJUVbt27V2bNnddVVVykpKUlxcXHeXiMAAIBfcPs5TpLUrFkzNWvWzFtrAQAA8GtuFadHH31UFoulwrGAgACFhYXp+uuv14MPPqjmzZt7tEAAAAB/4da76q677jrt3r3b+c66Bg0ayGKxaM+ePdqxY4fy8vL0/vvvq1+/fsrMzPTqggEAAHzFrTNO0dHRuuaaa7Rs2TJdc801zu05OTkaOnSobr/9dqWmpuqpp57SnDlztHjxYq8tGAAAwFfcOuO0du1aPf300y6lSZIaNmyoYcOGaeXKlQoMDFT//v21Z88erywUAADA19wqTkVFRQoKCqpwzGKx6MKFC5KksLAwlZaWur86AAAAP+JWcerQoYNeffXVch+tcvr0ac2bN0+JiYmSpO3bt6tp06aerxIAAMAPuHWP04QJEzRgwAD16NFDiYmJqlevnk6fPq3du3crPDxc6enp+uyzzzRv3jy98MILXl4yAACAb7h1xql58+b68MMPlZKSopKSEn377beSLj1R/KOPPlJsbKyuvvpqzZ49W/379/fqggEAAHzF7QdgRkVF6emnn/6v4wkJCUpISHB3egAAAL9jujitX7++ShPff//9VVwKAACAfzNdnMaPH+/yddmTww3D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qFahoaEuXwcEXPrvt7Iy1aBBg3LHNGjQQJmZmZKks2fPqkmTJuX2iY6Odv75zJkzkqR77rmnwjWcPHlSFotFy5Yt04IFC/SPf/xD69evV1BQkHr06KGpU6e6lBczQkJCyr0uwzCqNIckRURElNsWFhZW5XkA/DIoTgD8wtVXXy1Jys3NLTd26tQpRUVFSZKioqIq3KesLEmXLgdK0ptvvqnw8PBy+5adnWrUqJFeeOEFPf/888rKytJHH32kP/3pT4qKitLzzz/v6UtyslgskuS8WbyMO2ekAPgWl+oA+IXg4GBFR0fr/fffd9l+7Ngx7d69Wx06dJAkde7cWbt27XK5GfzgwYM6duyY8+uOHTtKkvLz89W2bVvnr7y8PL366qs6c+aMdu3apVtvvVV79+6VxWLRTTfdpGeffVZxcXH66aefvPrays4i/XzNFy9e1N69e7369wD45XHGCYBfsFgsGj16tCZMmKDnnntO9913n/Lz8503SqekpEiSHn/8cb377rt68sknNXLkSNntds2ePVtBQUHOueLj43Xfffdp8uTJ+vHHH9WmTRsdPnxYs2fPVpMmTXTDDTfIZrMpJCREY8eO1ciRI9WgQQP97//+r/bt26fHHnvMq6+tbt26SkxM1Ntvv63rr79edevW1VtvvaXi4mIuwwE1DMUJgN/o27evwsPDtWjRIo0YMUIRERHq1q2bRo8e7byHKSoqSn/+8581ffp0jR8/XuHh4Ro8eLA+/PBDl7lefvllLVq0SKtWrVJ2drbq16+vu+++W88884wCAwMVGBioZcuWadasWZo+fboKCgp0ww03aNq0aerbt6/XX9uMGTP04osvatKkSYqIiNADDzygm2++2a1HFgDwHYvhzt2LAAAAtRBnnACgAna7vdJ3xVksFpdHKwC48nHGCQAqkJycrB9//PGy+3Tq1Kncx7gAuLJRnACgAvv376/0CeLh4eFq3rx5Na0IgD+gOAEAAJjEc5wAAABMojgBAACYRHECAAAwieIEAABgEsUJAADAJIoTAACASRQnAAAAk/4/MEI7sh85oAcAAAAASUVORK5CYII=",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "sns.scatterplot(data=df, x='nodes_num', y='edges_num')"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "7f55780a-a91e-49ef-a24f-503eaf2efae8",
+ "id": "ae655662-5c2e-47ec-8650-bb0146323bbc",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "77ebcddb-ad7a-45eb-bff7-d35c33ca4885",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import re"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 35,
+ "id": "37e5c62e-9148-41fc-b30e-bee3e41d58b9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "pattern = r'[(]+'\n",
+ "patt = re.compile(pattern)\n",
+ "pattern = r'[)]+'\n",
+ "patt2 = re.compile(pattern)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 68,
+ "id": "4a621bdf-f825-4f67-8525-a3d74ef426a5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "string = 'Test)1234 und anbei test2 (Änderung)'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 69,
+ "id": "2487ade7-3b03-4e19-a15d-d150145de822",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "string = patt.sub('\\(', string)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 71,
+ "id": "8e0dacf2-2a39-43ae-a1af-5484c4b1f12a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "string = patt2.sub('\\)', string)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 73,
+ "id": "99039e7c-efe5-460f-8e02-54b60e144649",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Test\\)1234 und anbei test2 \\(Änderung\\)\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(string)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "09416b7b-9dee-4517-adab-e9cfbb8c11d2",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "fe9ad00d-4c6e-4db9-8add-e0157cfcf18b",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e70111a8-3110-4445-beb3-0848ae199d15",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 108,
+ "id": "248d29c7-80a6-4854-8393-774e9ff4041c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "cyto.layout_network()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 80,
+ "id": "8fb7a836-292d-446f-91cd-0168e6beb5b2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "pre_c = tkg_pre.copy()\n",
+ "post_c = tkg_post.copy()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "id": "c5681f05-ce64-4ef0-b8f0-db85ea9bc74e",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "92690"
+ ]
+ },
+ "execution_count": 32,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "list(post_c.edges(data='weight'))[0][2]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 87,
+ "id": "8bee6e03-976d-4621-bc74-c67ff4713008",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "original = set(pre_c.edges(data='weight'))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 88,
+ "id": "8751ddbb-c050-4b06-adb5-d9999b2c779f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ret = sorted(original, key=lambda tup: tup[2], reverse=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 89,
+ "id": "54e01e8c-c56e-4a1b-b2b2-0f0250c31df2",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "25600"
+ ]
+ },
+ "execution_count": 89,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(ret)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 90,
+ "id": "ed3506d5-52ea-4c44-a1b2-8ba651eef466",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "chosen = set(ret[:300])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 92,
+ "id": "c347381d-dd98-4b81-a0c7-7173b8bd20c1",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "300"
+ ]
+ },
+ "execution_count": 92,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(chosen)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 94,
+ "id": "33d07e9b-83ab-4794-81e1-472119786bcb",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "drop = original.difference(chosen)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 95,
+ "id": "b500a720-abe3-4a11-9038-bd52a294a704",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "25300"
+ ]
+ },
+ "execution_count": 95,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(drop)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 96,
+ "id": "60e37ec4-1df5-407d-8c53-f61c29e13ac6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "tkg_test = tkg_pre.copy()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 97,
+ "id": "4cbf8d58-60b2-4baa-aad1-a95a35b321b2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "tkg_test.remove_edges_from(drop)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 99,
+ "id": "8a20a28a-0ccc-4baa-ba47-88bf93a40bfa",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "tkg_test = graphs.filter_graph_by_node_degree(tkg_test, bound_lower=1, bound_upper=None)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 100,
+ "id": "05355584-717e-4411-8c6a-6c42d98f6274",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "TokenGraph(name: TokenGraph, number of nodes: 210, number of edges: 300)"
+ ]
+ },
+ "execution_count": 100,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "tkg_test"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 101,
+ "id": "b8be7c17-8011-408d-a3f9-49f799d43bdf",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "OutEdgeDataView([('Wartungstätigkeit', 'Vorgabe', 92690), ('Wartungstätigkeit', 'Maschinenhersteller', 92690), ('Wartungstätigkeit', 'Maschinenbediener', 242), ('Wartungstätigkeit', 'Laserabteilung', 242), ('Wartungstätigkeit', 'Arbeitsplan', 244), ('Wartungstätigkeit', 'abarbeiten', 242), ('Vorgabe', 'Maschinenhersteller', 92690), ('Vorgabe', 'PLEVA', 1369), ('Vorgabe', 'Wartungsplan', 2210), ('Vorgabe', 'sehen', 1905), ('Vorgabe', 'Extradatum', 1905), ('Vorgabe', 'Firma', 730), ('Vorgabe', 'Menzel', 712), ('Vorgabe', 'Vorbelegung', 527), ('Überprüfung', 'Ölabscheider', 1622), ('Überprüfung', 'Leiter', 504), ('Überprüfung', 'Kompensator', 200), ('Überprüfung', 'Verschleiß', 200), ('Überprüfung', 'Dichtigkeit', 212), ('Überprüfung', 'Akku', 165), ('Überprüfung', 'Kran', 90), ('Sichtkontrolle', 'Reinigung', 3450), ('Reinigung', 'Bedarf', 280), ('Reinigung', 'Sichtkontrolle', 239), ('Reinigung', 'Einrichtung', 239), ('Reinigung', 'Luftdruckkontrolle', 239), ('Kontrolle', 'WC-Anlage', 1265), ('Kontrolle', 'Stabbreithalter', 687), ('Kontrolle', 'Kompressorstation', 617), ('Kontrolle', 'Wasseraufbereitungsanlage', 521), ('Kontrolle', 'Heizungsanlage', 520), ('Kontrolle', 'Druckkontrolle', 487), ('Kontrolle', 'bar', 974), ('Kontrolle', 'Rieme', 198), ('Kontrolle', 'Erste-Hilfe-Koffer', 160), ('Kontrolle', 'orange', 160), ('Kontrolle', 'Gesamtanlage', 348), ('Kontrolle', 'Beschädigung', 398), ('Kontrolle', 'usw.', 398), ('Kontrolle', 'Feucht', 141), ('Kontrolle', 'Temperatursensor', 141), ('Kontrolle', 'Hilfe', 141), ('Kontrolle', 'Efficio-System', 141), ('Kontrolle', 'Pflasterschrank', 160), ('Kontrolle', 'Kühlturm', 132), ('Kontrolle', 'Reinigung', 257), ('Kontrolle', 'Schweißkopf', 107), ('Kontrolle', 'Verschleiß', 107), ('Kontrolle', 'prüfen', 107), ('Kontrolle', 'Auslassventil', 127), ('Kontrolle', 'Dampfzylinder', 127), ('Kontrolle', 'Verkalkung', 127), ('Druckkontrolle', 'bar', 974), ('machen', 'gegebenenfalls', 487), ('machen', 'Filter', 487), ('machen', 'sauber', 497), ('Analyse', 'Kesselwasser', 386), ('-', 'Speisewasser', 386), ('-', '-', 386), ('-', 'Kondensat', 386), ('überprüfen', 'Wasserverbrauch', 386), ('auffüllen', 'Desifektionsmittel', 303), ('auffüllen', 'Aschenbecher', 303), ('leeren', 'Aschenbecher', 303), ('Wartung', 'Toilette', 231), ('Wartung', 'Kühlturm', 198), ('Wartungsplan', 'PLEVA', 1369), ('Wartungsplan', 'Firma', 540), ('Wartungsplan', 'Menzel', 525), ('sehen', 'Extradatum', 1939), ('sehen', 'Arbeitsplan', 209), ('sehen', 'Vorbelegung', 533), ('Verschleiß', 'Dichtigkeit', 200), ('schmieren', 'Kontrolle', 198), ('schmieren', 'Rieme', 198), ('schmieren', 'Linearkugellager', 482), ('schmieren', 'neu', 185), ('Maschinenbediener', 'Laserabteilung', 242), ('abarbeiten', 'derzeit', 172), ('abarbeiten', 'Herr', 172), ('abarbeiten', 'Förster', 172), ('Stand', 'Stöppel', 1302), ('Stand', 'Binder', 150), ('Stand', 'KW', 90), ('Stand', 'Moser', 167), ('Stand', 'Termin', 93), ('Stand', 'Prüfung', 119), ('Stand', 'Herr', 161), ('-Leiterprüfung', 'Herr', 344), ('-Leiterprüfung', 'Buschmann', 172), ('-Leiterprüfung', 'derzeit', 172), ('-Leiterprüfung', 'Förster', 172), ('Herr', 'Buschmann', 380), ('Herr', 'derzeit', 175), ('Herr', 'Herr', 240), ('Herr', 'Förster', 695), ('Herr', 'Graf', 571), ('Herr', 'Sturm', 93), ('Herr', 'Stauner', 112), ('Buschmann', 'derzeit', 172), ('Buschmann', 'Herr', 172), ('Buschmann', 'Förster', 172), ('derzeit', 'Herr', 364), ('derzeit', 'Förster', 344), ('terminieren', 'Herr', 416), ('terminieren', 'Buschmann', 172), ('terminieren', 'Absprache', 108), ('reparieren', 'Leiter', 172), ('Prüfung', 'DGUV', 166), ('Prüfung', 'V3', 166), ('V3', 'DGUV', 166), ('Blombe', 'vorhanden', 160), ('Blombe', 'bitte', 160), ('Blombe', 'Ticket', 160), ('Blombe', 'Magazin', 160), ('Ticket', 'Magazin', 320), ('Ticket', 'Bedarf', 160), ('Ticket', 'Verbandsmaterial', 160), ('Ticket', 'bitte', 160), ('Küsters-Anlage', 'Anlage', 241), ('Küsters-Anlage', 'Leckage', 241), ('Küsters-Anlage', 'prüfen', 241), ('prüfen', 'Anlage', 591), ('prüfen', 'Leckage', 589), ('prüfen', 'Sitz', 163), ('prüfen', 'Befestigungsschraube', 132), ('prüfen', 'Verschleiß', 214), ('abschmieren', 'Lager', 241), ('Campen-Aufwickler', 'Linearkugellager', 241), ('Campen-Aufwickler', 'schmieren', 241), ('Campen-Abwickler', 'Linearkugellager', 241), ('Campen-Abwickler', 'schmieren', 241), ('Wumag-Trockner', 'Kontrolle', 241), ('Wumag-Trockner', 'Gesamtanlage', 241), ('Wumag-Trockner', 'Beschädigung', 241), ('Wumag-Trockner', 'usw.', 241), ('Gesamtanlage', 'Anlage', 107), ('Gesamtanlage', 'Leckage', 107), ('Gesamtanlage', 'prüfen', 107), ('Beschädigung', 'usw.', 398), ('Wasseraufbereitung', 'Anlage', 241), ('Wasseraufbereitung', 'Leckage', 241), ('Wasseraufbereitung', 'prüfen', 241), ('Leiterprüfung', 'derzeit', 153), ('Leiterprüfung', 'Arbeit', 153), ('Abteilungsleiter', 'Email', 153), ('Abteilungsleiter', 'Eigenverantwortlichkeit', 153), ('Abteilungsleiter', 'Mithilfe', 153), ('Abteilungsleiter', 'Herr', 155), ('Abteilungsleiter', 'Graf', 153), ('Email', 'Eigenverantwortlichkeit', 306), ('Email', 'Mithilfe', 306), ('Email', 'Herr', 306), ('Email', 'Graf', 306), ('Eigenverantwortlichkeit', 'Mithilfe', 459), ('Eigenverantwortlichkeit', 'Herr', 459), ('Eigenverantwortlichkeit', 'Graf', 459), ('Mithilfe', 'Herr', 306), ('Mithilfe', 'Graf', 306), ('informieren', 'Email', 154), ('informieren', 'Eigenverantwortlichkeit', 153), ('informieren', 'Mithilfe', 153), ('informieren', 'Herr', 171), ('informieren', 'Graf', 153), ('Feucht', 'Temperatursensor', 141), ('Hilfe', 'Efficio-System', 141), ('abgleichen', 'Messwert', 141), ('Bedarf', 'Verbandsmaterial', 160), ('Auflistung', 'Verbandsmaterial', 160), ('finden', 'Auflistung', 160), ('finden', 'Verbandsmaterial', 160), ('finden', 'Extradate', 160), ('finden', 'UTT', 160), ('finden', 'intern', 160), ('finden', 'Objekt', 160), ('Extradate', 'UTT', 160), ('Extradate', 'intern', 160), ('Extradate', 'Objekt', 160), ('UTT', 'intern', 160), ('UTT', 'Objekt', 160), ('Firma', 'Hawker', 165), ('Firma', 'Menzel', 712), ('Firma', 'MHM', 161), ('Abschmierung', 'Ventilator', 209), ('Abschmierung', 'Motor', 209), ('Ventilator', 'Motor', 221), ('Motor', 'ansonsten', 209), ('Motor', 'Bedarf', 209), ('durchführen', 'Monat', 209), ('Erledigungsdatum', 'Motor', 209), ('Erledigungsdatum', 'ansonsten', 209), ('Erledigungsdatum', 'Bedarf', 209), ('ansonsten', 'Bedarf', 209), ('anschreiben', 'Motor', 209), ('anschreiben', 'ansonsten', 209), ('anschreiben', 'Bedarf', 209), ('Wäscherkontrolle', 'Reinigung', 209), ('Wäscherkontrolle', 'Bedarf', 209), ('Wäscherkontrolle', 'Trommel', 209), ('Formplatte', 'Sitz', 107), ('Formplatte', 'Befestigungsschraube', 107), ('Formplatte', 'prüfen', 107), ('Sitz', 'Befestigungsschraube', 132), ('Gegendruckbolze', 'Verschleiß', 107), ('Gegendruckbolze', 'prüfen', 107), ('Schweißkopf', 'Verschleiß', 107), ('Schweißkopf', 'prüfen', 107), ('Karabulut', 'Sherif', 98), ('Leerung', 'Papiermüllbehälter', 106), ('Leerung', 'Keller', 106), ('Leerung', 'Personalbüro', 106), ('Keller', 'Personalbüro', 107), ('Verschmutzung', 'Fremdkörper', 164), ('Sicherstellung', 'Ausblasöffnung', 164), ('Indikator', 'Testomat', 133), ('Wartungsarbeit', 'sehen', 207), ('Wartungsarbeit', 'Arbeitsplan', 207), ('Vorbelegung', 'Extradatum', 527), ('Stehlagergehäus', 'SNI', 493), ('Stehlagergehäus', 'Nachschmieren', 493), ('Flanschlager', 'RIZ60', 493), ('Spannkopflager', 'TIU-60', 493), ('Inneneinheit', 'Kontrollieren', 127), ('Inneneinheit', 'Fileren', 127), ('Inneneinheit', 'Verschmutzung', 127), ('Kontrollieren', 'Fileren', 127), ('Kontrollieren', 'Verschmutzung', 127), ('Kontrollieren', 'Temperatur', 127), ('Kontrollieren', 'Feucht', 127), ('Außeneinheit', 'Luftansaugseite', 127), ('Außeneinheit', 'Sauberkeit', 127), ('Außeneinheit', 'Filter', 127), ('Außeneinheit', 'kontrollieren', 127), ('Luftansaugseite', 'Sauberkeit', 127), ('Luftansaugseite', 'Filter', 127), ('Luftansaugseite', 'kontrollieren', 127), ('Sauberkeit', 'Filter', 127), ('kontrollieren', 'Sauberkeit', 127), ('kontrollieren', 'Filter', 127), ('achten', 'Laufgeräusch', 127), ('Befeuchter', 'Kontrollieren', 127), ('Befeuchter', 'Feucht', 127), ('Auslassventil', 'Dampfzylinder', 127), ('Einrichtung', 'Luftdruckkontrolle', 240), ('anfragen', 'Termin', 361), ('anfragen', 'Schneider', 361), ('Termin', 'Schneider', 360), ('reinigen', 'SAE50', 185), ('reinigen', 'Bedarf', 185), ('reinigen', 'Woche', 185), ('reinigen', 'Monat', 185), ('reinigen', 'neu', 186), ('Uhr', 'ca.', 119), ('Lagerung', 'Palette', 282), ('Lagerung', 'Fach', 188), ('Lagerung', 'Hochregal', 188), ('Lagerung', 'Halle', 188), ('Lagerung', 'so', 188), ('Lagerung', 'zulässig', 188), ('Palette', 'Fach', 141), ('Palette', 'Hochregal', 141), ('Palette', 'Halle', 141), ('Palette', 'so', 188), ('Palette', 'zulässig', 188), ('Fach', 'Hochregal', 188), ('Fach', 'Halle', 188), ('Fach', 'so', 141), ('Fach', 'zulässig', 141), ('Hochregal', 'Halle', 188), ('Hochregal', 'so', 141), ('Hochregal', 'zulässig', 141), ('Halle', 'so', 141), ('Halle', 'zulässig', 141), ('so', 'zulässig', 188), ('zulässig', 'so', 94), ('noch', 'Haus', 107), ('Prüfbericht', 'noch', 189), ('Prüfbericht', 'Haus', 108), ('Absprache', 'Herr', 238), ('tauschen', 'Lager', 211), ('Rauwalze', 'Einziehwalze', 1275), ('Rauwalze', 'neu', 637), ('Einziehwalze', 'neu', 636), ('überziehen', 'neu', 678), ('erfolgen', 'Prüfung', 125), ('Baugruppe', 'Pos-Nr', 185), ('Baugruppe', 'Nr.', 185), ('Baugruppe', 'Stückliste', 185), ('Nr.', 'Stückliste', 185), ('ME-Nummer', 'Bezeichnung', 185), ('verbauen', 'Hersteller', 185), ('verbauen', 'Anzahl', 185), ('verbauen', 'Schmierstoff', 185), ('Wartungsintervall', 'Wechselintervall', 185), ('Rollenkette-zweifach', 'Öl', 185), ('SAE50', 'Bedarf', 185), ('Kettbaum', 'Gewind', 270), ('Kettbaum', 'nachschneiden', 270), ('nachschneiden', 'Gewind', 279), ('laufen', 'Maschine', 93)])"
+ ]
+ },
+ "execution_count": 101,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "tkg_test.edges(data='weight')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "11040820-9dce-4acd-b9ce-113dc1857084",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 63,
+ "id": "9fb559ca-658f-4fd7-943b-5509eacccb56",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "s1 = {1,2,3}\n",
+ "s2 = {1,2,3,4,5,6}"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 64,
+ "id": "0e093317-d708-4dda-a2b2-aaf31f237594",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{4, 5, 6}"
+ ]
+ },
+ "execution_count": 64,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "s2.difference(s1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f151211e-dcfb-4fa5-8590-0d4b5b75efc5",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6c49661f-5cb0-4a55-97c6-98ef562aba3d",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "000ea2c0-8ec4-45c2-a69b-8ff0f27bd742",
"metadata": {},
"outputs": [],
"source": []
diff --git a/pdm.lock b/pdm.lock
index c916a9b..43eaa42 100644
--- a/pdm.lock
+++ b/pdm.lock
@@ -5,7 +5,7 @@
groups = ["default", "dev", "notebooks", "trails", "trials"]
strategy = ["inherit_metadata"]
lock_version = "4.5.0"
-content_hash = "sha256:468a23f2e765abd2cf8760a33a219a4e475f1ebc73630f792eddf6563293720a"
+content_hash = "sha256:09aa90447c8cad5f9c18eeedf7b383574dcf5143110ed90033a9652757538544"
[[metadata.targets]]
requires_python = ">=3.11"
@@ -453,6 +453,68 @@ files = [
{file = "confection-0.1.4.tar.gz", hash = "sha256:e80f22fd008b5231a2e8852fac6de9e28f2276a04031d0536cff74fe4a990c8f"},
]
+[[package]]
+name = "contourpy"
+version = "1.3.0"
+requires_python = ">=3.9"
+summary = "Python library for calculating contours of 2D quadrilateral grids"
+groups = ["dev"]
+dependencies = [
+ "numpy>=1.23",
+]
+files = [
+ {file = "contourpy-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fa4c02abe6c446ba70d96ece336e621efa4aecae43eaa9b030ae5fb92b309ad"},
+ {file = "contourpy-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:834e0cfe17ba12f79963861e0f908556b2cedd52e1f75e6578801febcc6a9f49"},
+ {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbc4c3217eee163fa3984fd1567632b48d6dfd29216da3ded3d7b844a8014a66"},
+ {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4865cd1d419e0c7a7bf6de1777b185eebdc51470800a9f42b9e9decf17762081"},
+ {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:303c252947ab4b14c08afeb52375b26781ccd6a5ccd81abcdfc1fafd14cf93c1"},
+ {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637f674226be46f6ba372fd29d9523dd977a291f66ab2a74fbeb5530bb3f445d"},
+ {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:76a896b2f195b57db25d6b44e7e03f221d32fe318d03ede41f8b4d9ba1bff53c"},
+ {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e1fd23e9d01591bab45546c089ae89d926917a66dceb3abcf01f6105d927e2cb"},
+ {file = "contourpy-1.3.0-cp311-cp311-win32.whl", hash = "sha256:d402880b84df3bec6eab53cd0cf802cae6a2ef9537e70cf75e91618a3801c20c"},
+ {file = "contourpy-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:6cb6cc968059db9c62cb35fbf70248f40994dfcd7aa10444bbf8b3faeb7c2d67"},
+ {file = "contourpy-1.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:570ef7cf892f0afbe5b2ee410c507ce12e15a5fa91017a0009f79f7d93a1268f"},
+ {file = "contourpy-1.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:da84c537cb8b97d153e9fb208c221c45605f73147bd4cadd23bdae915042aad6"},
+ {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0be4d8425bfa755e0fd76ee1e019636ccc7c29f77a7c86b4328a9eb6a26d0639"},
+ {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c0da700bf58f6e0b65312d0a5e695179a71d0163957fa381bb3c1f72972537c"},
+ {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb8b141bb00fa977d9122636b16aa67d37fd40a3d8b52dd837e536d64b9a4d06"},
+ {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3634b5385c6716c258d0419c46d05c8aa7dc8cb70326c9a4fb66b69ad2b52e09"},
+ {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0dce35502151b6bd35027ac39ba6e5a44be13a68f55735c3612c568cac3805fd"},
+ {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aea348f053c645100612b333adc5983d87be69acdc6d77d3169c090d3b01dc35"},
+ {file = "contourpy-1.3.0-cp312-cp312-win32.whl", hash = "sha256:90f73a5116ad1ba7174341ef3ea5c3150ddf20b024b98fb0c3b29034752c8aeb"},
+ {file = "contourpy-1.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:b11b39aea6be6764f84360fce6c82211a9db32a7c7de8fa6dd5397cf1d079c3b"},
+ {file = "contourpy-1.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3e1c7fa44aaae40a2247e2e8e0627f4bea3dd257014764aa644f319a5f8600e3"},
+ {file = "contourpy-1.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:364174c2a76057feef647c802652f00953b575723062560498dc7930fc9b1cb7"},
+ {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32b238b3b3b649e09ce9aaf51f0c261d38644bdfa35cbaf7b263457850957a84"},
+ {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d51fca85f9f7ad0b65b4b9fe800406d0d77017d7270d31ec3fb1cc07358fdea0"},
+ {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:732896af21716b29ab3e988d4ce14bc5133733b85956316fb0c56355f398099b"},
+ {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d73f659398a0904e125280836ae6f88ba9b178b2fed6884f3b1f95b989d2c8da"},
+ {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c6c7c2408b7048082932cf4e641fa3b8ca848259212f51c8c59c45aa7ac18f14"},
+ {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f317576606de89da6b7e0861cf6061f6146ead3528acabff9236458a6ba467f8"},
+ {file = "contourpy-1.3.0-cp313-cp313-win32.whl", hash = "sha256:31cd3a85dbdf1fc002280c65caa7e2b5f65e4a973fcdf70dd2fdcb9868069294"},
+ {file = "contourpy-1.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:4553c421929ec95fb07b3aaca0fae668b2eb5a5203d1217ca7c34c063c53d087"},
+ {file = "contourpy-1.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:345af746d7766821d05d72cb8f3845dfd08dd137101a2cb9b24de277d716def8"},
+ {file = "contourpy-1.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3bb3808858a9dc68f6f03d319acd5f1b8a337e6cdda197f02f4b8ff67ad2057b"},
+ {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:420d39daa61aab1221567b42eecb01112908b2cab7f1b4106a52caaec8d36973"},
+ {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d63ee447261e963af02642ffcb864e5a2ee4cbfd78080657a9880b8b1868e18"},
+ {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:167d6c890815e1dac9536dca00828b445d5d0df4d6a8c6adb4a7ec3166812fa8"},
+ {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:710a26b3dc80c0e4febf04555de66f5fd17e9cf7170a7b08000601a10570bda6"},
+ {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:75ee7cb1a14c617f34a51d11fa7524173e56551646828353c4af859c56b766e2"},
+ {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:33c92cdae89ec5135d036e7218e69b0bb2851206077251f04a6c4e0e21f03927"},
+ {file = "contourpy-1.3.0.tar.gz", hash = "sha256:7ffa0db17717a8ffb127efd0c95a4362d996b892c2904db72428d5b52e1938a4"},
+]
+
+[[package]]
+name = "cycler"
+version = "0.12.1"
+requires_python = ">=3.8"
+summary = "Composable style cycles"
+groups = ["dev"]
+files = [
+ {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"},
+ {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"},
+]
+
[[package]]
name = "cymem"
version = "2.0.8"
@@ -670,6 +732,33 @@ files = [
{file = "flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842"},
]
+[[package]]
+name = "fonttools"
+version = "4.53.1"
+requires_python = ">=3.8"
+summary = "Tools to manipulate font files"
+groups = ["dev"]
+files = [
+ {file = "fonttools-4.53.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:da33440b1413bad53a8674393c5d29ce64d8c1a15ef8a77c642ffd900d07bfe1"},
+ {file = "fonttools-4.53.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ff7e5e9bad94e3a70c5cd2fa27f20b9bb9385e10cddab567b85ce5d306ea923"},
+ {file = "fonttools-4.53.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6e7170d675d12eac12ad1a981d90f118c06cf680b42a2d74c6c931e54b50719"},
+ {file = "fonttools-4.53.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bee32ea8765e859670c4447b0817514ca79054463b6b79784b08a8df3a4d78e3"},
+ {file = "fonttools-4.53.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e08f572625a1ee682115223eabebc4c6a2035a6917eac6f60350aba297ccadb"},
+ {file = "fonttools-4.53.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b21952c092ffd827504de7e66b62aba26fdb5f9d1e435c52477e6486e9d128b2"},
+ {file = "fonttools-4.53.1-cp311-cp311-win32.whl", hash = "sha256:9dfdae43b7996af46ff9da520998a32b105c7f098aeea06b2226b30e74fbba88"},
+ {file = "fonttools-4.53.1-cp311-cp311-win_amd64.whl", hash = "sha256:d4d0096cb1ac7a77b3b41cd78c9b6bc4a400550e21dc7a92f2b5ab53ed74eb02"},
+ {file = "fonttools-4.53.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d92d3c2a1b39631a6131c2fa25b5406855f97969b068e7e08413325bc0afba58"},
+ {file = "fonttools-4.53.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3b3c8ebafbee8d9002bd8f1195d09ed2bd9ff134ddec37ee8f6a6375e6a4f0e8"},
+ {file = "fonttools-4.53.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32f029c095ad66c425b0ee85553d0dc326d45d7059dbc227330fc29b43e8ba60"},
+ {file = "fonttools-4.53.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f5e6c3510b79ea27bb1ebfcc67048cde9ec67afa87c7dd7efa5c700491ac7f"},
+ {file = "fonttools-4.53.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f677ce218976496a587ab17140da141557beb91d2a5c1a14212c994093f2eae2"},
+ {file = "fonttools-4.53.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9e6ceba2a01b448e36754983d376064730690401da1dd104ddb543519470a15f"},
+ {file = "fonttools-4.53.1-cp312-cp312-win32.whl", hash = "sha256:791b31ebbc05197d7aa096bbc7bd76d591f05905d2fd908bf103af4488e60670"},
+ {file = "fonttools-4.53.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ed170b5e17da0264b9f6fae86073be3db15fa1bd74061c8331022bca6d09bab"},
+ {file = "fonttools-4.53.1-py3-none-any.whl", hash = "sha256:f1f8758a2ad110bd6432203a344269f445a2907dc24ef6bccfd0ac4e14e0d71d"},
+ {file = "fonttools-4.53.1.tar.gz", hash = "sha256:e128778a8e9bc11159ce5447f76766cefbd876f44bd79aff030287254e4752c4"},
+]
+
[[package]]
name = "fqdn"
version = "1.5.1"
@@ -1260,6 +1349,64 @@ files = [
{file = "kaleido-0.2.1-py2.py3-none-win_amd64.whl", hash = "sha256:4670985f28913c2d063c5734d125ecc28e40810141bdb0a46f15b76c1d45f23c"},
]
+[[package]]
+name = "kiwisolver"
+version = "1.4.7"
+requires_python = ">=3.8"
+summary = "A fast implementation of the Cassowary constraint solver"
+groups = ["dev"]
+files = [
+ {file = "kiwisolver-1.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d2b0e12a42fb4e72d509fc994713d099cbb15ebf1103545e8a45f14da2dfca54"},
+ {file = "kiwisolver-1.4.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2a8781ac3edc42ea4b90bc23e7d37b665d89423818e26eb6df90698aa2287c95"},
+ {file = "kiwisolver-1.4.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46707a10836894b559e04b0fd143e343945c97fd170d69a2d26d640b4e297935"},
+ {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef97b8df011141c9b0f6caf23b29379f87dd13183c978a30a3c546d2c47314cb"},
+ {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ab58c12a2cd0fc769089e6d38466c46d7f76aced0a1f54c77652446733d2d02"},
+ {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:803b8e1459341c1bb56d1c5c010406d5edec8a0713a0945851290a7930679b51"},
+ {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9a9e8a507420fe35992ee9ecb302dab68550dedc0da9e2880dd88071c5fb052"},
+ {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18077b53dc3bb490e330669a99920c5e6a496889ae8c63b58fbc57c3d7f33a18"},
+ {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6af936f79086a89b3680a280c47ea90b4df7047b5bdf3aa5c524bbedddb9e545"},
+ {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3abc5b19d24af4b77d1598a585b8a719beb8569a71568b66f4ebe1fb0449460b"},
+ {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:933d4de052939d90afbe6e9d5273ae05fb836cc86c15b686edd4b3560cc0ee36"},
+ {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:65e720d2ab2b53f1f72fb5da5fb477455905ce2c88aaa671ff0a447c2c80e8e3"},
+ {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3bf1ed55088f214ba6427484c59553123fdd9b218a42bbc8c6496d6754b1e523"},
+ {file = "kiwisolver-1.4.7-cp311-cp311-win32.whl", hash = "sha256:4c00336b9dd5ad96d0a558fd18a8b6f711b7449acce4c157e7343ba92dd0cf3d"},
+ {file = "kiwisolver-1.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:929e294c1ac1e9f615c62a4e4313ca1823ba37326c164ec720a803287c4c499b"},
+ {file = "kiwisolver-1.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:e33e8fbd440c917106b237ef1a2f1449dfbb9b6f6e1ce17c94cd6a1e0d438376"},
+ {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:5360cc32706dab3931f738d3079652d20982511f7c0ac5711483e6eab08efff2"},
+ {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942216596dc64ddb25adb215c3c783215b23626f8d84e8eff8d6d45c3f29f75a"},
+ {file = "kiwisolver-1.4.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:48b571ecd8bae15702e4f22d3ff6a0f13e54d3d00cd25216d5e7f658242065ee"},
+ {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad42ba922c67c5f219097b28fae965e10045ddf145d2928bfac2eb2e17673640"},
+ {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:612a10bdae23404a72941a0fc8fa2660c6ea1217c4ce0dbcab8a8f6543ea9e7f"},
+ {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e838bba3a3bac0fe06d849d29772eb1afb9745a59710762e4ba3f4cb8424483"},
+ {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22f499f6157236c19f4bbbd472fa55b063db77a16cd74d49afe28992dff8c258"},
+ {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693902d433cf585133699972b6d7c42a8b9f8f826ebcaf0132ff55200afc599e"},
+ {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4e77f2126c3e0b0d055f44513ed349038ac180371ed9b52fe96a32aa071a5107"},
+ {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:657a05857bda581c3656bfc3b20e353c232e9193eb167766ad2dc58b56504948"},
+ {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4bfa75a048c056a411f9705856abfc872558e33c055d80af6a380e3658766038"},
+ {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:34ea1de54beef1c104422d210c47c7d2a4999bdecf42c7b5718fbe59a4cac383"},
+ {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:90da3b5f694b85231cf93586dad5e90e2d71b9428f9aad96952c99055582f520"},
+ {file = "kiwisolver-1.4.7-cp312-cp312-win32.whl", hash = "sha256:18e0cca3e008e17fe9b164b55735a325140a5a35faad8de92dd80265cd5eb80b"},
+ {file = "kiwisolver-1.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:58cb20602b18f86f83a5c87d3ee1c766a79c0d452f8def86d925e6c60fbf7bfb"},
+ {file = "kiwisolver-1.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:f5a8b53bdc0b3961f8b6125e198617c40aeed638b387913bf1ce78afb1b0be2a"},
+ {file = "kiwisolver-1.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2e6039dcbe79a8e0f044f1c39db1986a1b8071051efba3ee4d74f5b365f5226e"},
+ {file = "kiwisolver-1.4.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a1ecf0ac1c518487d9d23b1cd7139a6a65bc460cd101ab01f1be82ecf09794b6"},
+ {file = "kiwisolver-1.4.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7ab9ccab2b5bd5702ab0803676a580fffa2aa178c2badc5557a84cc943fcf750"},
+ {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f816dd2277f8d63d79f9c8473a79fe54047bc0467754962840782c575522224d"},
+ {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf8bcc23ceb5a1b624572a1623b9f79d2c3b337c8c455405ef231933a10da379"},
+ {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dea0bf229319828467d7fca8c7c189780aa9ff679c94539eed7532ebe33ed37c"},
+ {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c06a4c7cf15ec739ce0e5971b26c93638730090add60e183530d70848ebdd34"},
+ {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:913983ad2deb14e66d83c28b632fd35ba2b825031f2fa4ca29675e665dfecbe1"},
+ {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5337ec7809bcd0f424c6b705ecf97941c46279cf5ed92311782c7c9c2026f07f"},
+ {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4c26ed10c4f6fa6ddb329a5120ba3b6db349ca192ae211e882970bfc9d91420b"},
+ {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c619b101e6de2222c1fcb0531e1b17bbffbe54294bfba43ea0d411d428618c27"},
+ {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:073a36c8273647592ea332e816e75ef8da5c303236ec0167196793eb1e34657a"},
+ {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3ce6b2b0231bda412463e152fc18335ba32faf4e8c23a754ad50ffa70e4091ee"},
+ {file = "kiwisolver-1.4.7-cp313-cp313-win32.whl", hash = "sha256:f4c9aee212bc89d4e13f58be11a56cc8036cabad119259d12ace14b34476fd07"},
+ {file = "kiwisolver-1.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:8a3ec5aa8e38fc4c8af308917ce12c536f1c88452ce554027e55b22cbbfbff76"},
+ {file = "kiwisolver-1.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:76c8094ac20ec259471ac53e774623eb62e6e1f56cd8690c67ce6ce4fcb05650"},
+ {file = "kiwisolver-1.4.7.tar.gz", hash = "sha256:9893ff81bd7107f7b685d3017cc6583daadb4fc26e4a888350df530e41980a60"},
+]
+
[[package]]
name = "langcodes"
version = "3.4.0"
@@ -1375,6 +1522,51 @@ files = [
{file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"},
]
+[[package]]
+name = "matplotlib"
+version = "3.9.2"
+requires_python = ">=3.9"
+summary = "Python plotting package"
+groups = ["dev"]
+dependencies = [
+ "contourpy>=1.0.1",
+ "cycler>=0.10",
+ "fonttools>=4.22.0",
+ "importlib-resources>=3.2.0; python_version < \"3.10\"",
+ "kiwisolver>=1.3.1",
+ "numpy>=1.23",
+ "packaging>=20.0",
+ "pillow>=8",
+ "pyparsing>=2.3.1",
+ "python-dateutil>=2.7",
+]
+files = [
+ {file = "matplotlib-3.9.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d8dd059447824eec055e829258ab092b56bb0579fc3164fa09c64f3acd478772"},
+ {file = "matplotlib-3.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c797dac8bb9c7a3fd3382b16fe8f215b4cf0f22adccea36f1545a6d7be310b41"},
+ {file = "matplotlib-3.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d719465db13267bcef19ea8954a971db03b9f48b4647e3860e4bc8e6ed86610f"},
+ {file = "matplotlib-3.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8912ef7c2362f7193b5819d17dae8629b34a95c58603d781329712ada83f9447"},
+ {file = "matplotlib-3.9.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7741f26a58a240f43bee74965c4882b6c93df3e7eb3de160126d8c8f53a6ae6e"},
+ {file = "matplotlib-3.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:ae82a14dab96fbfad7965403c643cafe6515e386de723e498cf3eeb1e0b70cc7"},
+ {file = "matplotlib-3.9.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ac43031375a65c3196bee99f6001e7fa5bdfb00ddf43379d3c0609bdca042df9"},
+ {file = "matplotlib-3.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be0fc24a5e4531ae4d8e858a1a548c1fe33b176bb13eff7f9d0d38ce5112a27d"},
+ {file = "matplotlib-3.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf81de2926c2db243c9b2cbc3917619a0fc85796c6ba4e58f541df814bbf83c7"},
+ {file = "matplotlib-3.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6ee45bc4245533111ced13f1f2cace1e7f89d1c793390392a80c139d6cf0e6c"},
+ {file = "matplotlib-3.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:306c8dfc73239f0e72ac50e5a9cf19cc4e8e331dd0c54f5e69ca8758550f1e1e"},
+ {file = "matplotlib-3.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:5413401594cfaff0052f9d8b1aafc6d305b4bd7c4331dccd18f561ff7e1d3bd3"},
+ {file = "matplotlib-3.9.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:18128cc08f0d3cfff10b76baa2f296fc28c4607368a8402de61bb3f2eb33c7d9"},
+ {file = "matplotlib-3.9.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4876d7d40219e8ae8bb70f9263bcbe5714415acfdf781086601211335e24f8aa"},
+ {file = "matplotlib-3.9.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d9f07a80deab4bb0b82858a9e9ad53d1382fd122be8cde11080f4e7dfedb38b"},
+ {file = "matplotlib-3.9.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7c0410f181a531ec4e93bbc27692f2c71a15c2da16766f5ba9761e7ae518413"},
+ {file = "matplotlib-3.9.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:909645cce2dc28b735674ce0931a4ac94e12f5b13f6bb0b5a5e65e7cea2c192b"},
+ {file = "matplotlib-3.9.2-cp313-cp313-win_amd64.whl", hash = "sha256:f32c7410c7f246838a77d6d1eff0c0f87f3cb0e7c4247aebea71a6d5a68cab49"},
+ {file = "matplotlib-3.9.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:37e51dd1c2db16ede9cfd7b5cabdfc818b2c6397c83f8b10e0e797501c963a03"},
+ {file = "matplotlib-3.9.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b82c5045cebcecd8496a4d694d43f9cc84aeeb49fe2133e036b207abe73f4d30"},
+ {file = "matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f053c40f94bc51bc03832a41b4f153d83f2062d88c72b5e79997072594e97e51"},
+ {file = "matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbe196377a8248972f5cede786d4c5508ed5f5ca4a1e09b44bda889958b33f8c"},
+ {file = "matplotlib-3.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5816b1e1fe8c192cbc013f8f3e3368ac56fbecf02fb41b8f8559303f24c5015e"},
+ {file = "matplotlib-3.9.2.tar.gz", hash = "sha256:96ab43906269ca64a6366934106fa01534454a69e471b7bf3d79083981aaab92"},
+]
+
[[package]]
name = "matplotlib-inline"
version = "0.1.7"
@@ -1552,7 +1744,7 @@ name = "numpy"
version = "1.26.4"
requires_python = ">=3.9"
summary = "Fundamental package for array computing in Python"
-groups = ["default"]
+groups = ["default", "dev"]
files = [
{file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"},
{file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"},
@@ -1763,7 +1955,7 @@ name = "packaging"
version = "24.0"
requires_python = ">=3.7"
summary = "Core utilities for Python packages"
-groups = ["default", "notebooks"]
+groups = ["default", "dev", "notebooks"]
files = [
{file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"},
{file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"},
@@ -1774,7 +1966,7 @@ name = "pandas"
version = "2.2.2"
requires_python = ">=3.9"
summary = "Powerful data structures for data analysis, time series, and statistics"
-groups = ["default"]
+groups = ["default", "dev"]
dependencies = [
"numpy>=1.22.4; python_version < \"3.11\"",
"numpy>=1.23.2; python_version == \"3.11\"",
@@ -1842,7 +2034,7 @@ name = "pillow"
version = "10.3.0"
requires_python = ">=3.8"
summary = "Python Imaging Library (Fork)"
-groups = ["default"]
+groups = ["default", "dev"]
files = [
{file = "pillow-10.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795"},
{file = "pillow-10.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57"},
@@ -2121,12 +2313,23 @@ files = [
{file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"},
]
+[[package]]
+name = "pyparsing"
+version = "3.1.4"
+requires_python = ">=3.6.8"
+summary = "pyparsing module - Classes and methods to define and execute parsing grammars"
+groups = ["dev"]
+files = [
+ {file = "pyparsing-3.1.4-py3-none-any.whl", hash = "sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c"},
+ {file = "pyparsing-3.1.4.tar.gz", hash = "sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032"},
+]
+
[[package]]
name = "python-dateutil"
version = "2.9.0.post0"
requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
summary = "Extensions to the standard Python datetime module"
-groups = ["default", "notebooks"]
+groups = ["default", "dev", "notebooks"]
dependencies = [
"six>=1.5",
]
@@ -2150,7 +2353,7 @@ files = [
name = "pytz"
version = "2024.1"
summary = "World timezone definitions, modern and historical"
-groups = ["default"]
+groups = ["default", "dev"]
files = [
{file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"},
{file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"},
@@ -2558,6 +2761,22 @@ files = [
{file = "scipy-1.13.0.tar.gz", hash = "sha256:58569af537ea29d3f78e5abd18398459f195546bb3be23d16677fb26616cc11e"},
]
+[[package]]
+name = "seaborn"
+version = "0.13.2"
+requires_python = ">=3.8"
+summary = "Statistical data visualization"
+groups = ["dev"]
+dependencies = [
+ "matplotlib!=3.6.1,>=3.4",
+ "numpy!=1.24.0,>=1.20",
+ "pandas>=1.2",
+]
+files = [
+ {file = "seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987"},
+ {file = "seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7"},
+]
+
[[package]]
name = "send2trash"
version = "1.8.3"
@@ -2606,7 +2825,7 @@ name = "six"
version = "1.16.0"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
summary = "Python 2 and 3 compatibility utilities"
-groups = ["default", "notebooks"]
+groups = ["default", "dev", "notebooks"]
files = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
@@ -3199,7 +3418,7 @@ name = "tzdata"
version = "2024.1"
requires_python = ">=2"
summary = "Provider of IANA time zone data"
-groups = ["default"]
+groups = ["default", "dev"]
files = [
{file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"},
{file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"},
diff --git a/pyproject.toml b/pyproject.toml
index 5a7bb6d..a515abb 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -46,6 +46,7 @@ trials = [
dev = [
"cython>=3.0.10",
"openpyxl>=3.1.5",
+ "seaborn>=0.13.2",
]
[tool.ruff]
diff --git a/scripts/analyse_dataset.py b/scripts/analyse_dataset.py
index e7c96a0..a489050 100644
--- a/scripts/analyse_dataset.py
+++ b/scripts/analyse_dataset.py
@@ -42,8 +42,8 @@ from lang_main.types import (
)
# ** profiling
-ONLY_PROFILING_REPORT: Final[bool] = True
-USE_PROFILING: Final[bool] = True
+USE_PROFILING: Final[bool] = False
+ONLY_PROFILING_REPORT: Final[bool] = False
PROFILE_REPORT_NAME: Final[str] = 'prof_report.profdata'
# ** build pipelines
diff --git a/scripts/lang_main_config.toml b/scripts/lang_main_config.toml
index 653eacf..41e4305 100644
--- a/scripts/lang_main_config.toml
+++ b/scripts/lang_main_config.toml
@@ -6,43 +6,40 @@ inputs = './inputs/'
# dataset = '../data/Dummy_Dataset_N_1000.csv'
results = './results/test_20240807/'
dataset = '../data/02_202307/Export4.csv'
-#results = './results/Export7/'
-#dataset = './01_03_Rohdaten_202403/Export7_59499_Zeilen.csv'
-#results = './results/Export7_trunc/'
-#dataset = './01_03_Rohdaten_202403/Export7_trunc.csv'
# only debugging features, production-ready pipelines should always
# be fully executed
[control]
-preprocessing_skip = false
-token_analysis_skip = false
+preprocessing_skip = true
+token_analysis_skip = true
graph_postprocessing_skip = false
graph_rescaling_skip = false
graph_static_rendering_skip = false
-time_analysis_skip = false
-
-#[export_filenames]
-#filename_cossim_filter_candidates = 'CosSim-FilterCandidates'
+time_analysis_skip = true
[preprocess]
-filename_cossim_filter_candidates = 'CosSim-FilterCandidates'
date_cols = [
- "VorgangsDatum",
- "ErledigungsDatum",
- "Arbeitsbeginn",
+ "VorgangsDatum",
+ "ErledigungsDatum",
+ "Arbeitsbeginn",
"ErstellungsDatum",
]
threshold_amount_characters = 5
threshold_similarity = 0.8
[graph_postprocessing]
-threshold_edge_weight = 150
+threshold_edge_number = 330
+# threshold_edge_weight = 150
[time_analysis.uniqueness]
threshold_unique_texts = 4
criterion_feature = 'HObjektText'
feature_name_obj_id = 'ObjektID'
+[time_analysis.preparation]
+name_delta_feat_to_repair = 'Zeitspanne bis zur Behebung [Tage]'
+name_delta_feat_to_next_failure = 'Zeitspanne bis zum nächsten Ereignis [Tage]'
+
[time_analysis.model_input]
# input_features = [
# 'VorgangsTypName',
diff --git a/src/lang_main/analysis/graphs.py b/src/lang_main/analysis/graphs.py
index 1935cdf..35ff65a 100644
--- a/src/lang_main/analysis/graphs.py
+++ b/src/lang_main/analysis/graphs.py
@@ -5,7 +5,7 @@ import sys
import typing
from collections.abc import Hashable, Iterable
from pathlib import Path
-from typing import Any, Final, Literal, Self, cast, overload
+from typing import Any, Literal, Self, cast, overload
import networkx as nx
import numpy as np
@@ -15,9 +15,14 @@ from pandas import DataFrame
from lang_main.constants import (
EDGE_WEIGHT_DECIMALS,
+ LOGGING_DEFAULT_GRAPHS,
PROPERTY_NAME_DEGREE_WEIGHTED,
)
-from lang_main.errors import EdgePropertyNotContainedError, EmptyEdgesError, EmptyGraphError
+from lang_main.errors import (
+ EdgePropertyNotContainedError,
+ EmptyEdgesError,
+ EmptyGraphError,
+)
from lang_main.io import load_pickle, save_pickle
from lang_main.loggers import logger_graphs as logger
from lang_main.types import (
@@ -27,9 +32,6 @@ from lang_main.types import (
WeightData,
)
-# TODO change logging behaviour, add logging to file
-LOGGING_DEFAULT: Final[bool] = False
-
def save_to_GraphML(
graph: DiGraph | Graph,
@@ -45,7 +47,7 @@ def save_to_GraphML(
def get_graph_metadata(
graph: Graph | DiGraph,
- logging: bool = LOGGING_DEFAULT,
+ logging: bool = LOGGING_DEFAULT_GRAPHS,
) -> dict[str, int]:
# info about graph
graph_info: dict[str, int] = {}
@@ -121,7 +123,7 @@ def update_graph(
# build undirected adjacency matrix
def convert_graph_to_undirected(
graph: DiGraph,
- logging: bool = LOGGING_DEFAULT,
+ logging: bool = LOGGING_DEFAULT_GRAPHS,
cast_int: bool = False,
) -> Graph:
dtype = np.float32
@@ -282,6 +284,23 @@ def filter_graph_by_node_degree(
return filtered_graph
+def filter_graph_by_number_edges(
+ graph: TokenGraph,
+ limit: int,
+ property: str = 'weight',
+ descending: bool = True,
+) -> TokenGraph:
+ graph = graph.copy()
+ # edges
+ original = set(graph.edges(data=property)) # type: ignore
+ original_sorted = sorted(original, key=lambda tup: tup[2], reverse=descending)
+ chosen = set(original_sorted[:limit])
+ edges_to_drop = original.difference(chosen)
+ graph.remove_edges_from(edges_to_drop)
+
+ return graph
+
+
def add_weighted_degree(
graph: DiGraph | Graph,
edge_weight_property: str = 'weight',
diff --git a/src/lang_main/constants.py b/src/lang_main/constants.py
index 88a789c..e656b1b 100644
--- a/src/lang_main/constants.py
+++ b/src/lang_main/constants.py
@@ -1,10 +1,6 @@
from pathlib import Path
from typing import Final
-# TODO check removal
-# import spacy
-# from sentence_transformers import SentenceTransformer
-# from spacy.language import Language as GermanSpacyModel
from lang_main import CONFIG, CYTO_PATH_STYLESHEET
from lang_main import model_loader as m_load
from lang_main.types import (
@@ -20,19 +16,20 @@ __all__ = [
'CYTO_PATH_STYLESHEET',
]
+# ** logging
+# graphs
+LOGGING_DEFAULT_GRAPHS: Final[bool] = False
+
# ** paths
input_path_conf = Path.cwd() / Path(CONFIG['paths']['inputs'])
INPUT_PATH_FOLDER: Final[Path] = input_path_conf.resolve()
-# INPUT_PATH_FOLDER: Final[Path] = (CALLER_PATH / input_path_conf).resolve()
# TODO reactivate later
# if not INPUT_PATH_FOLDER.exists():
# raise FileNotFoundError(f'Input path >>{INPUT_PATH_FOLDER}<< does not exist.')
save_path_conf = Path.cwd() / Path(CONFIG['paths']['results'])
SAVE_PATH_FOLDER: Final[Path] = save_path_conf.resolve()
-# SAVE_PATH_FOLDER: Final[Path] = (CALLER_PATH / save_path_conf).resolve()
path_dataset_conf = Path.cwd() / Path(CONFIG['paths']['dataset'])
PATH_TO_DATASET: Final[Path] = path_dataset_conf.resolve()
-# PATH_TO_DATASET: Final[Path] = (CALLER_PATH / path_dataset_conf).resolve()
# if not PATH_TO_DATASET.exists():
# raise FileNotFoundError(f'Dataset path >>{PATH_TO_DATASET}<< does not exist.')
# ** control
@@ -64,20 +61,9 @@ MODEL_LOADER_MAP: Final[ModelLoaderMap] = {
},
},
}
-# ** sentence_transformers
-
-# STFR_MODEL: Final[SentenceTransformer] = SentenceTransformer(
-# 'sentence-transformers/all-mpnet-base-v2', device=STFR_DEVICE
-# )
-
-# ** spacy
-# SPCY_MODEL: Final[GermanSpacyModel] = spacy.load('de_dep_news_trf')
# ** export
# ** preprocessing
-FILENAME_COSSIM_FILTER_CANDIDATES: Final[str] = CONFIG['preprocess'][
- 'filename_cossim_filter_candidates'
-]
DATE_COLS: Final[list[str]] = CONFIG['preprocess']['date_cols']
THRESHOLD_AMOUNT_CHARACTERS: Final[float] = CONFIG['preprocess'][
'threshold_amount_characters'
@@ -87,10 +73,13 @@ THRESHOLD_SIMILARITY: Final[float] = CONFIG['preprocess']['threshold_similarity'
# ** graph postprocessing
EDGE_WEIGHT_DECIMALS: Final[int] = 4
-THRESHOLD_EDGE_WEIGHT: Final[int] = CONFIG['graph_postprocessing']['threshold_edge_weight']
+THRESHOLD_EDGE_NUMBER: Final[int] = CONFIG['graph_postprocessing']['threshold_edge_number']
+# THRESHOLD_EDGE_WEIGHT: Final[int] = CONFIG['graph_postprocessing']['threshold_edge_weight']
PROPERTY_NAME_DEGREE_WEIGHTED: Final[str] = 'degree_weighted'
# ** graph exports (Cytoscape)
+CYTO_MAX_NODE_COUNT: Final[int] = 500
+CYTO_MAX_EDGE_COUNT: Final[int] = 800
CYTO_COLLECTION_NAME: Final[str] = 'lang_main'
CYTO_BASE_NETWORK_NAME: Final[str] = 'token_graph'
CYTO_LAYOUT_NAME: Final[CytoLayouts] = 'force-directed'
@@ -119,9 +108,14 @@ UNIQUE_CRITERION_FEATURE: Final[str] = CONFIG['time_analysis']['uniqueness'][
]
FEATURE_NAME_OBJ_ID: Final[str] = CONFIG['time_analysis']['uniqueness']['feature_name_obj_id']
# ** time_analysis.preparation
-NAME_DELTA_FEAT_TO_REPAIR: Final[str] = 'delta_to_repair'
-# NAME_DELTA_FEAT_TO_REPAIR: Final[str] = 'Zeitspanne bis zur Behebung [Tage]'
-NAME_DELTA_FEAT_TO_NEXT_FAILURE: Final[str] = 'Zeitspanne bis zum nächsten Ereignis [Tage]'
+# NAME_DELTA_FEAT_TO_REPAIR: Final[str] = 'delta_to_repair'
+CONFIG['time_analysis']['preparation']['name_delta_feat_to_repair']
+NAME_DELTA_FEAT_TO_REPAIR: Final[str] = CONFIG['time_analysis']['preparation'][
+ 'name_delta_feat_to_repair'
+]
+NAME_DELTA_FEAT_TO_NEXT_FAILURE: Final[str] = CONFIG['time_analysis']['preparation'][
+ 'name_delta_feat_to_next_failure'
+]
# ** time_analysis.model_input
MODEL_INPUT_FEATURES: Final[tuple[str, ...]] = tuple(
CONFIG['time_analysis']['model_input']['input_features']
diff --git a/src/lang_main/errors.py b/src/lang_main/errors.py
index 2292524..f999e67 100644
--- a/src/lang_main/errors.py
+++ b/src/lang_main/errors.py
@@ -10,3 +10,7 @@ class EmptyGraphError(Exception):
class EmptyEdgesError(EmptyGraphError):
"""Error raised if action should be performed on a graph's edges, but
it does not contain any"""
+
+
+class GraphRenderError(Exception):
+ """Error raised if a graph object can not be rendered"""
diff --git a/src/lang_main/lang_main_config.toml b/src/lang_main/lang_main_config.toml
index 3c00289..3a7a171 100644
--- a/src/lang_main/lang_main_config.toml
+++ b/src/lang_main/lang_main_config.toml
@@ -2,12 +2,10 @@
[paths]
inputs = './inputs/'
-results = './results/test_20240619/'
+# results = './results/dummy_N_1000/'
+# dataset = '../data/Dummy_Dataset_N_1000.csv'
+results = './results/test_20240807/'
dataset = '../data/02_202307/Export4.csv'
-#results = './results/Export7/'
-#dataset = './01_03_Rohdaten_202403/Export7_59499_Zeilen.csv'
-#results = './results/Export7_trunc/'
-#dataset = './01_03_Rohdaten_202403/Export7_trunc.csv'
# only debugging features, production-ready pipelines should always
# be fully executed
@@ -19,28 +17,29 @@ graph_rescaling_skip = false
graph_static_rendering_skip = false
time_analysis_skip = true
-#[export_filenames]
-#filename_cossim_filter_candidates = 'CosSim-FilterCandidates'
-
[preprocess]
-filename_cossim_filter_candidates = 'CosSim-FilterCandidates'
date_cols = [
- "VorgangsDatum",
- "ErledigungsDatum",
- "Arbeitsbeginn",
+ "VorgangsDatum",
+ "ErledigungsDatum",
+ "Arbeitsbeginn",
"ErstellungsDatum",
]
threshold_amount_characters = 5
threshold_similarity = 0.8
[graph_postprocessing]
-threshold_edge_weight = 150
+threshold_edge_number = 330
+# threshold_edge_weight = 150
[time_analysis.uniqueness]
threshold_unique_texts = 4
criterion_feature = 'HObjektText'
feature_name_obj_id = 'ObjektID'
+[time_analysis.preparation]
+name_delta_feat_to_repair = 'Zeitspanne bis zur Behebung [Tage]'
+name_delta_feat_to_next_failure = 'Zeitspanne bis zum nächsten Ereignis [Tage]'
+
[time_analysis.model_input]
# input_features = [
# 'VorgangsTypName',
diff --git a/src/lang_main/pipelines/predefined.py b/src/lang_main/pipelines/predefined.py
index c074ebe..c1cf2e7 100644
--- a/src/lang_main/pipelines/predefined.py
+++ b/src/lang_main/pipelines/predefined.py
@@ -34,7 +34,7 @@ from lang_main.constants import (
NAME_DELTA_FEAT_TO_REPAIR,
SAVE_PATH_FOLDER,
THRESHOLD_AMOUNT_CHARACTERS,
- THRESHOLD_EDGE_WEIGHT,
+ THRESHOLD_EDGE_NUMBER,
THRESHOLD_NUM_ACTIVITIES,
THRESHOLD_SIMILARITY,
THRESHOLD_TIMELINE_SIMILARITY,
@@ -89,31 +89,6 @@ def build_base_target_feature_pipe() -> Pipeline:
return pipe_target_feat
-# output: DataFrame containing target feature with
-# number of occurrences and associated ObjectIDs
-
-# ** embedding pipe
-# ?? still needed?
-# using similarity between entries to catch duplicates with typo or similar content
-# pipe_embds = BasePipeline(name='Embedding1', working_dir=SAVE_PATH_FOLDER)
-
-
-# pipe_embds.add(build_cosSim_matrix, {'model': model_stfr}, save_result=True)
-# pipe_embds.add(
-# filt_thresh_cosSim_matrix, {'threshold': THRESHOLD_SIMILARITY}, save_result=True
-# )
-# pipe_embds.add(
-# list_cosSim_dupl_candidates,
-# {
-# 'save_candidates': True,
-# 'saving_path': SAVE_PATH_FOLDER,
-# 'filename': FILENAME_COSSIM_FILTER_CANDIDATES,
-# 'pipeline': pipe_embds,
-# },
-# save_result=True,
-# )
-
-
# ** Merge duplicates
def build_merge_duplicates_pipe() -> Pipeline:
pipe_merge = Pipeline(name='Merge_Duplicates', working_dir=SAVE_PATH_FOLDER)
@@ -162,11 +137,18 @@ def build_tk_graph_post_pipe() -> Pipeline:
pipe_graph_postprocessing = Pipeline(
name='Graph_Postprocessing', working_dir=SAVE_PATH_FOLDER
)
+ # pipe_graph_postprocessing.add(
+ # graphs.filter_graph_by_edge_weight,
+ # {
+ # 'bound_lower': THRESHOLD_EDGE_WEIGHT,
+ # 'bound_upper': None,
+ # },
+ # )
pipe_graph_postprocessing.add(
- graphs.filter_graph_by_edge_weight,
+ graphs.filter_graph_by_number_edges,
{
- 'bound_lower': THRESHOLD_EDGE_WEIGHT,
- 'bound_upper': None,
+ 'limit': THRESHOLD_EDGE_NUMBER,
+ 'property': 'weight',
},
)
pipe_graph_postprocessing.add(
diff --git a/src/lang_main/render/cytoscape.py b/src/lang_main/render/cytoscape.py
index f6a83dd..1125b79 100644
--- a/src/lang_main/render/cytoscape.py
+++ b/src/lang_main/render/cytoscape.py
@@ -5,6 +5,7 @@ from typing import Literal, cast
import py4cytoscape as p4c
from networkx import DiGraph, Graph
+from py4cytoscape import network_selection as p4c_network_selection
from py4cytoscape.exceptions import CyError
from requests.exceptions import RequestException
@@ -14,6 +15,8 @@ from lang_main.constants import (
CYTO_ITER_NEIGHBOUR_DEPTH,
CYTO_LAYOUT_NAME,
CYTO_LAYOUT_PROPERTIES,
+ CYTO_MAX_EDGE_COUNT,
+ CYTO_MAX_NODE_COUNT,
CYTO_NETWORK_ZOOM_FACTOR,
CYTO_NUMBER_SUBGRAPHS,
CYTO_PATH_STYLESHEET,
@@ -23,7 +26,9 @@ from lang_main.constants import (
PROPERTY_NAME_DEGREE_WEIGHTED,
SAVE_PATH_FOLDER,
)
+from lang_main.errors import GraphRenderError
from lang_main.loggers import logger_rendering as logger
+from lang_main.render import cytoscape_monkeypatch as cs_monkeypatch
from lang_main.types import (
CytoExportFileTypes,
CytoExportPageSizes,
@@ -32,9 +37,17 @@ from lang_main.types import (
CytoNodeID,
)
+# monkeypatch non-stable py4cytoscape function
+p4c_network_selection.select_edges_connecting_selected_nodes = (
+ cs_monkeypatch.select_edges_connecting_selected_nodes
+)
+p4c.select_edges_connecting_selected_nodes = (
+ cs_monkeypatch.select_edges_connecting_selected_nodes
+)
+
# ** Cytoscape API related, using py4cytoscape
-def verify_connection():
+def verify_connection() -> None:
"""Cytoscape: checks if CyREST and Cytoscape versions are compatible nad
if Cytoscape API endpoint is reachable
@@ -55,6 +68,60 @@ def verify_connection():
raise error
+def verify_graph_render_size(
+ graph: Graph | DiGraph,
+ max_node_count: int | None = CYTO_MAX_NODE_COUNT,
+ max_edge_count: int | None = CYTO_MAX_EDGE_COUNT,
+) -> None:
+ """verify that the graph size can still be handled within an acceptable time
+ frame for rendering in Cytoscape
+
+ Parameters
+ ----------
+ graph : Graph | DiGraph
+ graph to verify
+ max_node_count : int | None, optional
+ maximum allowed number of nodes, by default CYTO_MAX_NODE_COUNT
+ max_edge_count : int | None, optional
+ maximum allowed number of edges, by default CYTO_MAX_EDGE_COUNT
+
+ Raises
+ ------
+ GraphRenderError
+ if any of the provided limits is exceeded
+ """
+ num_nodes = len(graph.nodes)
+ num_edges = len(graph.edges)
+ if max_node_count is not None and num_nodes > max_node_count:
+ raise GraphRenderError(
+ f'Maximum number of nodes for rendering exceeded. '
+ f'Limit {max_node_count}, Counted: {num_nodes}'
+ )
+
+ if max_edge_count is not None and num_edges > max_edge_count:
+ raise GraphRenderError(
+ f'Maximum number of edges for rendering exceeded. '
+ f'Limit {max_edge_count}, Counted: {num_edges}'
+ )
+
+
+def change_default_layout() -> None:
+ """Cytoscape: resets the default layout to `grid` to accelerate the import process
+ (grid layout one of the fastest)
+
+ Raises
+ ------
+ RequestException
+ API endpoint not reachable or CyREST operation not successful
+ """
+ body: dict[str, str] = {'value': 'grid', 'key': 'layout.default'}
+ try:
+ p4c.cyrest_put('properties/cytoscape3.props/layout.default', body=body)
+ except RequestException as error:
+ logger.error('[CytoAPIConnection] Property change of default layout not successful.')
+ raise error
+
+
def import_to_cytoscape(
graph: DiGraph | Graph,
network_name: str = CYTO_BASE_NETWORK_NAME,
@@ -70,6 +137,10 @@ def import_to_cytoscape(
"""
logger.debug('Checking Cytoscape connection...')
verify_connection()
+ logger.debug('Checking graph size for rendering...')
+ verify_graph_render_size(graph)
+ logger.debug('Setting default layout to improve import speed...')
+ change_default_layout()
logger.debug('Setting Cytoscape sandbox...')
p4c.sandbox_set(
sandbox_name=sandbox_name,
diff --git a/src/lang_main/render/cytoscape_monkeypatch.py b/src/lang_main/render/cytoscape_monkeypatch.py
new file mode 100644
index 0000000..84cb173
--- /dev/null
+++ b/src/lang_main/render/cytoscape_monkeypatch.py
@@ -0,0 +1,73 @@
+import re
+
+from py4cytoscape import networks
+from py4cytoscape.network_selection import get_selected_nodes, select_edges
+from py4cytoscape.py4cytoscape_logger import cy_log
+from py4cytoscape.py4cytoscape_utils import * # type: ignore # noqa: F403
+
+re_parenthesis_1 = re.compile(r'[(]+')
+re_parenthesis_2 = re.compile(r'[)]+')
+
+
+@cy_log
+def select_edges_connecting_selected_nodes(network=None, base_url=DEFAULT_BASE_URL): # noqa: F405
+ """Select edges in a Cytoscape Network connecting the selected nodes, including self loops connecting single nodes.
+
+ Any edges selected beforehand are deselected before any new edges are selected
+
+ Args:
+ network (SUID or str or None): Name or SUID of a network. Default is the
+ "current" network active in Cytoscape.
+ base_url (str): Ignore unless you need to specify a custom domain,
+ port or version to connect to the CyREST API. Default is http://127.0.0.1:1234
+ and the latest version of the CyREST API supported by this version of py4cytoscape.
+
+ Returns:
+ dict: {'nodes': [node list], 'edges': [edge list]} or None if no selected nodes
+ Raises:
+ CyError: if network name or SUID doesn't exist
+ requests.exceptions.RequestException: if can't connect to Cytoscape or Cytoscape returns an error
+
+ Examples:
+ >>> select_edges_connecting_selected_nodes()
+ None
+ >>> select_edges_connecting_selected_nodes(network='My Network')
+ {'nodes': [103990, 103991, ...], 'edges': [104432, 104431, ...]}
+ >>> select_edges_connecting_selected_nodes(network=52)
+ {'nodes': [103990, 103991, ...], 'edges': [104432, 104431, ...]}
+
+ Note:
+ In the return value node list is list of all selected nodes, and
+ edge list is the SUIDs of selected edges -- dict is None if no nodes were selected or there were no newly
+ created edges
+ """
+ net_suid = networks.get_network_suid(network, base_url=base_url)
+
+ selected_nodes = get_selected_nodes(network=net_suid, base_url=base_url)
+ # TODO: In R version, NA test is after len() test ... shouldn't it be before?
+ if not selected_nodes:
+ return None
+
+ all_edges = networks.get_all_edges(net_suid, base_url=base_url)
+
+ selected_sources = set()
+ selected_targets = set()
+ for n in selected_nodes:
+ n = re_parenthesis_1.sub('\(', n) # type: ignore
+ n = re_parenthesis_2.sub('\)', n) # type: ignore
+ selected_sources |= set(filter(re.compile('^' + n).search, all_edges)) # type: ignore
+ selected_targets |= set(filter(re.compile(n + '$').search, all_edges)) # type: ignore
+
+ selected_edges = list(selected_sources.intersection(selected_targets))
+
+ if len(selected_edges) == 0:
+ return None
+ res = select_edges(
+ selected_edges,
+ by_col='name',
+ preserve_current_selection=False,
+ network=net_suid,
+ base_url=base_url,
+ )
+ return res
+ # TODO: isn't the pattern match a bit cheesy ... shouldn't it be ^+n+' (' and ') '+n+$ ???