Skip to content

Commit

Permalink
Merge pull request #29 from barahona-research-group/constructor_class
Browse files Browse the repository at this point in the history
use class in constructors
  • Loading branch information
arnaudon authored Feb 11, 2021
2 parents 3573045 + 1889ec6 commit d4fec14
Show file tree
Hide file tree
Showing 12 changed files with 289 additions and 156 deletions.
7 changes: 3 additions & 4 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ name: Publish sdist and wheels macos-manylinux

on:
release:
push:
types: [created]

env:
Expand All @@ -12,8 +11,8 @@ env:
# Only build on Python 3.x
CIBW_BUILD: 'cp3?-*'
CIBW_SKIP: 'cp35-* cp39-* *-manylinux_i686'
CIBW_BEFORE_TEST: pip install nose mock h5py numpy
CIBW_TEST_COMMAND: nosetests -s -v -P {project}/tests
CIBW_BEFORE_TEST: pip install pybind11
CIBW_TEST_COMMAND: pytest {package}/tests

jobs:
build_wheels:
Expand Down Expand Up @@ -93,6 +92,6 @@ jobs:
- name: Publish package to PyPI
uses: pypa/gh-action-pypi-publish@master
with:
user: __token__
user: ${{ secrets.PYPI_USERNAME }}
password: ${{ secrets.PYPI_PASSWORD }}
packages_dir: dist/
2 changes: 1 addition & 1 deletion .github/workflows/run-tox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.6, 3.7, 3.8]
python-version: [3.7, 3.8]

steps:
- uses: actions/checkout@v2
Expand Down
10 changes: 10 additions & 0 deletions examples/create_graph.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""create graph for simple example"""
import pandas as pd
import matplotlib.pyplot as plt
import pickle
import networkx as nx
Expand Down Expand Up @@ -30,11 +31,20 @@ def create_sbm():
plt.title("Ground truth communities")
plt.savefig("ground_truth.png", bbox_inches="tight")

# save adjacency with pickle
with open("sbm_graph.pkl", "wb") as pickle_file:
pickle.dump(nx.adjacency_matrix(graph, weight="weight"), pickle_file)

# save .gpickle for community plotting
nx.write_gpickle(graph, "sbm_graph.gpickle")

# save with text file as alternative format
edges = pd.DataFrame()
edges["i"] = [e[0] for e in graph.edges] + [e[1] for e in graph.edges]
edges["j"] = [e[1] for e in graph.edges] + [e[0] for e in graph.edges]
edges["weight"] = 2 * [graph.edges[e]["weight"] for e in graph.edges]
edges.to_csv("edges.csv", index=False)


if __name__ == "__main__":
create_sbm()
18 changes: 17 additions & 1 deletion examples/run_simple_example.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
#!/bin/bash

python create_graph.py
pygenstability run sbm_graph.pkl

pygenstability run --help
pygenstability run \
--constructor continuous_normalized \
--min-time -2 \
--max-time 0\
--n-time 50 \
--n-louvain 100 \
--n-workers 40 \
edges.csv
# sbm_graph.pkl

pygenstability plot_scan --help
pygenstability plot_scan results.pkl

pygenstability plot_communities --help
pygenstability plot_communities sbm_graph.gpickle results.pkl
3 changes: 2 additions & 1 deletion pygenstability/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""Import main functions."""
from pygenstability.io import load_results, save_results
from pygenstability.io import load_results
from pygenstability.io import save_results
from pygenstability.pygenstability import run
84 changes: 58 additions & 26 deletions pygenstability/app.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
"""Command line interface."""
import pickle
from pathlib import Path

import click
import numpy as np
import pandas as pd
from scipy import sparse as sp

from .io import load_results

# pylint: disable=import-outside-toplevel
from pygenstability import load_results
from pygenstability import run as _run
from pygenstability.plotting import plot_communities as _plot_communities
from pygenstability.plotting import plot_scan as _plot_scan


