From 88ada1516db651006b864696ea62c2c93aeda9a2 Mon Sep 17 00:00:00 2001 From: Matthieu Totet Date: Wed, 27 Aug 2025 18:47:12 +0200 Subject: [PATCH 1/4] Layout class that aim to ease layout usage --- gephipy/gephipy.py | 87 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/gephipy/gephipy.py b/gephipy/gephipy.py index eaa10aa..c146d33 100644 --- a/gephipy/gephipy.py +++ b/gephipy/gephipy.py @@ -2,9 +2,14 @@ import jpype.imports import networkx as nx +import inspect +from tqdm import tqdm +from functools import lru_cache # Starting the JVM from gephipy import jvm -jvm.start() + +if not jpype.isJVMStarted(): + jvm.start() # Java import from java.io import File @@ -14,6 +19,8 @@ from org.gephi.io.processor.plugin import DefaultProcessor from org.gephi.io.exporter.api import ExportController from org.gephi.io.importer.api import ImportController, EdgeDirectionDefault +from org.gephi.layout.spi import LayoutBuilder +from typing import Union # # Create a new Gephi workspace @@ -122,4 +129,80 @@ def export_png(workspace, file_path="./graph.png"): export = Lookup.getDefault().lookup(ExportController) png = export.getExporter("png") png.setWorkspace(workspace) - export.exportFile(File(file_path), png) \ No newline at end of file + export.exportFile(File(file_path), png) + +@lru_cache(1) +def get_available_layouts(): + """ + Dictonary of available Layout + """ + return {str(layout.getName()):layout for layout in Lookup.getDefault().lookupAll(LayoutBuilder)} + +# Context Class to ease Layout usage +class Layout: + class _LayoutInstance(): + """ + Internal Layout Class that offers run() or pass the method call to the underlying + class instance + """ + def __init__(self,instance,log_progress:bool): + self.instance = instance + self.log_progress = log_progress + + + @lru_cache(1) + def _inspect(self): + """ + Inspect utils tool to fetch existing method for the class + """ + return dict(inspect.getmembers(self.instance)) + + def run(self, step=1): + """ + Perform a run of the layout within given steps. + It's a pure wrapper function to ease usage of Layout. + """ + + loop = range(step) + + if self.log_progress: # Could be useful, especially for jupyter folks to keep track of the algo status + loop = tqdm(loop,desc=f"Running {self.instance}") + for _ in loop: + if self.instance.canAlgo(): + self.instance.goAlgo() + else: + break + + def __getattr__(self, name: str): + """ + If other attributes or method are call, passing the invokation to underlying instance + """ + return self._inspect()[name] + + def __init__(self,layout:Union[jpype.JClass, str], graphModel, log_progress=False): + """ + When creating the object + """ + if isinstance(layout,str): + available_layouts = get_available_layouts() + _layout = available_layouts.get(layout) + if _layout is None: + raise Exception(f"Invalid Layout name {layout}, available layout are : {', '.join(available_layouts.keys())} ") + else: + _layout = layout + self.layout_instance = Layout._LayoutInstance(_layout.buildLayout(), log_progress) + self.layout_instance.setGraphModel(graphModel) + + def __enter__(self): + """ + Entering the context (with ... as ...) + """ + self.layout_instance.resetPropertiesValues() + self.layout_instance.initAlgo() + return self.layout_instance + + def __exit__(self,tp,e,traceback): + """ + Exiting context + """ + self.layout_instance.endAlgo() From 00891a7a316f3d9587ff61a5525f04193f7a4055 Mon Sep 17 00:00:00 2001 From: totetmatt Date: Wed, 27 Aug 2025 21:13:39 +0200 Subject: [PATCH 2/4] Add tqdm and test --- poetry.lock | 28 +++++++++++++++++++++++++--- pyproject.toml | 1 + test/test_scenario.py | 14 +++----------- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/poetry.lock b/poetry.lock index 5da2faf..e93dca9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -6,12 +6,12 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["test"] -markers = "sys_platform == \"win32\"" +groups = ["main", "test"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +markers = {main = "platform_system == \"Windows\"", test = "sys_platform == \"win32\""} [[package]] name = "iniconfig" @@ -156,7 +156,29 @@ pygments = ">=2.7.2" [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] +[[package]] +name = "tqdm" +version = "4.67.1" +description = "Fast, Extensible Progress Meter" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, + {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"] +discord = ["requests"] +notebook = ["ipywidgets (>=6)"] +slack = ["slack-sdk"] +telegram = ["requests"] + [metadata] lock-version = "2.1" python-versions = "^3.11" -content-hash = "c057812194b30e3849d1d0e28b5921df5e5600c21a5bda395b1470e102a47abe" +content-hash = "fde888d88ae855145229fa09796bd6a666eb0d865e98907280d8bfb4e2b515a3" diff --git a/pyproject.toml b/pyproject.toml index 9e900be..b6c508e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,6 +10,7 @@ license="MIT" python = "^3.11" JPype1 = "^1.6.0" networkx = "^3.5" +tqdm = "^4.67.1" [tool.poetry.group.test.dependencies] pytest = "^8.2.0" diff --git a/test/test_scenario.py b/test/test_scenario.py index 91ad6ea..187bf89 100644 --- a/test/test_scenario.py +++ b/test/test_scenario.py @@ -77,17 +77,9 @@ def test_scenario(): random.goAlgo() random.endAlgo() - # FA2 layout - fa2 = ForceAtlas2Builder().buildLayout() - fa2.setGraphModel(graphModel) - fa2.resetPropertiesValues() - fa2.initAlgo() - for x in range(1000): - if fa2.canAlgo(): - fa2.goAlgo() - else: - break - fa2.endAlgo() + + with gephipy.Layout("Force Atlas 2",graphModel=graphModel,log_progress=True) as layout: + layout.run(1000) # Noverlap layout noverlap = NoverlapLayoutBuilder().buildLayout() From 405f208ab97b5ccf3025c9ae22058c4f453beb34 Mon Sep 17 00:00:00 2001 From: totetmatt Date: Wed, 27 Aug 2025 21:44:39 +0200 Subject: [PATCH 3/4] String name change if not on windows --- test/test_scenario.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_scenario.py b/test/test_scenario.py index 187bf89..5cdf0e8 100644 --- a/test/test_scenario.py +++ b/test/test_scenario.py @@ -78,7 +78,7 @@ def test_scenario(): random.endAlgo() - with gephipy.Layout("Force Atlas 2",graphModel=graphModel,log_progress=True) as layout: + with gephipy.Layout("ForceAtlas 2",graphModel=graphModel,log_progress=True) as layout: layout.run(1000) # Noverlap layout From 1e361183a463254a151d8b5ac06ca1465d33bcaa Mon Sep 17 00:00:00 2001 From: totetmatt Date: Wed, 27 Aug 2025 22:02:23 +0200 Subject: [PATCH 4/4] Update jupyter example. Bug found : layout getName is localized --- gephipy-example.ipynb | 9599 ++--------------------------------------- gephipy/gephipy.py | 2 +- 2 files changed, 282 insertions(+), 9319 deletions(-) diff --git a/gephipy-example.ipynb b/gephipy-example.ipynb index ad85f73..2e65ba7 100644 --- a/gephipy-example.ipynb +++ b/gephipy-example.ipynb @@ -1,9335 +1,298 @@ { - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { "colab": { - "provenance": [] + "base_uri": "https://localhost:8080/" }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } + "id": "qgDKsAt_vlnz", + "outputId": "906f6f20-3952-4fa3-a394-0ee72deec789" + }, + "outputs": [], + "source": [ + "!pip install gephipy" + ] }, - "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "V757ca6jvwpS" + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 34, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "qgDKsAt_vlnz", - "outputId": "906f6f20-3952-4fa3-a394-0ee72deec789" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Requirement already satisfied: gephipy in /usr/local/lib/python3.12/dist-packages (0.0.2)\n", - "Requirement already satisfied: JPype1<2.0.0,>=1.6.0 in /usr/local/lib/python3.12/dist-packages (from gephipy) (1.6.0)\n", - "Requirement already satisfied: networkx<4.0,>=3.5 in /usr/local/lib/python3.12/dist-packages (from gephipy) (3.5)\n", - "Requirement already satisfied: packaging in /usr/local/lib/python3.12/dist-packages (from JPype1<2.0.0,>=1.6.0->gephipy) (25.0)\n" - ] - } - ], - "source": [ - "!pip install gephipy" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "None\n", + "start JVM\n" + ] + } + ], + "source": [ + "#\n", + "# Create a Gephy workspace\n", + "#\n", + "from gephipy import gephipy\n", + "\n", + "workspace = gephipy.create_workspace()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "lktn7GSPvwY5", + "outputId": "99ad112d-9c56-40ed-99d7-43bc0bef3f12" + }, + "outputs": [ { - "cell_type": "code", - "source": [ - "#\n", - "# Create a Gephy workspace\n", - "#\n", - "from gephipy import gephipy\n", - "\n", - "workspace = gephipy.create_workspace()\n" - ], - "metadata": { - "id": "V757ca6jvwpS" - }, - "execution_count": 35, - "outputs": [] + "name": "stdout", + "output_type": "stream", + "text": [ + "Import done!\n" + ] + } + ], + "source": [ + "#\n", + "# Load a graph in Gephy\n", + "#\n", + "from gephipy import gephipy\n", + "import networkx as nx\n", + "\n", + "# Create a random graph with NetworkX\n", + "graphX = nx.erdos_renyi_graph(500,0.01)\n", + "\n", + "# Load it in Gephi\n", + "gephipy.networkx_to_gephi(workspace, graphX)\n", + "\n", + "print(\"Import done!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "Uezb67nZebA5", + "outputId": "19f8945d-5de5-4a41-beed-a7fc3955b1e5" + }, + "outputs": [ { - "cell_type": "code", - "source": [ - "#\n", - "# Load a graph in Gephy\n", - "#\n", - "from gephipy import gephipy\n", - "import networkx as nx\n", - "\n", - "# Create a random graph with NetworkX\n", - "graphX = nx.erdos_renyi_graph(500,0.01)\n", - "\n", - "# Load it in Gephi\n", - "gephipy.networkx_to_gephi(workspace, graphX)\n", - "\n", - "print(\"Import done!\")" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "lktn7GSPvwY5", - "outputId": "99ad112d-9c56-40ed-99d7-43bc0bef3f12" - }, - "execution_count": 36, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Import done!\n" - ] - } - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Metrics done!\n" + ] + } + ], + "source": [ + "#\n", + "# Compute some metrics\n", + "#\n", + "from gephipy import gephipy\n", + "from org.gephi.statistics.plugin import GraphDistance, Modularity\n", + "\n", + "# Get the Gephi graph model from the current workspace\n", + "graphModel = gephipy.get_graph_model(workspace)\n", + "\n", + "# Louvain\n", + "modularity = Modularity()\n", + "modularity.execute(graphModel)\n", + "\n", + "# Betweeness centrality\n", + "centrality = GraphDistance()\n", + "centrality.setDirected(True)\n", + "centrality.execute(graphModel)\n", + "\n", + "print(\"Metrics done!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, - { - "cell_type": "code", - "source": [ - "#\n", - "# Compute some metrics\n", - "#\n", - "from gephipy import gephipy\n", - "from org.gephi.statistics.plugin import GraphDistance, Modularity\n", - "\n", - "# Get the Gephi graph model from the current workspace\n", - "graphModel = gephipy.get_graph_model(workspace)\n", - "\n", - "# Louvain\n", - "modularity = Modularity()\n", - "modularity.execute(graphModel)\n", - "\n", - "# Betweeness centrality\n", - "centrality = GraphDistance()\n", - "centrality.setDirected(True)\n", - "centrality.execute(graphModel)\n", - "\n", - "print(\"Metrics done!\")" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "Uezb67nZebA5", - "outputId": "19f8945d-5de5-4a41-beed-a7fc3955b1e5" - }, - "execution_count": 37, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Metrics done!\n" - ] - } - ] + "id": "zdz9VNa8fP8-", + "outputId": "46972cb2-630c-45ab-ef09-70cc50f1d809" + }, + "outputs": [], + "source": [ + "#\n", + "# Apply appearance\n", + "#\n", + "from gephipy import gephipy\n", + "\n", + "from org.openide.util import Lookup\n", + "from org.gephi.appearance.api import AppearanceController\n", + "from org.gephi.appearance.plugin import RankingNodeSizeTransformer, PartitionElementColorTransformer\n", + "from org.gephi.appearance.plugin.palette import PaletteManager\n", + "\n", + "appearanceController = Lookup.getDefault().lookup(AppearanceController)\n", + "appearanceModel = appearanceController.getModel()\n", + "\n", + "# Size Make node size based on centrality\n", + "centralityColumn = graphModel.getNodeTable().getColumn(GraphDistance.BETWEENNESS)\n", + "centralityRanking = appearanceModel.getNodeFunction(centralityColumn, RankingNodeSizeTransformer)\n", + "centralityTransformer = centralityRanking.getTransformer()\n", + "centralityTransformer.setMinSize(10)\n", + "centralityTransformer.setMaxSize(100)\n", + "appearanceController.transform(centralityRanking)\n", + "\n", + "# Color by community\n", + "communityColumn = graphModel.getNodeTable().getColumn(Modularity.MODULARITY_CLASS)\n", + "colorPartition = appearanceModel.getNodeFunction(communityColumn, PartitionElementColorTransformer)\n", + "partition = colorPartition.getPartition()\n", + "palette = PaletteManager.getInstance().generatePalette(partition.size(graphModel.getGraph()))\n", + "partition.setColors(graphModel.getGraph(), palette.getColors())\n", + "appearanceController.transform(colorPartition)\n", + "\n", + "print(\"Appearance done!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "IOeaVb8kfbgn", + "outputId": "d4e7e13c-7ff7-4442-ea2c-4d2aa3bed7d0" + }, + "outputs": [ { - "cell_type": "code", - "source": [ - "#\n", - "# Apply appearance\n", - "#\n", - "from gephipy import gephipy\n", - "\n", - "from org.openide.util import Lookup\n", - "from org.gephi.appearance.api import AppearanceController\n", - "from org.gephi.appearance.plugin import RankingNodeSizeTransformer, PartitionElementColorTransformer\n", - "from org.gephi.appearance.plugin.palette import PaletteManager\n", - "\n", - "appearanceController = Lookup.getDefault().lookup(AppearanceController)\n", - "appearanceModel = appearanceController.getModel()\n", - "\n", - "# Size Make node size based on centrality\n", - "centralityColumn = graphModel.getNodeTable().getColumn(GraphDistance.BETWEENNESS)\n", - "centralityRanking = appearanceModel.getNodeFunction(centralityColumn, RankingNodeSizeTransformer)\n", - "centralityTransformer = centralityRanking.getTransformer()\n", - "centralityTransformer.setMinSize(10)\n", - "centralityTransformer.setMaxSize(100)\n", - "appearanceController.transform(centralityRanking)\n", - "\n", - "# Color by community\n", - "communityColumn = graphModel.getNodeTable().getColumn(Modularity.MODULARITY_CLASS)\n", - "colorPartition = appearanceModel.getNodeFunction(communityColumn, PartitionElementColorTransformer)\n", - "partition = colorPartition.getPartition()\n", - "palette = PaletteManager.getInstance().generatePalette(partition.size(graphModel.getGraph()))\n", - "partition.setColors(graphModel.getGraph(), palette.getColors())\n", - "appearanceController.transform(colorPartition)\n", - "\n", - "print(\"Appearance done!\")" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "zdz9VNa8fP8-", - "outputId": "46972cb2-630c-45ab-ef09-70cc50f1d809" - }, - "execution_count": 38, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Appearance done!\n" - ] - } - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "Running org.gephi.layout.plugin.forceAtlas2.ForceAtlas2@4d9ac0b4: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1000/1000 [00:00<00:00, 1724.12it/s]" + ] }, { - "cell_type": "code", - "source": [ - "#\n", - "# Run Layouts\n", - "#\n", - "from gephipy import gephipy\n", - "\n", - "from org.gephi.layout.plugin.forceAtlas2 import ForceAtlas2Builder\n", - "from org.gephi.layout.plugin.random import Random\n", - "from org.gephi.layout.plugin.noverlap import NoverlapLayoutBuilder\n", - "\n", - "# Random layout\n", - "random = Random().buildLayout()\n", - "random.setGraphModel(gephipy.get_graph_model(workspace))\n", - "random.initAlgo()\n", - "random.goAlgo()\n", - "random.endAlgo()\n", - "\n", - "# FA2 layout\n", - "fa2 = ForceAtlas2Builder().buildLayout()\n", - "fa2.setGraphModel(gephipy.get_graph_model(workspace))\n", - "fa2.resetPropertiesValues()\n", - "fa2.initAlgo()\n", - "for x in range(1000):\n", - " fa2.goAlgo()\n", - "fa2.endAlgo()\n", - "\n", - "# Noverlap layout\n", - "noverlap = NoverlapLayoutBuilder().buildLayout()\n", - "noverlap.setGraphModel(gephipy.get_graph_model(workspace))\n", - "noverlap.initAlgo()\n", - "noverlap.endAlgo()\n", - "\n", - "print(\"Layouts done!\")" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "IOeaVb8kfbgn", - "outputId": "d4e7e13c-7ff7-4442-ea2c-4d2aa3bed7d0" - }, - "execution_count": 39, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Layout done!\n" - ] - } - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Layouts done!\n" + ] }, { - "cell_type": "code", - "source": [ - "#\n", - "# Export your graph / visualize your graph\n", - "#\n", - "from gephipy import gephipy\n", - "from IPython.display import display,HTML\n", - "\n", - "# Transform it to graphX\n", - "graphx = gephipy.gephi_to_networkx(workspace)\n", - "\n", - "# Export your graph\n", - "gephipy.export_gexf(workspace, \"my-gephi-graph.gexf\")\n", - "gephipy.export_pdf(workspace, \"my-gephi-graph.pdf\")\n", - "\n", - "gephipy.export_svg(workspace, \"my-gephi-graph.svg\")\n", - "with open(\"./my-gephi-graph.svg\", 'r') as file_svg:\n", - " svg = file_svg.read()\n", - " html_code = f\"\"\"\n", - " \n", - "
\n", - " {svg}\n", - "
\n", - " \n", - " \"\"\"\n", - "\n", - " display(HTML(html_code))\n", - "\n", - "print(\"Exports done!\")" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 538 - }, - "id": "5cT5R-w7fiYD", - "outputId": "4326ec82-b9f1-4c6e-f3dd-31a833dac952" - }, - "execution_count": 46, - "outputs": [ - { - "output_type": "display_data", - "data": { - "text/plain": [ - "" - ], - "text/html": [ - "\n", - " \n", - "
\n", - " \n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n", - "
\n", - " \n", - " " - ] - }, - "metadata": {} - }, - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Exports done!\n" - ] - } - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "\n" + ] } - ] -} \ No newline at end of file + ], + "source": [ + "#\n", + "# Run Layouts\n", + "#\n", + "from gephipy import gephipy\n", + "\n", + "from org.gephi.layout.plugin.forceAtlas2 import ForceAtlas2Builder\n", + "from org.gephi.layout.plugin.random import Random\n", + "from org.gephi.layout.plugin.noverlap import NoverlapLayoutBuilder\n", + "\n", + "# Random layout\n", + "with gephipy.Layout(\"Random\",gephipy.get_graph_model(workspace),False) as layout:\n", + " layout.run(1)\n", + "\n", + "# Force Atlas 2\n", + "with gephipy.Layout(\"ForceAtlas 2\",gephipy.get_graph_model(workspace),True) as layout:\n", + " layout.run(1000)\n", + "\n", + "\n", + "# Noverlap layout\n", + "with gephipy.Layout(\"Noverlap\",gephipy.get_graph_model(workspace),False) as layout:\n", + " pass\n", + "\n", + "\n", + "print(\"Layouts done!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 538 + }, + "id": "5cT5R-w7fiYD", + "outputId": "4326ec82-b9f1-4c6e-f3dd-31a833dac952" + }, + "outputs": [], + "source": [ + "#\n", + "# Export your graph / visualize your graph\n", + "#\n", + "from gephipy import gephipy\n", + "from IPython.display import display,HTML\n", + "\n", + "# Transform it to graphX\n", + "graphx = gephipy.gephi_to_networkx(workspace)\n", + "\n", + "# Export your graph\n", + "gephipy.export_gexf(workspace, \"my-gephi-graph.gexf\")\n", + "gephipy.export_pdf(workspace, \"my-gephi-graph.pdf\")\n", + "\n", + "gephipy.export_svg(workspace, \"my-gephi-graph.svg\")\n", + "with open(\"./my-gephi-graph.svg\", 'r') as file_svg:\n", + " svg = file_svg.read()\n", + " html_code = f\"\"\"\n", + " \n", + "
\n", + " {svg}\n", + "
\n", + " \n", + " \"\"\"\n", + "\n", + " display(HTML(html_code))\n", + "\n", + "print(\"Exports done!\")" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.2" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/gephipy/gephipy.py b/gephipy/gephipy.py index c146d33..1f9331e 100644 --- a/gephipy/gephipy.py +++ b/gephipy/gephipy.py @@ -136,7 +136,7 @@ def get_available_layouts(): """ Dictonary of available Layout """ - return {str(layout.getName()):layout for layout in Lookup.getDefault().lookupAll(LayoutBuilder)} + return {str(layout.getName()).strip():layout for layout in Lookup.getDefault().lookupAll(LayoutBuilder)} # Context Class to ease Layout usage class Layout: