Skip to content

Commit

Permalink
Refactored to allow project changes
Browse files Browse the repository at this point in the history
  • Loading branch information
ajkolenc committed Jan 31, 2025
1 parent 76af681 commit dcab07d
Show file tree
Hide file tree
Showing 49 changed files with 1,886 additions and 1,155 deletions.
1 change: 1 addition & 0 deletions environment/configuration/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ matplotlib
networkx[default]
pyside6>=6.6
flet==0.25.*
pyodide-py
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ profile = "black"

[tool.pylint]
max-line-length=240
disable = "C0103, C0114, C0115, C0116, C0302, E0401, W0212, W0511, R0801, R0902, R0903, R0913, R0914, R0904, R0917"
disable = "C0103, C0114, C0115, C0116, C0302, E0401, W0212, W0511, R0801, R0902, R0903, R0913, R0914, R0904, R0917, W0718"
extension-pkg-allow-list = [
"matplotlib",
]
Expand Down
7 changes: 4 additions & 3 deletions source/package/adaptation_pathways/app/model/metric.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,14 +147,15 @@ class Volume:
si = [
MetricUnit(name="Milliliter", symbol="ml"),
MetricUnit(name="Liter", symbol="l"),
MetricUnit(name="Cubic Centimeter", symbol="cm^3"),
MetricUnit(name="Cubic Meter", symbol="m^3"),
MetricUnit(name="Cubic Centimeter", symbol="cm³"),
MetricUnit(name="Cubic Meter", symbol="m³"),
]
imperial = [
MetricUnit(name="Fluid Ounce", symbol="fl oz"),
MetricUnit(name="Pint", symbol="pt"),
MetricUnit(name="Quart", symbol="qt"),
MetricUnit(name="Gallon", symbol="gal"),
MetricUnit(name="Acre Feet", symbol="ac-ft"),
]

volume = Volume()
Expand Down Expand Up @@ -233,7 +234,7 @@ class MassWeight:
]

