Skip to content

Commit

Permalink
#18 fixed branch information
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelweinold committed Oct 2, 2024
1 parent ab5b69f commit 58164da
Show file tree
Hide file tree
Showing 5 changed files with 227 additions and 19 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,6 @@ cython_debug/
.DS_Store

# development environment
bw_webapp_dev/
bw_webapp_dev/

.vscode
10 changes: 5 additions & 5 deletions app/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def nodes_dict_to_dataframe(nodes: dict) -> pd.DataFrame:
A dataframe with human-readable descriptions and emissions values of the nodes in the graph traversal.
"""
list_of_row_dicts = []
for i in range(0, len(nodes)-1):
for i in range(0, len(nodes)):
current_node: Node = nodes[i]
scope_1: bool = False
if current_node.unique_id == 0:
Expand Down Expand Up @@ -122,7 +122,7 @@ def edges_dict_to_dataframe(edges: dict) -> pd.DataFrame:

def trace_branch(df: pd.DataFrame, start_node: int) -> list:
"""
Given a dataframe of graph edges and a starting node, returns the branch of nodes that lead to the starting node.
Given a dataframe of graph edges and a "starting node" (producer_unique_id), returns the branch of nodes that lead to the starting node.
For example:
Expand All @@ -142,7 +142,7 @@ def trace_branch(df: pd.DataFrame, start_node: int) -> list:
df : pd.DataFrame
Dataframe of graph edges. Must contain integer-type columns 'consumer_unique_id' and 'producer_unique_id'.
start_node : int
The integer indicating the starting node to trace back from.
The integer indicating the producer_unique_id starting node to trace back from.
Returns
-------
Expand All @@ -162,7 +162,7 @@ def trace_branch(df: pd.DataFrame, start_node: int) -> list:
return branch


