-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add CF uncertainty and many improvements (#356)
* Add CF context menu, implement wizard and delegates * Allow CFTable to handle modifying CFs and storing them correctly in methods * Add TupleNameDialog for ease of editing a method name * Implement IA method copy dialog, warn when given name exists * Add wiring to MethodsTab to filter by copied method * Simplify MethodsTable selectedItems method and related code * Modify method to account for possible third item in tuple * Add uncertainty interface classes to simplify data extraction * Show the new value that will be set for amount in warning * Remove lognormal_check property from wizard page * Add additional code to show mean where distribution does not * Alter label of 'loc' field to match distribution description * Show the mean/amount value on the generated distplot * Ensure cf table always reflects hide/show toggle * Additional catches for invalid input to avoid error spam
- Loading branch information
1 parent
f1a3c93
commit 2dff150
Showing
9 changed files
with
512 additions
and
153 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
# -*- coding: utf-8 -* | ||
import abc | ||
|
||
from bw2data.parameters import ParameterBase | ||
from bw2data.proxies import ExchangeProxyBase | ||
from stats_arrays import ( | ||
UncertaintyBase, UndefinedUncertainty, uncertainty_choices as uc | ||
) | ||
|
||
|
||
class BaseUncertaintyInterface(abc.ABC): | ||
__slots__ = ["_data"] | ||
KEYS = { | ||
"uncertainty type", "loc", "scale", "shape", "minimum", "maximum", | ||
"negative" | ||
} | ||
data_type = "" | ||
|
||
def __init__(self, unc_obj): | ||
self._data = unc_obj | ||
|
||
@property | ||
def data(self): | ||
return self._data | ||
|
||
@property | ||
@abc.abstractmethod | ||
def amount(self) -> float: | ||
pass | ||
|
||
@property | ||
@abc.abstractmethod | ||
def uncertainty_type(self) -> UncertaintyBase: | ||
pass | ||
|
||
@property | ||
@abc.abstractmethod | ||
def uncertainty(self) -> dict: | ||
pass | ||
|
||
|
||
class ExchangeUncertaintyInterface(BaseUncertaintyInterface): | ||
"""Many kinds of exchanges use uncertainty to describe how 'correct' the | ||
data is which makes up the amount of the exchange. | ||
""" | ||
_data: ExchangeProxyBase | ||
data_type = "exchange" | ||
|
||
@property | ||
def amount(self) -> float: | ||
return self._data.amount | ||
|
||
@property | ||
def uncertainty_type(self) -> UncertaintyBase: | ||
return self._data.uncertainty_type | ||
|
||
@property | ||
def uncertainty(self) -> dict: | ||
return self._data.uncertainty | ||
|
||
|
||
class ParameterUncertaintyInterface(BaseUncertaintyInterface): | ||
"""All levels of parameters can describe their amounts with uncertainty.""" | ||
_data: ParameterBase | ||
data_type = "parameter" | ||
|
||
@property | ||
def amount(self) -> float: | ||
return self._data.amount | ||
|
||
@property | ||
def uncertainty_type(self) -> UncertaintyBase: | ||
if "uncertainty type" not in self._data.data: | ||
return UndefinedUncertainty | ||
return uc[self._data.data.get("uncertainty type", 0)] | ||
|
||
@property | ||
def uncertainty(self) -> dict: | ||
return {k: self._data.data.get(k) for k in self.KEYS if k in self._data.data} | ||
|
||
|
||
class CFUncertaintyInterface(BaseUncertaintyInterface): | ||
"""The characterization factors (CFs) of an impact assessment method can also | ||
contain uncertainty. | ||
This is however not certain (ha), as the CF is made up out of a flow key | ||
and either an amount (float) or the uncertainty values + an amount (dict). | ||
See the ``Method`` and ``ProcessedDataStore`` classes in the bw2data library. | ||
""" | ||
_data: tuple | ||
data_type = "cf" | ||
|
||
@property | ||
def is_uncertain(self) -> bool: | ||
return isinstance(self._data[1], dict) | ||
|
||
@property | ||
def amount(self) -> float: | ||
return self._data[1]["amount"] if self.is_uncertain else self._data[1] | ||
|
||
@property | ||
def uncertainty_type(self) -> UncertaintyBase: | ||
if not self.is_uncertain: | ||
return UndefinedUncertainty | ||
return uc[self._data[1].get("uncertainty type", 0)] | ||
|
||
@property | ||
def uncertainty(self) -> dict: | ||
if not self.is_uncertain: | ||
return {} | ||
return {k: self._data[1].get(k) for k in self.KEYS if k in self._data[1]} | ||
|
||
|
||
def get_uncertainty_interface(data: object) -> BaseUncertaintyInterface: | ||
if isinstance(data, ExchangeProxyBase): | ||
return ExchangeUncertaintyInterface(data) | ||
elif isinstance(data, ParameterBase): | ||
return ParameterUncertaintyInterface(data) | ||
elif isinstance(data, tuple): | ||
return CFUncertaintyInterface(data) | ||
else: | ||
raise TypeError( | ||
"No uncertainty interface exists for object type {}".format(type(data)) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.