risk-network 0.0.12b0__py3-none-any.whl → 0.0.12b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- risk/__init__.py +1 -1
- risk/annotations/__init__.py +10 -0
- risk/annotations/annotations.py +354 -0
- risk/annotations/io.py +241 -0
- risk/annotations/nltk_setup.py +86 -0
- risk/log/__init__.py +11 -0
- risk/log/console.py +141 -0
- risk/log/parameters.py +171 -0
- risk/neighborhoods/__init__.py +7 -0
- risk/neighborhoods/api.py +442 -0
- risk/neighborhoods/community.py +441 -0
- risk/neighborhoods/domains.py +360 -0
- risk/neighborhoods/neighborhoods.py +514 -0
- risk/neighborhoods/stats/__init__.py +13 -0
- risk/neighborhoods/stats/permutation/__init__.py +6 -0
- risk/neighborhoods/stats/permutation/permutation.py +240 -0
- risk/neighborhoods/stats/permutation/test_functions.py +70 -0
- risk/neighborhoods/stats/tests.py +275 -0
- risk/network/__init__.py +4 -0
- risk/network/graph/__init__.py +4 -0
- risk/network/graph/api.py +200 -0
- risk/network/graph/graph.py +268 -0
- risk/network/graph/stats.py +166 -0
- risk/network/graph/summary.py +253 -0
- risk/network/io.py +693 -0
- risk/network/plotter/__init__.py +4 -0
- risk/network/plotter/api.py +54 -0
- risk/network/plotter/canvas.py +291 -0
- risk/network/plotter/contour.py +329 -0
- risk/network/plotter/labels.py +935 -0
- risk/network/plotter/network.py +294 -0
- risk/network/plotter/plotter.py +141 -0
- risk/network/plotter/utils/colors.py +419 -0
- risk/network/plotter/utils/layout.py +94 -0
- risk_network-0.0.12b1.dist-info/METADATA +122 -0
- risk_network-0.0.12b1.dist-info/RECORD +40 -0
- {risk_network-0.0.12b0.dist-info → risk_network-0.0.12b1.dist-info}/WHEEL +1 -1
- risk_network-0.0.12b0.dist-info/METADATA +0 -796
- risk_network-0.0.12b0.dist-info/RECORD +0 -7
- {risk_network-0.0.12b0.dist-info → risk_network-0.0.12b1.dist-info}/licenses/LICENSE +0 -0
- {risk_network-0.0.12b0.dist-info → risk_network-0.0.12b1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
"""
|
2
|
+
risk/annotations/nltk_setup
|
3
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
4
|
+
"""
|
5
|
+
|
6
|
+
import os
|
7
|
+
import zipfile
|
8
|
+
from typing import List, Tuple
|
9
|
+
|
10
|
+
import nltk
|
11
|
+
from nltk.data import find
|
12
|
+
from nltk.data import path as nltk_data_path
|
13
|
+
|
14
|
+
from risk.log import logger
|
15
|
+
|
16
|
+
|
17
|
+
def setup_nltk_resources(required_resources: List[Tuple[str, str]] = None) -> None:
|
18
|
+
"""Ensures all required NLTK resources are available and properly extracted.
|
19
|
+
Uses NLTK's default paths and mechanisms.
|
20
|
+
|
21
|
+
Args:
|
22
|
+
required_resources (List[Tuple[str, str]], optional): List of required resources
|
23
|
+
to download and extract. Each tuple should contain the resource path within
|
24
|
+
NLTK data and the package name. Defaults to None.
|
25
|
+
"""
|
26
|
+
if required_resources is None:
|
27
|
+
required_resources = [
|
28
|
+
("tokenizers/punkt", "punkt"),
|
29
|
+
("tokenizers/punkt_tab", "punkt_tab"),
|
30
|
+
("corpora/stopwords", "stopwords"),
|
31
|
+
("corpora/wordnet", "wordnet"),
|
32
|
+
]
|
33
|
+
|
34
|
+
# Process each resource
|
35
|
+
for resource_path, package_name in required_resources:
|
36
|
+
try:
|
37
|
+
# First try to find the resource - this is how NLTK checks if it's available
|
38
|
+
find(resource_path)
|
39
|
+
except LookupError:
|
40
|
+
# Resource not found, download it
|
41
|
+
logger.info(f"Downloading missing NLTK resource: {package_name}")
|
42
|
+
nltk.download(package_name, quiet=True)
|
43
|
+
|
44
|
+
# Even if find() succeeded, the resource might be a zip that failed to extract
|
45
|
+
# Check if we need to manually extract zips
|
46
|
+
verify_and_extract_if_needed(resource_path, package_name)
|
47
|
+
|
48
|
+
|
49
|
+
def verify_and_extract_if_needed(resource_path: str, package_name: str) -> None:
|
50
|
+
"""Verifies if the resource is properly extracted and extracts if needed. Respects
|
51
|
+
NLTK's directory structure where the extracted content should be in the same directory
|
52
|
+
as the zip file.
|
53
|
+
|
54
|
+
Args:
|
55
|
+
resource_path (str): Path to the resource within NLTK data.
|
56
|
+
package_name (str): Name of the NLTK package.
|
57
|
+
"""
|
58
|
+
# Get the directory and base name from the resource path
|
59
|
+
path_parts = resource_path.split("/")
|
60
|
+
resource_type = path_parts[0] # 'corpora', 'tokenizers', etc.
|
61
|
+
resource_name = path_parts[-1] # 'wordnet', 'punkt', etc.
|
62
|
+
|
63
|
+
# Check all NLTK data directories
|
64
|
+
for base in nltk_data_path:
|
65
|
+
# For resource paths like 'corpora/wordnet', the zip file is at '~/nltk_data/corpora/wordnet.zip'
|
66
|
+
# and the extracted directory should be at '~/nltk_data/corpora/wordnet'
|
67
|
+
resource_dir = os.path.join(base, resource_type)
|
68
|
+
zip_path = os.path.join(resource_dir, f"{resource_name}.zip")
|
69
|
+
folder_path = os.path.join(resource_dir, resource_name)
|
70
|
+
|
71
|
+
# If zip exists but folder doesn't, extraction is needed
|
72
|
+
if os.path.exists(zip_path) and not os.path.exists(folder_path):
|
73
|
+
logger.info(f"Found unextracted zip for {package_name}, extracting...")
|
74
|
+
try:
|
75
|
+
with zipfile.ZipFile(zip_path, "r") as zf:
|
76
|
+
# Extract files to the same directory where the zip file is located
|
77
|
+
zf.extractall(path=resource_dir)
|
78
|
+
|
79
|
+
if os.path.exists(folder_path):
|
80
|
+
logger.info(f"Successfully extracted {package_name}")
|
81
|
+
else:
|
82
|
+
logger.warning(
|
83
|
+
f"Extraction completed but resource directory not found for {package_name}"
|
84
|
+
)
|
85
|
+
except Exception as e:
|
86
|
+
logger.error(f"Failed to extract {package_name}: {e}")
|
risk/log/__init__.py
ADDED
risk/log/console.py
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
"""
|
2
|
+
risk/log/console
|
3
|
+
~~~~~~~~~~~~~~~~
|
4
|
+
"""
|
5
|
+
|
6
|
+
import logging
|
7
|
+
|
8
|
+
|
9
|
+
def in_jupyter():
|
10
|
+
"""Check if the code is running in a Jupyter notebook environment.
|
11
|
+
|
12
|
+
Returns:
|
13
|
+
bool: True if running in a Jupyter notebook or QtConsole, False otherwise.
|
14
|
+
"""
|
15
|
+
try:
|
16
|
+
shell = get_ipython().__class__.__name__
|
17
|
+
if shell == "ZMQInteractiveShell": # Jupyter Notebook or QtConsole
|
18
|
+
return True
|
19
|
+
if shell == "TerminalInteractiveShell": # Terminal running IPython
|
20
|
+
return False
|
21
|
+
|
22
|
+
return False # Other type (?)
|
23
|
+
except NameError:
|
24
|
+
return False # Not in Jupyter
|
25
|
+
|
26
|
+
|
27
|
+
# Define the MockLogger class to replicate logging behavior with print statements in Jupyter
|
28
|
+
class MockLogger:
|
29
|
+
"""MockLogger: A lightweight logger replacement using print statements in Jupyter.
|
30
|
+
|
31
|
+
The MockLogger class replicates the behavior of a standard logger using print statements
|
32
|
+
to display messages. This is primarily used in a Jupyter environment to show outputs
|
33
|
+
directly in the notebook. The class supports logging levels such as `info`, `debug`,
|
34
|
+
`warning`, and `error`, while the `verbose` attribute controls whether to display non-error messages.
|
35
|
+
"""
|
36
|
+
|
37
|
+
def __init__(self, verbose: bool = True):
|
38
|
+
"""Initialize the MockLogger with verbosity settings.
|
39
|
+
|
40
|
+
Args:
|
41
|
+
verbose (bool): If True, display all log messages (info, debug, warning).
|
42
|
+
If False, only display error messages. Defaults to True.
|
43
|
+
"""
|
44
|
+
self.verbose = verbose
|
45
|
+
|
46
|
+
def info(self, message: str) -> None:
|
47
|
+
"""Display an informational message.
|
48
|
+
|
49
|
+
Args:
|
50
|
+
message (str): The informational message to be printed.
|
51
|
+
"""
|
52
|
+
if self.verbose:
|
53
|
+
print(message)
|
54
|
+
|
55
|
+
def debug(self, message: str) -> None:
|
56
|
+
"""Display a debug message.
|
57
|
+
|
58
|
+
Args:
|
59
|
+
message (str): The debug message to be printed.
|
60
|
+
"""
|
61
|
+
if self.verbose:
|
62
|
+
print(message)
|
63
|
+
|
64
|
+
def warning(self, message: str) -> None:
|
65
|
+
"""Display a warning message.
|
66
|
+
|
67
|
+
Args:
|
68
|
+
message (str): The warning message to be printed.
|
69
|
+
"""
|
70
|
+
print(message)
|
71
|
+
|
72
|
+
def error(self, message: str) -> None:
|
73
|
+
"""Display an error message.
|
74
|
+
|
75
|
+
Args:
|
76
|
+
message (str): The error message to be printed.
|
77
|
+
"""
|
78
|
+
print(message)
|
79
|
+
|
80
|
+
def setLevel(self, level: int) -> None:
|
81
|
+
"""Adjust verbosity based on the logging level.
|
82
|
+
|
83
|
+
Args:
|
84
|
+
level (int): Logging level to control message display.
|
85
|
+
- logging.DEBUG sets verbose to True (show all messages).
|
86
|
+
- logging.WARNING sets verbose to False (show only warning, error, and critical messages).
|
87
|
+
"""
|
88
|
+
if level == logging.DEBUG:
|
89
|
+
self.verbose = True # Show all messages
|
90
|
+
elif level == logging.WARNING:
|
91
|
+
self.verbose = False # Suppress all except warning, error, and critical messages
|
92
|
+
|
93
|
+
|
94
|
+
# Set up logger based on environment
|
95
|
+
if not in_jupyter():
|
96
|
+
# Set up logger normally for .py files or terminal environments
|
97
|
+
logger = logging.getLogger("risk_logger")
|
98
|
+
logger.setLevel(logging.DEBUG)
|
99
|
+
console_handler = logging.StreamHandler()
|
100
|
+
console_handler.setLevel(logging.DEBUG)
|
101
|
+
console_handler.setFormatter(logging.Formatter("%(message)s"))
|
102
|
+
|
103
|
+
if not logger.hasHandlers():
|
104
|
+
logger.addHandler(console_handler)
|
105
|
+
else:
|
106
|
+
# If in Jupyter, use the MockLogger
|
107
|
+
logger = MockLogger()
|
108
|
+
|
109
|
+
|
110
|
+
def set_global_verbosity(verbose):
|
111
|
+
"""Set the global verbosity level for the logger.
|
112
|
+
|
113
|
+
Args:
|
114
|
+
verbose (bool): Whether to display all log messages (True) or only error messages (False).
|
115
|
+
|
116
|
+
Returns:
|
117
|
+
None
|
118
|
+
"""
|
119
|
+
if not isinstance(logger, MockLogger):
|
120
|
+
# For the regular logger, adjust logging levels
|
121
|
+
if verbose:
|
122
|
+
logger.setLevel(logging.DEBUG) # Show all messages
|
123
|
+
console_handler.setLevel(logging.DEBUG)
|
124
|
+
else:
|
125
|
+
logger.setLevel(logging.WARNING) # Show only warning, error, and critical messages
|
126
|
+
console_handler.setLevel(logging.WARNING)
|
127
|
+
else:
|
128
|
+
# For the MockLogger, set verbosity directly
|
129
|
+
logger.setLevel(logging.DEBUG if verbose else logging.WARNING)
|
130
|
+
|
131
|
+
|
132
|
+
def log_header(input_string: str) -> None:
|
133
|
+
"""Log the input string as a header with a line of dashes above and below it.
|
134
|
+
|
135
|
+
Args:
|
136
|
+
input_string (str): The string to be printed as a header.
|
137
|
+
"""
|
138
|
+
border = "-" * len(input_string)
|
139
|
+
logger.info(border)
|
140
|
+
logger.info(input_string)
|
141
|
+
logger.info(border)
|
risk/log/parameters.py
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
"""
|
2
|
+
risk/log/parameters
|
3
|
+
~~~~~~~~~~~~~~~~~~~
|
4
|
+
"""
|
5
|
+
|
6
|
+
import csv
|
7
|
+
import json
|
8
|
+
import warnings
|
9
|
+
from datetime import datetime
|
10
|
+
from typing import Any, Dict
|
11
|
+
|
12
|
+
import numpy as np
|
13
|
+
|
14
|
+
from risk.log.console import log_header, logger
|
15
|
+
|
16
|
+
# Suppress all warnings - this is to resolve warnings from multiprocessing
|
17
|
+
warnings.filterwarnings("ignore")
|
18
|
+
|
19
|
+
|
20
|
+
class Params:
|
21
|
+
"""Handles the storage and logging of various parameters for network analysis.
|
22
|
+
|
23
|
+
The Params class provides methods to log parameters related to different components of the analysis,
|
24
|
+
such as the network, annotations, neighborhoods, graph, and plotter settings. It also stores
|
25
|
+
the current datetime when the parameters were initialized.
|
26
|
+
"""
|
27
|
+
|
28
|
+
def __init__(self):
|
29
|
+
"""Initialize the Params object with default settings and current datetime."""
|
30
|
+
self.initialize()
|
31
|
+
self.datetime = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
32
|
+
|
33
|
+
def initialize(self) -> None:
|
34
|
+
"""Initialize the parameter dictionaries for different components."""
|
35
|
+
self.network = {}
|
36
|
+
self.annotations = {}
|
37
|
+
self.neighborhoods = {}
|
38
|
+
self.graph = {}
|
39
|
+
self.plotter = {}
|
40
|
+
|
41
|
+
def log_network(self, **kwargs) -> None:
|
42
|
+
"""Log network-related parameters.
|
43
|
+
|
44
|
+
Args:
|
45
|
+
**kwargs: Network parameters to log.
|
46
|
+
"""
|
47
|
+
self.network = {**self.network, **kwargs}
|
48
|
+
|
49
|
+
def log_annotations(self, **kwargs) -> None:
|
50
|
+
"""Log annotation-related parameters.
|
51
|
+
|
52
|
+
Args:
|
53
|
+
**kwargs: Annotation parameters to log.
|
54
|
+
"""
|
55
|
+
self.annotations = {**self.annotations, **kwargs}
|
56
|
+
|
57
|
+
def log_neighborhoods(self, **kwargs) -> None:
|
58
|
+
"""Log neighborhood-related parameters.
|
59
|
+
|
60
|
+
Args:
|
61
|
+
**kwargs: Neighborhood parameters to log.
|
62
|
+
"""
|
63
|
+
self.neighborhoods = {**self.neighborhoods, **kwargs}
|
64
|
+
|
65
|
+
def log_graph(self, **kwargs) -> None:
|
66
|
+
"""Log graph-related parameters.
|
67
|
+
|
68
|
+
Args:
|
69
|
+
**kwargs: Graph parameters to log.
|
70
|
+
"""
|
71
|
+
self.graph = {**self.graph, **kwargs}
|
72
|
+
|
73
|
+
def log_plotter(self, **kwargs) -> None:
|
74
|
+
"""Log plotter-related parameters.
|
75
|
+
|
76
|
+
Args:
|
77
|
+
**kwargs: Plotter parameters to log.
|
78
|
+
"""
|
79
|
+
self.plotter = {**self.plotter, **kwargs}
|
80
|
+
|
81
|
+
def to_csv(self, filepath: str) -> None:
|
82
|
+
"""Export the parameters to a CSV file.
|
83
|
+
|
84
|
+
Args:
|
85
|
+
filepath (str): The path where the CSV file will be saved.
|
86
|
+
"""
|
87
|
+
# Load the parameter dictionary
|
88
|
+
params = self.load()
|
89
|
+
# Open the file in write mode
|
90
|
+
with open(filepath, "w", encoding="utf-8", newline="") as csv_file:
|
91
|
+
writer = csv.writer(csv_file)
|
92
|
+
# Write the header
|
93
|
+
writer.writerow(["parent_key", "child_key", "value"])
|
94
|
+
# Write the rows
|
95
|
+
for parent_key, parent_value in params.items():
|
96
|
+
if isinstance(parent_value, dict):
|
97
|
+
for child_key, child_value in parent_value.items():
|
98
|
+
writer.writerow([parent_key, child_key, child_value])
|
99
|
+
else:
|
100
|
+
writer.writerow([parent_key, "", parent_value])
|
101
|
+
|
102
|
+
logger.info(f"Parameters exported to CSV file: {filepath}")
|
103
|
+
|
104
|
+
def to_json(self, filepath: str) -> None:
|
105
|
+
"""Export the parameters to a JSON file.
|
106
|
+
|
107
|
+
Args:
|
108
|
+
filepath (str): The path where the JSON file will be saved.
|
109
|
+
"""
|
110
|
+
with open(filepath, "w", encoding="utf-8") as json_file:
|
111
|
+
json.dump(self.load(), json_file, indent=4)
|
112
|
+
|
113
|
+
logger.info(f"Parameters exported to JSON file: {filepath}")
|
114
|
+
|
115
|
+
def to_txt(self, filepath: str) -> None:
|
116
|
+
"""Export the parameters to a text file.
|
117
|
+
|
118
|
+
Args:
|
119
|
+
filepath (str): The path where the text file will be saved.
|
120
|
+
"""
|
121
|
+
# Load the parameter dictionary
|
122
|
+
params = self.load()
|
123
|
+
# Open the file in write mode
|
124
|
+
with open(filepath, "w", encoding="utf-8") as txt_file:
|
125
|
+
for key, value in params.items():
|
126
|
+
# Write the key and its corresponding value
|
127
|
+
txt_file.write(f"{key}: {value}\n")
|
128
|
+
# Add a blank line after each entry
|
129
|
+
txt_file.write("\n")
|
130
|
+
|
131
|
+
logger.info(f"Parameters exported to text file: {filepath}")
|
132
|
+
|
133
|
+
def load(self) -> Dict[str, Any]:
|
134
|
+
"""Load and process various parameters, converting any np.ndarray values to lists.
|
135
|
+
|
136
|
+
Returns:
|
137
|
+
Dict[str, Any]: A dictionary containing the processed parameters.
|
138
|
+
"""
|
139
|
+
log_header("Loading parameters")
|
140
|
+
return self._convert_ndarray_to_list(
|
141
|
+
{
|
142
|
+
"annotations": self.annotations,
|
143
|
+
"datetime": self.datetime,
|
144
|
+
"graph": self.graph,
|
145
|
+
"neighborhoods": self.neighborhoods,
|
146
|
+
"network": self.network,
|
147
|
+
"plotter": self.plotter,
|
148
|
+
}
|
149
|
+
)
|
150
|
+
|
151
|
+
def _convert_ndarray_to_list(self, d: Dict[str, Any]) -> Dict[str, Any]:
|
152
|
+
"""Recursively convert all np.ndarray values in the dictionary to lists.
|
153
|
+
|
154
|
+
Args:
|
155
|
+
d (Dict[str, Any]): The dictionary to process.
|
156
|
+
|
157
|
+
Returns:
|
158
|
+
Dict[str, Any]: The processed dictionary with np.ndarray values converted to lists.
|
159
|
+
"""
|
160
|
+
if isinstance(d, dict):
|
161
|
+
# Recursively process each value in the dictionary
|
162
|
+
return {k: self._convert_ndarray_to_list(v) for k, v in d.items()}
|
163
|
+
if isinstance(d, list):
|
164
|
+
# Recursively process each item in the list
|
165
|
+
return [self._convert_ndarray_to_list(v) for v in d]
|
166
|
+
if isinstance(d, np.ndarray):
|
167
|
+
# Convert numpy arrays to lists
|
168
|
+
return d.tolist()
|
169
|
+
|
170
|
+
# Return the value unchanged if it's not a dict, List, or ndarray
|
171
|
+
return d
|