@click.group()
Expand All @@ -19,68 +24,74 @@ def cli():
"--constructor",
default="linearized",
show_default=True,
help="name of the quality constructor",
help="Name of the quality constructor.",
)
@click.option(
"--min-time",
default=-2.0,
show_default=True,
help="minimum Markov time",
help="Minimum Markov time.",
)
@click.option(
"--max-time",
default=0.5,
show_default=True,
help="maximum Markov time",
help="Maximum Markov time.",
)
@click.option("--n-time", default=20, show_default=True, help="number of time steps")
@click.option("--n-time", default=20, show_default=True, help="Number of time steps.")
@click.option(
"--log-time",
default=True,
show_default=True,
help="use linear or log scales for times",
help="Use linear or log scales for times.",
)
@click.option(
"--n-louvain",
default=100,
show_default=True,
help="number of Louvain evaluations",
help="Number of Louvain evaluations.",
)
@click.option(
"--VI/--no-VI",
default=True,
show_default=True,
help="compute the variation of information between Louvain runs",
help="Compute the variation of information between Louvain runs.",
)
@click.option(
"--n-louvain-VI",
default=20,
show_default=True,
help="number of randomly chosen Louvain run to estimate the VI",
help="Number of randomly chosen Louvain run to estimate the VI.",
)
@click.option(
"--postprocessing/--no-postprocessing",
default=True,
show_default=True,
help="apply the final postprocessing step",
help="Apply the final postprocessing step.",
)
@click.option(
"--ttprime/--no-ttprime",
default=True,
show_default=True,
help="compute the ttprime matrix",
help="Compute the ttprime matrix.",
)
@click.option(
"--spectral-gap/--no-spectral-gap",
default=True,
show_default=True,
help="Normalize time by spectral gap.",
)
@click.option(
"--result-file",
default="results.pkl",
show_default=True,
help="path to the result file",
help="Path to the result file.",
)
@click.option(
"--n-workers",
default=4,
show_default=True,
help="number of workers for multiprocessing",
help="Number of workers for multiprocessing.",
)
@click.option("--tqdm-disable", default=False, show_default=True, help="disable progress bars")
def run(
Expand All @@ -95,16 +106,37 @@ def run(
n_louvain_vi,
postprocessing,
ttprime,
spectral_gap,
result_file,
n_workers,
tqdm_disable,
):
"""Run pygenstability."""
from .pygenstability import run
"""Run pygenstability.
with open(graph_file, "rb") as pickle_file:
graph = pickle.load(pickle_file)
run(
graph_file: path to either a .pkl with adjacency matrix in sparse format,
or a text file with three columns encoding node indices and edge weight.
The columns need a header, or the first line will be dropped.
Notice that doubled edges with opposite orientations are needed for symetric graph.
See https://barahona-research-group.github.io/PyGenStability/ for more information.
"""
try:
# load pickle file
if Path(graph_file).suffix == ".pkl":
with open(graph_file, "rb") as pickle_file:
graph = pickle.load(pickle_file)
else:
# load text file with edge list
edges = pd.read_csv(graph_file)
n_nodes = len(np.unique(edges[edges.columns[:2]].to_numpy().flatten()))
graph = sp.csr_matrix(
(edges[edges.columns[2]], tuple(edges[edges.columns[:2]].to_numpy().T)),
shape=(n_nodes, n_nodes),
)
except Exception as exc:
raise Exception("Could not load the graph file.") from exc

_run(
graph,
constructor=constructor,
min_time=min_time,
Expand All @@ -116,6 +148,7 @@ def run(
n_louvain_VI=n_louvain_vi,
with_postprocessing=postprocessing,
with_ttprime=ttprime,
with_spectral_gap=spectral_gap,
result_file=result_file,
n_workers=n_workers,
tqdm_disable=tqdm_disable,
Expand All @@ -126,18 +159,17 @@ def run(
@click.argument("results_file", type=click.Path(exists=True))
def plot_scan(results_file):
"""Plot results in scan plot."""
from .plotting import plot_scan

plot_scan(load_results(results_file))
_plot_scan(load_results(results_file))


@cli.command("plot_communities")
@click.argument("graph_file", type=click.Path(exists=True))
@click.argument("results_file", type=click.Path(exists=True))
def plot_communities(results_file, graph_file):
"""Plot communities on networkx graph."""
from .plotting import plot_communities
"""Plot communities on networkx graph.
Argument graph_file has to be a .gpickle compatible with network.
"""
with open(graph_file, "rb") as pickle_file:
graph = pickle.load(pickle_file)
plot_communities(graph, load_results(results_file))
_plot_communities(graph, load_results(results_file))
Loading

0 comments on commit d4fec14

Please sign in to comment.