relative = [
MetricUnit(name="Percent", symbol="%", value_format=".2%"),
MetricUnit(name="Percent", symbol="%", value_format=".2"),
MetricUnit(
name="Impact", symbol="", short_name="Impact", value_format=FORMAT_SLIDER
),
Expand Down
194 changes: 82 additions & 112 deletions source/package/adaptation_pathways/app/model/pathways_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
"""
The single class that stores all data needed to work on a project
"""
from typing import Callable, Iterable

from adaptation_pathways.app.model.sorting import SortingInfo
from json import JSONEncoder
from typing import Iterable

from .action import Action
from .metric import Metric, MetricEffect, MetricOperation, MetricValue, MetricValueState
Expand All @@ -20,13 +19,22 @@ def __init__(
organization: str,
start_year: int,
end_year: int,
conditions: list[Metric],
criteria: list[Metric],
scenarios: list[Scenario],
actions: list[Action],
pathways: list[Pathway],
root_action: Action,
root_pathway_id: str,
conditions_by_id: dict[str, Metric] | None = None,
condition_ids: list[str] | None = None,
criteria_by_id: dict[str, Metric] | None = None,
criteria_ids: list[str] | None = None,
actions_by_id: dict[str, Action] | None = None,
action_ids: list[str] | None = None,
scenarios_by_id: dict[str, Scenario] | None = None,
scenario_ids: list[str] | None = None,
pathways_by_id: dict[str, Pathway] | None = None,
pathway_ids: list[str] | None = None,
root_action_id: str = "",
root_pathway_id: str = "",
values_scenario_id: str | None = None,
graph_metric_id: str | None = None,
graph_scenario_id: str | None = None,
graph_is_time=False,
):
self.id = project_id
self.name = name
Expand All @@ -35,108 +43,50 @@ def __init__(
self.end_year = end_year
self._current_id = 0

self.conditions_by_id: dict[str, Metric] = {}
for metric in conditions:
self.conditions_by_id[metric.id] = metric

self.criteria_by_id: dict[str, Metric] = {}
for metric in criteria:
self.criteria_by_id[metric.id] = metric

self.scenarios_by_id: dict[str, Scenario] = {}
for scenario in scenarios:
self.scenarios_by_id[scenario.id] = scenario

self.actions_by_id: dict[str, Action] = {}
self.actions_by_id[root_action.id] = root_action
for action in actions:
self.actions_by_id[action.id] = action

self.pathways_by_id: dict[str, Pathway] = {}
for pathway in pathways:
self.pathways_by_id[pathway.id] = pathway

self.condition_sorting = SortingInfo()
self.criteria_sorting = SortingInfo()
self.scenario_sorting = SortingInfo()
self.action_sorting = SortingInfo()
self.pathway_sorting = SortingInfo()

self.root_pathway_id = root_pathway_id
self.selected_condition_ids: set[str] = set()
self.selected_criteria_ids: set[str] = set()
self.selected_action_ids: set[str] = set()
self.selected_pathway_ids: set[str] = set()
self.selected_scenario_ids: set[str] = set()

self.values_scenario_id: str | None = (
None if len(scenarios) == 0 else scenarios[0].id
)

self.graph_metric_id: str | None = (
conditions[0].id if len(conditions) > 0 else None
)
self.graph_is_time: bool = self.graph_metric_id is not None
self.graph_scenario_id: str | None = (
scenarios[0].id if len(scenarios) > 0 else None
)

self.on_conditions_changed: list[Callable[[], None]] = []
self.on_criteria_changed: list[Callable[[], None]] = []
self.on_scenarios_changed: list[Callable[[], None]] = []
self.on_actions_changed: list[Callable[[], None]] = []
self.on_action_color_changed: list[Callable[[], None]] = []
self.on_pathways_changed: list[Callable[[], None]] = []

for metric in self.all_metrics():
self.update_pathway_values(metric.id)

def __hash__(self):
return self.id.__hash__()
self.condition_ids = condition_ids or []
self.conditions_by_id = conditions_by_id or {}
self.criteria_ids = criteria_ids or []
self.criteria_by_id = criteria_by_id or {}

def notify_conditions_changed(self):
for listener in self.on_conditions_changed:
listener()
self.scenario_ids = scenario_ids or []
self.scenarios_by_id = scenarios_by_id or {}

def notify_criteria_changed(self):
for listener in self.on_criteria_changed:
listener()
self.action_ids = action_ids or []
self.actions_by_id = actions_by_id or {}

def notify_scenarios_changed(self):
for listener in self.on_scenarios_changed:
listener()
self.pathway_ids = pathway_ids or []
self.pathways_by_id = pathways_by_id or {}

def notify_actions_changed(self):
for listener in self.on_actions_changed:
listener()
self.root_pathway_id = root_pathway_id or ""
self.root_action_id = root_action_id or ""

def notify_action_color_changed(self):
for listener in self.on_action_color_changed:
listener()
self.values_scenario_id = values_scenario_id or "none"
self.graph_metric_id = graph_metric_id or "none"
self.graph_scenario_id = graph_scenario_id or "none"
self.graph_is_time = graph_is_time

def notify_pathways_changed(self):
for listener in self.on_pathways_changed:
listener()
def __hash__(self):
return self.id.__hash__()

@property
def all_actions(self):
return self.actions_by_id.values()
def all_conditions(self) -> Iterable[Metric]:
return (self.conditions_by_id[metric_id] for metric_id in self.condition_ids)

@property
def all_conditions(self):
return self.conditions_by_id.values()
def all_criteria(self) -> Iterable[Metric]:
return (self.criteria_by_id[metric_id] for metric_id in self.criteria_ids)

@property
def all_criteria(self):
return self.criteria_by_id.values()
def all_scenarios(self) -> Iterable[Scenario]:
return (self.scenarios_by_id[scenario_id] for scenario_id in self.scenario_ids)

@property
def all_scenarios(self):
return self.scenarios_by_id.values()
def all_actions(self) -> Iterable[Action]:
return (self.actions_by_id[action_id] for action_id in self.action_ids)

@property
def all_pathways(self):
return self.pathways_by_id.values()
def all_pathways(self) -> Iterable[Pathway]:
return (self.pathways_by_id[pathway_id] for pathway_id in self.pathway_ids)

@property
def root_pathway(self):
Expand Down Expand Up @@ -168,10 +118,13 @@ def all_metrics(self):
yield from self.all_conditions
yield from self.all_criteria

def _create_metric(self, name: str, metrics_by_id: dict[str, Metric]) -> Metric:
def _create_metric(
self, name: str, metrics_by_id: dict[str, Metric], metric_ids: list[str]
) -> Metric:
metric_id = self._create_id()
metric = Metric(metric_id, name, "")
metrics_by_id[metric_id] = metric
metric_ids.append(metric_id)

for action in self.all_actions:
action.metric_data[metric_id] = MetricEffect(0, MetricOperation.ADD)
Expand All @@ -180,21 +133,28 @@ def _create_metric(self, name: str, metrics_by_id: dict[str, Metric]) -> Metric:
return metric

def create_condition(self) -> Metric:
metric = self._create_metric("New Condition", self.conditions_by_id)
metric = self._create_metric(
"New Condition", self.conditions_by_id, self.condition_ids
)
if self.graph_metric_id == "none":
self.graph_metric_id = metric.id

return metric

def create_criteria(self) -> Metric:
metric = self._create_metric("New Criteria", self.criteria_by_id)
metric = self._create_metric(
"New Criteria", self.criteria_by_id, self.criteria_ids
)
return metric

def delete_condition(self, metric_id: str) -> Metric | None:
metric = self.conditions_by_id.pop(metric_id)
self.selected_condition_ids.remove(metric_id)
self.condition_ids.remove(metric_id)
return metric

def delete_criteria(self, metric_id: str) -> Metric | None:
metric = self.criteria_by_id.pop(metric_id)
self.selected_criteria_ids.remove(metric_id)
self.criteria_ids.remove(metric_id)
return metric

def get_scenario(self, scenario_id: str) -> Scenario | None:
Expand All @@ -204,8 +164,11 @@ def create_scenario(self, name: str) -> Scenario:
scenario_id = self._create_id()
scenario = Scenario(scenario_id, name)
self.scenarios_by_id[scenario.id] = scenario
if self.graph_scenario_id is None:
self.scenario_ids.append(scenario.id)

if self.graph_scenario_id == "none":
self.graph_scenario_id = scenario_id

return scenario

def copy_scenario(self, scenario_id: str, suffix=" (Copy)") -> Scenario | None:
Expand All @@ -225,8 +188,11 @@ def copy_scenario(self, scenario_id: str, suffix=" (Copy)") -> Scenario | None:

def delete_scenario(self, scenario_id: str) -> Scenario | None:
scenario = self.scenarios_by_id.pop(scenario_id)
if self.graph_scenario_id is scenario_id:
self.graph_scenario_id = next(self.all_scenarios, None)
self.scenario_ids.remove(scenario_id)
if self.graph_scenario_id == scenario_id:
self.graph_scenario_id = (
self.scenario_ids[0] if len(self.scenario_ids) > 0 else "none"
)
return scenario

def delete_scenarios(self, scenario_ids: Iterable[str]):
Expand All @@ -240,11 +206,11 @@ def update_scenario_values(self, metric_id: str):
def get_action(self, action_id: str) -> Action:
return self.actions_by_id[action_id]

def create_action(self, color, icon) -> Action:
def create_action(self, color: str, icon: str, name: str | None = None) -> Action:
action_id = self._create_id()
action = Action(
action_id,
"New Action",
name or f"New Action ({action_id})",
color,
icon,
{
Expand All @@ -254,10 +220,12 @@ def create_action(self, color, icon) -> Action:
)

self.actions_by_id[action.id] = action
self.action_ids.append(action.id)
return action

def delete_action(self, action_id: str) -> Action | None:
action = self.actions_by_id.pop(action_id)
self.action_ids.remove(action_id)
return action

def delete_actions(self, action_ids: Iterable[str]):
Expand All @@ -281,6 +249,8 @@ def create_pathway(
) -> Pathway:
pathway = Pathway(action_id, parent_pathway_id)
self.pathways_by_id[pathway.id] = pathway
self.pathway_ids.append(pathway.id)

for metric in self.all_metrics():
self.update_pathway_values(metric.id)

Expand Down Expand Up @@ -340,12 +310,12 @@ def _update_pathway_value(

def delete_pathway(self, pathway_id: str) -> Pathway | None:
pathway = self.pathways_by_id.pop(pathway_id, None)
self.pathway_ids.append(pathway_id)
return pathway

def delete_pathways(self, pathway_ids: Iterable[str]):
ids_to_delete: set[str] = set()
ids_to_delete.update(pathway_ids)
print(ids_to_delete)

# Delete any orphaned children
for pathway in self.all_pathways:
Expand All @@ -357,13 +327,8 @@ def delete_pathways(self, pathway_ids: Iterable[str]):
ids_to_delete.add(pathway.id)

for pathway_id in ids_to_delete:
print(pathway_id)
self.delete_pathway(pathway_id)

def delete_selected_pathways(self):
self.delete_pathways(self.selected_pathway_ids)
self.selected_pathway_ids.clear()

def get_children(self, pathway_id: str):
return (
pathway for pathway in self.all_pathways if pathway.parent_id == pathway_id
Expand All @@ -388,3 +353,8 @@ def get_ancestors_and_self(self, pathway: Pathway):
current_pathway = self.get_pathway(current_pathway.parent_id)
else:
current_pathway = None


class PathwaysProjectEncoder(JSONEncoder):
def default(self, o):
return o.__dict__
8 changes: 4 additions & 4 deletions source/package/adaptation_pathways/app/model/scenario.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ def _get_previous_value(
) -> tuple[int, MetricValue, int] | None:
for index in range(year_index - 1, -1, -1):
data = self.yearly_data[index]
metric_value = data.metric_data[metric_id]
if not metric_value.is_estimate:
metric_value = data.metric_data.get(metric_id, None)
if metric_value is not None and not metric_value.is_estimate:
return (data.year, metric_value, index)
return None

Expand All @@ -124,8 +124,8 @@ def _get_next_value(
) -> tuple[int, MetricValue, int] | None:
for index in range(year_index + 1, len(self.yearly_data)):
data = self.yearly_data[index]
metric_value = data.metric_data[metric_id]
if not metric_value.is_estimate:
metric_value = data.metric_data.get(metric_id, None)
if metric_value is not None and not metric_value.is_estimate:
return (data.year, metric_value, index)

return None
Expand Down
File renamed without changes.
Loading

0 comments on commit dcab07d

Please sign in to comment.