def add_branch_information_to_dataframe(df: pd.DataFrame) -> pd.DataFrame:
def add_branch_information_to_edges_dataframe(df: pd.DataFrame) -> pd.DataFrame:
"""
Adds 'branch' information to terminal nodes in a dataframe of graph edges.
Expand Down Expand Up @@ -471,7 +471,7 @@ def perform_graph_traversal(self, event):
if self.df_graph_traversal_edges.empty:
return
else:
self.df_graph_traversal_edges = add_branch_information_to_dataframe(self.df_graph_traversal_edges)
self.df_graph_traversal_edges = add_branch_information_to_edges_dataframe(self.df_graph_traversal_edges)
self.df_graph_traversal_nodes = pd.merge(
self.df_graph_traversal_nodes,
self.df_graph_traversal_edges,
Expand Down
206 changes: 206 additions & 0 deletions dev/trace_branch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
# %%
import bw_graph_tools as bgt
import bw2io as bi
import bw2data as bd
import bw2calc as bc
import pandas as pd

from bw2data.backends.proxies import Activity
from bw_graph_tools.graph_traversal import Node

if 'USEEIO-1.1' not in bd.projects:
bi.install_project(project_key="USEEIO-1.1", overwrite_existing=True)
bd.projects.set_current("USEEIO-1.1")
else:
bd.projects.set_current("USEEIO-1.1")

useeio = bd.Database("USEEIO-1.1")

cars_activity = bd.utils.get_node(
database = 'USEEIO-1.1',
name = 'Automobiles; at manufacturer',
type = 'product',
location = 'United States'
)

method_gcc = bd.Method(('Impact Potential', 'GCC'))
lca = bc.LCA(
demand={cars_activity: 1},
method = method_gcc.name # attention here: it's not the Method object, just its name!!!
)
lca.lci()
lca.lcia()

graph_traversal: dict = bgt.NewNodeEachVisitGraphTraversal.calculate(lca, cutoff=0.005)


def nodes_dict_to_dataframe(nodes: dict) -> pd.DataFrame:
"""
Returns a dataframe with human-readable descriptions and emissions values of the nodes in the graph traversal.
Parameters
----------
nodes : dict
A dictionary of nodes in the graph traversal.
Can be created by selecting the 'nodes' key from the dictionary
returned by the function `bw_graph_tools.NewNodeEachVisitGraphTraversal.calculate()`.
Returns
-------
pd.DataFrame
A dataframe with human-readable descriptions and emissions values of the nodes in the graph traversal.
"""
list_of_row_dicts = []
for i in range(0, len(nodes)-1):
current_node: Node = nodes[i]
scope_1: bool = False
if current_node.unique_id == 0:
scope_1 = True
else:
pass
list_of_row_dicts.append(
{
'UID': current_node.unique_id,
'Scope 1?': scope_1,
'Name': bd.get_node(id=current_node.activity_datapackage_id)['name'],
'Cumulative': current_node.cumulative_score,
'Direct': current_node.direct_emissions_score,
'Depth': current_node.depth,
'activity_datapackage_id': current_node.activity_datapackage_id,
}
)
return pd.DataFrame(list_of_row_dicts)


def edges_dict_to_dataframe(edges: dict) -> pd.DataFrame:
"""
To be added...
"""
if len(edges) < 2:
return pd.DataFrame()
else:
list_of_row_dicts = []
for i in range(0, len(edges)):
current_edge: Edge = edges[i]
list_of_row_dicts.append(
{
'consumer_unique_id': current_edge.consumer_unique_id,
'producer_unique_id': current_edge.producer_unique_id
}
)
return pd.DataFrame(list_of_row_dicts).drop(0)


def trace_branch(df: pd.DataFrame, start_node: int) -> list:
"""
Given a dataframe of graph edges and a starting node, returns the branch of nodes that lead to the starting node.
For example:
| consumer_unique_id | producer_unique_id |
|--------------------|--------------------|
| 0 | 1 | # 1 is terminal producer node
| 0 | 2 |
| 0 | 3 |
| 2 | 4 | # 4 is terminal producer node
| 3 | 5 |
| 5 | 6 | # 6 is terminal producer node
For start_node = 6, the function returns [0, 3, 5, 6]
Parameters
----------
df : pd.DataFrame
Dataframe of graph edges. Must contain integer-type columns 'consumer_unique_id' and 'producer_unique_id'.
start_node : int
The integer indicating the starting node to trace back from.
Returns
-------
list
A list of integers indicating the branch of nodes that lead to the starting node.
"""

branch: list = [start_node]

while True:
previous_node: int = df[df['producer_unique_id'] == start_node]['consumer_unique_id']
if previous_node.empty:
break
start_node: int = previous_node.values[0]
branch.insert(0, start_node)

return branch


def add_branch_information_to_dataframe(df: pd.DataFrame) -> pd.DataFrame:
"""
Adds 'branch' information to terminal nodes in a dataframe of graph edges.
For example:
| consumer_unique_id | producer_unique_id |
|--------------------|--------------------|
| 0 | 1 | # 1 is terminal producer node
| 0 | 2 |
| 0 | 3 |
| 2 | 4 | # 4 is terminal producer node
| 3 | 5 |
| 5 | 6 | # 6 is terminal producer node
| consumer_unique_id | producer_unique_id | branch |
|--------------------|--------------------|--------------|
| 0 | 1 | [0, 1] |
| 0 | 2 | [0, 2] |
| 0 | 3 | [0, 3] |
| 2 | 4 | [0, 2, 4] |
| 3 | 5 | [0, 3, 5] |
| 5 | 6 | [0, 3, 5, 6] |
Parameters
----------
df_edges : pd.DataFrame
A dataframe of graph edges.
Must contain integer-type columns 'consumer_unique_id' and 'producer_unique_id'.
Returns
-------
pd.DataFrame
A dataframe of graph nodes with a column 'branch' that contains the branch of nodes that lead to the terminal producer node.
"""
# initialize empty list to store branches
branches: list = []

for _, row in df.iterrows():
branch: list = trace_branch(df, int(row['producer_unique_id']))
branches.append({
'producer_unique_id': int(row['producer_unique_id']),
'Branch': branch
})

return pd.DataFrame(branches)


def merge_enriched_edge_dataframe_into_nodes_dataframe(df_left, df_right):
"""
Merges the enriched edges DataFrame with the nodes DataFrame
to add branch information.
Note that the last row is dropped, since
| UID | ... |
|-----|-----|
| 0 | ... |
| 1 | ... |
| 2 | ... |
"""
self.df_graph_traversal_nodes = pd.merge(
df_nodes,
df_edges_enriched,
left_on='UID',
right_on='producer_unique_id',
how='left'
).iloc[:-1] # the
24 changes: 12 additions & 12 deletions pyodide/index.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyodide/index.js

Large diffs are not rendered by default.

0 comments on commit 58164da

Please sign in to comment.