33from typing import Iterable , Optional , Union
44from logging import getLogger
55
6- import bw2analyzer as ba
76import bw2calc as bc
87import numpy as np
98import pandas as pd
109from PySide2 .QtWidgets import QApplication , QMessageBox
1110
1211from activity_browser .mod import bw2data as bd
12+ from activity_browser .mod .bw2analyzer import ABContributionAnalysis
1313
1414from .commontasks import wrap_text
1515from .errors import ReferenceFlowValueError
1616from .metadata import AB_metadata
1717
1818log = getLogger (__name__ )
19- ca = ba . ContributionAnalysis ()
19+ ca = ABContributionAnalysis ()
2020
2121
2222class MLCA (object ):
@@ -394,20 +394,24 @@ def __init__(self, mlca):
394394 ),
395395 }
396396
397- def normalize (self , contribution_array : np .ndarray ) -> np .ndarray :
398- """Normalise the contribution array.
397+ def normalize (self , contribution_array : np .ndarray , total_range : bool = True ) -> np .ndarray :
398+ """Normalize the contribution array based on range or score
399399
400400 Parameters
401401 ----------
402402 contribution_array : A 2-dimensional contribution array
403+ total_range : A bool, True for normalization based on range, False for score
403404
404405 Returns
405406 -------
406407 2-dimensional array of same shape, with scores normalized.
407408
408409 """
409- scores = abs (contribution_array .sum (axis = 1 , keepdims = True ))
410- return contribution_array / scores
410+ if total_range : # total is based on the range
411+ total = abs (abs (contribution_array ).sum (axis = 1 , keepdims = True ))
412+ else : # total is based on the score
413+ total = abs (contribution_array .sum (axis = 1 , keepdims = True ))
414+ return contribution_array / total
411415
412416 def _build_dict (
413417 self ,
@@ -437,12 +441,13 @@ def _build_dict(
437441 for fu_or_method , col in FU_M_index .items ():
438442 contribution_col = contributions [col , :]
439443 if total_range : # total is based on the range
440- total = np .abs (contribution_col ).sum ()
444+ normalize_to = np .abs (contribution_col ).sum ()
441445 else : # total is based on the score
442- total = contribution_col .sum ()
446+ normalize_to = contribution_col .sum ()
447+ score = contribution_col .sum ()
443448
444449 top_contribution = ca .sort_array (
445- contribution_col , limit = limit , limit_type = limit_type , total = total
450+ contribution_col , limit = limit , limit_type = limit_type , total = normalize_to
446451 )
447452
448453 # split and calculate remaining rest sections for positive and negative part
@@ -458,7 +463,7 @@ def _build_dict(
458463 cont_per = OrderedDict ()
459464 cont_per .update (
460465 {
461- ("Total " , "" ): total ,
466+ ("Score " , "" ): score ,
462467 ("Rest (+)" , "" ): pos_rest ,
463468 ("Rest (-)" , "" ): neg_rest ,
464469 }
@@ -602,20 +607,21 @@ def get_labelled_contribution_dict(
602607 # If the cont_dict has tuples for keys, coerce df.columns into MultiIndex
603608 if all (isinstance (k , tuple ) for k in cont_dict .keys ()):
604609 df .columns = pd .MultiIndex .from_tuples (df .columns )
605- special_keys = [("Total" , "" ), ("Rest (+)" , "" ), ("Rest (-)" , "" )]
610+
611+ special_keys = [("Score" , "" ), ("Rest (+)" , "" ), ("Rest (-)" , "" )]
606612 # replace all 0 values with NaN and drop all rows with only NaNs
607613 df = df .replace (0 , np .nan )
608614
609- # sort on absolute mean of a row
610- df_bot = deepcopy (df .loc [df .index .difference (special_keys )].dropna (how = "all" ))
611-
612- func = lambda row : np .nanmean (np .abs (row ))
615+ # sort on mean square of a row
616+ df_bot = deepcopy (df .iloc [3 :, :])
617+ func = lambda row : np .nanmean (np .square (row ))
613618 if len (df_bot ) > 1 : # but only sort if there is something to sort
614619 df_bot ["_sort_me_" ] = (df_bot .select_dtypes (include = np .number )).apply (func , axis = 1 )
615620 df_bot .sort_values (by = "_sort_me_" , ascending = False , inplace = True )
616621 del df_bot ["_sort_me_" ]
617622
618623 df = pd .concat ([df .iloc [:3 , :], df_bot ], axis = 0 )
624+ df .dropna (how = "all" , inplace = True )
619625
620626 if not mask :
621627 joined = self .join_df_with_metadata (
@@ -638,7 +644,7 @@ def adjust_table_unit(df: pd.DataFrame, method: Optional[tuple]) -> pd.DataFrame
638644 """Given a dataframe, adjust the unit of the table to either match the given method, or not exist."""
639645 if "unit" not in df .columns :
640646 return df
641- keys = df .index [~ df ["index" ].isin ({"Total " , "Rest (+)" , "Rest (-)" })]
647+ keys = df .index [~ df ["index" ].isin ({"Score " , "Rest (+)" , "Rest (-)" })]
642648 unit = bd .Method (method ).metadata .get ("unit" ) if method else "unit"
643649 df .loc [keys , "unit" ] = unit
644650 return df
@@ -850,7 +856,7 @@ def top_elementary_flow_contributions(
850856
851857 # Normalise if required
852858 if normalize :
853- contributions = self .normalize (contributions )
859+ contributions = self .normalize (contributions , total_range )
854860
855861 top_cont_dict = self ._build_dict (
856862 contributions , index , rev_index , limit , limit_type , total_range
@@ -906,7 +912,7 @@ def top_process_contributions(
906912
907913 # Normalise if required
908914 if normalize :
909- contributions = self .normalize (contributions )
915+ contributions = self .normalize (contributions , total_range )
910916
911917 top_cont_dict = self ._build_dict (
912918 contributions , index , rev_index , limit , limit_type , total_range
0 commit comments