diff --git a/repair/apps/asmfa/graphs/graph.py b/repair/apps/asmfa/graphs/graph.py
index 09066c247..e251701db 100644
--- a/repair/apps/asmfa/graphs/graph.py
+++ b/repair/apps/asmfa/graphs/graph.py
@@ -724,6 +724,7 @@ def _get_affected_flows(self, solution_part):
origin__activity = af.origin_activity,
destination__activity = af.destination_activity
)
+
kwargs = {
'strategy_material': af.material.id
}
diff --git a/repair/apps/asmfa/graphs/graphwalker.py b/repair/apps/asmfa/graphs/graphwalker.py
index 1ad106d7e..261f9b4cf 100644
--- a/repair/apps/asmfa/graphs/graphwalker.py
+++ b/repair/apps/asmfa/graphs/graphwalker.py
@@ -1,48 +1,79 @@
try:
import graph_tool as gt
- from graph_tool import util, search
+ from graph_tool import search
from graph_tool.search import BFSVisitor
except ModuleNotFoundError:
class BFSVisitor:
pass
import copy
-import numpy as np
-from django.db.models import Q
-import time
-
-from repair.apps.asmfa.models.flows import FractionFlow
-from repair.apps.asmfa.models import Actor
class NodeVisitor(BFSVisitor):
- def __init__(self, name, amount, visited, change,
- balance_factor):
+ def __init__(self, name, amount, change,
+ balance_factor, forward=True):
self.id = name
self.amount = amount
- self.visited = visited
self.change = change
self.balance_factor = balance_factor
+ self.forward = forward
+
+ def examine_vertex(self, u):
+ vertex_id = int(u)
+ out_degree = u.out_degree()
+ if not out_degree:
+ return
+
+ bf = self.balance_factor[vertex_id]
+ sum_in_deltas = u.in_degree(weight=self.change)
+ balanced_delta = sum_in_deltas * bf
+ sum_out_f = u.out_degree(weight=self.amount)
+ if sum_out_f:
+ amount_factor = balanced_delta / sum_out_f
+ else:
+ amount_factor = balanced_delta / out_degree
- def examine_edge(self, e):
- """Compute the amount change on each inflow for the vertex
+ for e_out in u.out_edges():
+ amount_delta = self.amount[e_out] * amount_factor
+ if self.forward:
+ self.change[e_out] += amount_delta
+ else:
+ if abs(self.change[e_out]) < abs(amount_delta):
+ self.change[e_out] = amount_delta
+ else:
+ self.change[e_out] += amount_delta
+
+
+class NodeVisitorBalanceDeltas(BFSVisitor):
+
+ def __init__(self, name, amount, change,
+ balance_factor):
+ self.id = name
+ self.amount = amount
+ self.change = change
+ self.balance_factor = balance_factor
- This function is invoked on a edge as it is popped from the queue.
- """
- u = e.target()
+ def examine_vertex(self, u):
vertex_id = int(u)
+ out_degree = u.out_degree()
+ if not out_degree:
+ return
- balanced_delta = self.change[e] * self.balance_factor[vertex_id]
- edges_out = list(u.out_edges())
- sum_out_f = sum(self.amount[out_f] for out_f in edges_out)
+ sum_in_deltas = u.in_degree(self.change)
+ sum_out_deltas = u.out_degree(self.change)
+ bf = self.balance_factor[vertex_id]
+ balanced_out_deltas = sum_out_deltas / bf
+ balanced_delta = sum_in_deltas - balanced_out_deltas
+ if abs(balanced_delta) < 0.0000001:
+ return
+ sum_out_f = u.out_degree(weight=self.amount)
if sum_out_f:
amount_factor = balanced_delta / sum_out_f
- elif edges_out:
- amount_factor = balanced_delta / len(edges_out)
- for e_out in edges_out:
- if not (self.visited[e_out] and self.visited[e]):
- self.change[e_out] += self.amount[e_out] * amount_factor
- self.visited[e_out] = True
+ else:
+ amount_factor = balanced_delta / out_degree
+ for e_out in u.out_edges():
+ amount_delta = self.amount[e_out] * amount_factor
+ self.change[e_out] += amount_delta
def traverse_graph(g, edge, delta, upstream=True):
@@ -61,47 +92,173 @@ def traverse_graph(g, edge, delta, upstream=True):
Edge ProperyMap (float)
The signed change on the edges
"""
- # Property map for keeping track of the visited edge. Once an edge has
- # been visited it won't be processed anymore.
+ plot = False
amount = g.ep.amount
- visited = g.new_edge_property("bool", val=False)
change = g.new_edge_property("float", val=0.0)
- change[edge] = delta
- visited[edge] = True
+ total_change = g.new_edge_property("float", val=0.0)
+
+ if plot:
+ # prepare plotting of intermediate results
+ from repair.apps.asmfa.tests import flowmodeltestdata
+ flowmodeltestdata.plot_materials(g, file='materials.png')
+ flowmodeltestdata.plot_amounts(g,'amounts.png', 'amount')
+ g.ep.change = change
# We are only interested in the edges that define the solution
g.set_edge_filter(g.ep.include)
+ MAX_ITERATIONS = 20
+ balance_factor = g.vp.downstream_balance_factor.a
+
+ # make a first run with the given changes to the implementation edge
# By default we go upstream first, because 'demand dictates supply'
if upstream:
+ node = edge.source()
g.set_reversed(True)
- balance_factor = 1 / g.vp.downstream_balance_factor.a
- node = edge.target()
+ balance_factor = 1 / balance_factor
else:
+ node = edge.target()
g.set_reversed(False)
- balance_factor = g.vp.downstream_balance_factor.a
- node = edge.source()
- node_visitor = NodeVisitor(g.vp["id"], amount, visited, change,
+ # initialize the node-visitors
+ node_visitor = NodeVisitor(g.vp["id"], amount, change,
+ balance_factor)
+ node_visitor2 = NodeVisitorBalanceDeltas(g.vp["id"], amount, change,
balance_factor)
+
+ node_visitor.forward = True
+ total_change.a[:] = 0
+ new_delta = delta
+ i = 0
+ change[edge] = new_delta
+ # start in one direction
search.bfs_search(g, node, node_visitor)
+ change[edge] = new_delta
- # now go downstream, if we started upstream
- # (or upstream, if we started downstream)
+ if plot:
+ ## Plot changes after forward run
+ g.ep.change.a[:] = change.a
+ flowmodeltestdata.plot_amounts(g,'plastic_deltas.png', 'change')
- g.set_reversed(not g.is_reversed())
- node = edge.target() if g.is_reversed() else edge.source()
- # reverse the balancing factors
- node_visitor.balance_factor = 1 / node_visitor.balance_factor
- # print("\nTraversing in 2. direction")
+ node = reverse_graph(g, node_visitor, node_visitor2, edge)
search.bfs_search(g, node, node_visitor)
+ change[edge] = new_delta
+
+ if plot:
+ ## Plot changes after backward run
+ g.ep.change.a[:] = change.a
+ flowmodeltestdata.plot_amounts(g,'plastic_deltas.png', 'change')
+
+ # balance out the changes
+ search.bfs_search(g, node, node_visitor2)
+ change[edge] = new_delta
+
+ # add up the total changes
+ total_change.a += change.a
+
+ if plot:
+ ## Plot total changes
+ g.ep.change.a[:] = total_change.a
+ flowmodeltestdata.plot_amounts(g,f'plastic_deltas_{i}.png', 'change')
+
+ node = reverse_graph(g, node_visitor, node_visitor2, edge)
+
+ if upstream:
+ if node.in_degree():
+ sum_f = node.in_degree(weight=total_change)
+ new_delta = delta - sum_f
+ else:
+ new_delta = 0
+ else:
+ if node.out_degree():
+ sum_f = node.out_degree(weight=total_change)
+ new_delta = delta - sum_f
+ else:
+ new_delta = 0
+ i += 1
+
+
+ while i < MAX_ITERATIONS and abs(new_delta) > 0.00001:
+ change.a[:] = 0
+ change[edge] = new_delta
+
+ # start in one direction
+
+ search.bfs_search(g, node, node_visitor)
+ change[edge] = 0
+
+ if plot:
+ ## Plot changes after forward run
+ g.ep.change.a[:] = change.a
+ flowmodeltestdata.plot_amounts(g,'plastic_deltas.png', 'change')
+
+
+ # now go downstream, if we started upstream
+ # (or upstream, if we started downstream)
+ node = reverse_graph(g, node_visitor, node_visitor2, edge)
+ if upstream:
+ sum_f = node.out_degree(weight=total_change) + \
+ node.out_degree(weight=change)
+ else:
+ sum_f = node.in_degree(weight=total_change) + \
+ node.in_degree(weight=change)
+ new_delta = delta - sum_f
+ change[edge] = new_delta
+ search.bfs_search(g, node, node_visitor)
+
+
+ if plot:
+ ## Plot changes after backward run
+ g.ep.change.a[:] = change.a
+ flowmodeltestdata.plot_amounts(g,'plastic_deltas.png', 'change')
+
+ # balance out the changes
+ search.bfs_search(g, node, node_visitor2)
+ change[edge] = 0
+
+ if plot:
+ ## Plot changes after balancing
+ g.ep.change.a[:] = change.a
+ flowmodeltestdata.plot_amounts(g,'plastic_deltas.png', 'change')
+
+ # add up the total changes
+ total_change.a += change.a
+
+ node = reverse_graph(g, node_visitor, node_visitor2, edge)
+
+ if plot:
+ ## Plot total changes
+ g.ep.change.a[:] = total_change.a
+ flowmodeltestdata.plot_amounts(g,f'plastic_deltas_{i}.png', 'change')
+
+ if upstream:
+ if node.in_degree():
+ sum_f = node.in_degree(weight=total_change)
+ new_delta = delta - sum_f
+ else:
+ new_delta = 0
+ else:
+ if node.out_degree():
+ sum_f = node.out_degree(weight=total_change)
+ new_delta = delta - sum_f
+ else:
+ new_delta = 0
+ i += 1
# finally clean up
- del visited
g.set_reversed(False)
g.clear_filters()
- return node_visitor.change
+ return total_change
+
+
+def reverse_graph(g, node_visitor: NodeVisitor, node_visitor2, edge):
+ g.set_reversed(not g.is_reversed())
+ node_visitor.balance_factor = 1 / node_visitor.balance_factor
+ node = edge.target() if not g.is_reversed() else edge.source()
+ node_visitor.forward = not node_visitor.forward
+ node_visitor2.balance_factor = 1 / node_visitor2.balance_factor
+ return node
class GraphWalker:
diff --git a/repair/apps/asmfa/tests/flowmodeltestdata.py b/repair/apps/asmfa/tests/flowmodeltestdata.py
index 127b6019f..9ce2c87ff 100644
--- a/repair/apps/asmfa/tests/flowmodeltestdata.py
+++ b/repair/apps/asmfa/tests/flowmodeltestdata.py
@@ -106,8 +106,7 @@ def plastic_package_graph():
G.vp.id[10] = 'Stock 2'
G.vp.id[11] = 'Waste 2'
flow = G.new_edge_property("object")
- eid = G.new_edge_property(
- "int") # need a persistent edge id, because graph-tool can reindex the edges
+ eid = G.new_edge_property("int") # need a persistent edge id, because graph-tool can reindex the edges
G.edge_properties["flow"] = flow
G.edge_properties["eid"] = eid
e = G.add_edge(G.vertex(0), G.vertex(1))
@@ -153,12 +152,23 @@ def plastic_package_graph():
return split
-def plot_amounts(g, file=None):
- """Plots the graph with the 'amount' property on the edges into a file"""
+def plot_amounts(g, file=None, prop='amount'):
+ """
+ Plots the graph with the property defined by `prop`
+ on the edges into a file
+
+ Parameters
+ ----------
+ g : graph_tool.Graph
+ file : str
+ prop : str, optional (default='amount')
+
+ """
+ quantities = g.ep[prop]
vertex_ids = [f'{int(v)}' for v in g.vertices()]
vertex_text = g.new_vertex_property("string", vals=vertex_ids)
mass_text = g.new_edge_property("string",
- vals=[str(round(i, 2))for i in g.ep.amount])
+ vals=[str(round(i, 3)) for i in quantities])
gt.draw.graph_draw(g, vertex_size=20, vertex_text=vertex_text,
vprops={"text_position": -1,
"font_size": 10},
diff --git a/repair/apps/asmfa/tests/test_graph.py b/repair/apps/asmfa/tests/test_graph.py
index 6da888492..f83e29c22 100644
--- a/repair/apps/asmfa/tests/test_graph.py
+++ b/repair/apps/asmfa/tests/test_graph.py
@@ -75,7 +75,6 @@ def test_plastic_packaging(self):
Consumption --> Recycling -0.12
Recycling --> Production -0.06
"""
- return
plastic = flowmodeltestdata.plastic_package_graph()
gw = GraphWalker(plastic)
change = gw.graph.new_edge_property('float')
@@ -100,47 +99,86 @@ def test_plastic_packaging(self):
else:
gw.graph.ep.include[e] = False
result = gw.calculate(implementation_edges, deltas)
+
+ # for each flow, test if the results are approximately
+ # the expected value, taking some delta due to the balancing
+ # into account
for i, e in enumerate(result.edges()):
- print(f"{result.vp.id[e.source()]} --> {result.vp.id[e.target()]} / {result.ep.material[e]}: {result.ep.amount[e]}")
+ print(f"{result.vp.id[e.source()]} --> {result.vp.id[e.target()]} "
+ f"/ {result.ep.material[e]}: {result.ep.amount[e]}")
if result.vp.id[e.source()] == 'Packaging' \
and result.vp.id[e.target()] == 'Consumption' \
and result.ep.material[e] == 'plastic':
expected = 5.0 - 0.3
- self.assertAlmostEqual(result.ep.amount[e], expected, 2, 'Packaging->Consumption')
+ self.assertAlmostEqual(
+ result.ep.amount[e], expected, delta=0.2,
+ msg='Packaging->Consumption')
elif result.vp.id[e.source()] == 'Oil rig' \
and result.vp.id[e.target()] == 'Oil refinery' \
and result.ep.material[e] == 'crude oil':
expected = 20.0 - 0.3
- self.assertAlmostEqual(result.ep.amount[e], expected, 2, 'Oil rig->Oil refinery')
+ self.assertAlmostEqual(
+ result.ep.amount[e], expected, delta=0.2,
+ msg='Oil rig->Oil refinery')
elif result.vp.id[e.source()] == 'Oil refinery' \
and result.vp.id[e.target()] == 'Production' \
and result.ep.material[e] == 'plastic':
expected = 4.0 - 0.24
- self.assertAlmostEqual(result.ep.amount[e], expected, 2, 'Oil refinery->Production')
+ self.assertAlmostEqual(
+ result.ep.amount[e], expected, delta=0.2,
+ msg='Oil refinery->Production')
elif result.vp.id[e.source()] == 'Production' \
and result.vp.id[e.target()] == 'Packaging' \
and result.ep.material[e] == 'plastic':
expected = 5.0 - 0.3
- self.assertAlmostEqual(result.ep.amount[e], expected, 2, 'Production->Packaging')
+ self.assertAlmostEqual(
+ result.ep.amount[e], expected, delta=0.2,
+ msg='Production->Packaging')
elif result.vp.id[e.source()] == 'Consumption' \
and result.vp.id[e.target()] == 'Burn' \
and result.ep.material[e] == 'plastic':
expected = 3.0 - 0.18
- self.assertAlmostEqual(result.ep.amount[e], expected, 2, 'Consumption->Burn')
+ self.assertAlmostEqual(
+ result.ep.amount[e], expected, delta=0.1,
+ msg='Consumption->Burn')
elif result.vp.id[e.source()] == 'Consumption' \
and result.vp.id[e.target()] == 'Recycling' \
and result.ep.material[e] == 'plastic':
expected = 2.0 - 0.12
- self.assertAlmostEqual(result.ep.amount[e], expected, 2, 'Consumption->Recycling')
+ self.assertAlmostEqual(
+ result.ep.amount[e], expected, delta=0.1,
+ msg='Consumption->Recycling')
elif result.vp.id[e.source()] == 'Recycling' \
and result.vp.id[e.target()] == 'Production' \
and result.ep.material[e] == 'plastic':
expected = 1.0 - 0.06
- self.assertAlmostEqual(result.ep.amount[e], expected, 2, 'Recycling->Production')
+ self.assertAlmostEqual(
+ result.ep.amount[e], expected, delta=0.06,
+ msg='Recycling->Production')
else:
self.assertAlmostEqual(result.ep.amount[e],
- gw.graph.ep.amount[e], places=2)
-
+ gw.graph.ep.amount[e],
+ delta=result.ep.amount[e]/10)
+
+ # test if the changes in all nodes are balanced
+ result.ep.change.a = result.ep.amount.a - gw.graph.ep.amount.a
+
+ for u in result.vertices():
+ # dangling nodes with no in- or outflows can be ignored
+ if not (u.in_degree() and u.out_degree()):
+ continue
+ # for the rest, the sum of the in-deltas should equal to the
+ # sum of the out-deltas, adjusted with the balancing factor
+ sum_in_deltas = u.in_degree(result.ep.change)
+ sum_out_deltas = u.out_degree(result.ep.change)
+ balanced_out_deltas = sum_out_deltas / bf[u]
+ balanced_delta = sum_in_deltas - balanced_out_deltas
+ self.assertAlmostEqual(
+ balanced_delta, 0, places=4,
+ msg=f'Node {int(u)} not balanced, deltas in: {sum_in_deltas}, '
+ f'deltas out: {sum_out_deltas}, bf: {bf[u]}, '
+ f'balanced deltas out: {balanced_out_deltas}'
+ )
def test_milk_production(self):
"""Reduce milk production between Farm->Packaging
@@ -1251,6 +1289,7 @@ def affect_biofuel_chain(solpart):
strat_digest_factor = strat_out_digester_sum / strat_in_digester_sum
self.assertAlmostEqual(sq_digest_factor, strat_digest_factor,
+ places=1,
msg=f'the factor at actor {biodigester} in '
'strategy is not the same as in status quo')
@@ -1281,7 +1320,7 @@ def assert_balance_factor(activity):
sf_out = out_flows.aggregate(amount=Sum('strategy_amount'))['amount']
sq_factor = (sq_out / sq_in) if sq_out and sq_in else 1
sf_factor = (sf_out / sf_in) if sf_out and sf_in else 1
- self.assertAlmostEqual(sq_factor, sf_factor,
+ self.assertAlmostEqual(sq_factor, sf_factor, 1,
msg='the balance factor at actor '
f'{actor} in strategy is not the '
'same as in status quo')
diff --git a/repair/apps/statusquo/views/computation.py b/repair/apps/statusquo/views/computation.py
index 3f4a3e7ab..006898d3a 100644
--- a/repair/apps/statusquo/views/computation.py
+++ b/repair/apps/statusquo/views/computation.py
@@ -49,7 +49,8 @@ def get_queryset(self, indicator_flow, geom=None):
hazardous = indicator_flow.hazardous.name
avoidable = indicator_flow.avoidable.name
- flows = get_annotated_fractionflows(self.keyflow_pk, strategy=self.strategy)
+ flows = get_annotated_fractionflows(self.keyflow_pk,
+ strategy_id=self.strategy.id)
# filter flows by type (waste/product/both)
if flow_type != 'BOTH':
diff --git a/repair/js/views/common/baseview.js b/repair/js/views/common/baseview.js
index 661242bc8..77a721dfb 100644
--- a/repair/js/views/common/baseview.js
+++ b/repair/js/views/common/baseview.js
@@ -50,8 +50,13 @@ var BaseView = Backbone.View.extend(
},
/** format a number to currently set language **/
- format: function(value){
- return value.toLocaleString(this.language);
+ format: function(value, forceSignum){
+ var formatted = value.toLocaleString(this.language);
+ if (this.forceSignum){
+ if (value > 0) formatted = '+' + formatted;
+ if (value == 0) formatted = '+-0';
+ }
+ return formatted;
},
/**
diff --git a/repair/js/views/common/filter-flows.js b/repair/js/views/common/filter-flows.js
index 226d4d33e..e60ce998e 100644
--- a/repair/js/views/common/filter-flows.js
+++ b/repair/js/views/common/filter-flows.js
@@ -179,6 +179,7 @@ var FilterFlowsView = BaseView.extend(
displayWarnings: true,
filter: filter
});
+ this.flowsView.loader = this.loader;
var displayLevel = this.displayLevelSelect.value;
this.flowsView.draw(displayLevel);
},
diff --git a/repair/js/views/common/flows.js b/repair/js/views/common/flows.js
index 871814b48..02e276ad2 100644
--- a/repair/js/views/common/flows.js
+++ b/repair/js/views/common/flows.js
@@ -229,7 +229,6 @@ var FlowsView = BaseView.extend(
apiTag: 'flows',
apiIds: [ this.caseStudy.id, this.keyflowId]
});
-
this.loader.activate();
var data = {};
if (options.strategy)
diff --git a/repair/js/views/common/flowsankey.js b/repair/js/views/common/flowsankey.js
index bdf0eb74e..2ca0f4473 100644
--- a/repair/js/views/common/flowsankey.js
+++ b/repair/js/views/common/flowsankey.js
@@ -108,7 +108,8 @@ var FlowSankeyView = BaseView.extend(
selectable: true,
gradient: false,
stretchFactor: (this.stretchInput) ? this.stretchInput.value: 1,
- selectOnDoubleClick: (dblclkCheck) ? dblclkCheck.checked : false
+ selectOnDoubleClick: (dblclkCheck) ? dblclkCheck.checked : false,
+ forceSignum: this.forceSignum
})
// redirect the event with same properties
@@ -213,14 +214,12 @@ var FlowSankeyView = BaseView.extend(
fractions.forEach(function(material){
var amount = (material.value != null) ? material.value: material.amount;
if (amount == 0) return;
- if (_this.forceSignum && amount >= 0)
- text += '+';
if (_this.showRelativeComposition){
fraction = amount / totalAmount,
value = Math.round(fraction * 100000) / 1000;
- text += _this.format(value) + '%';
+ text += _this.format(value, _this.forceSignum) + '%';
} else {
- text += _this.format(amount) + ' ' + gettext('t/year');
+ text += _this.format(amount, _this.forceSignum) + ' ' + gettext('t/year');
}
text += ' ' + material.name
if (material.avoidable) text += ' ' + gettext('avoidable') +'';
@@ -263,9 +262,6 @@ var FlowSankeyView = BaseView.extend(
var crepr = compositionRepr(flow),
amount = flow.get('amount'),
value = (norm === 'log')? normalize(amount): Math.round(amount);
-
- if (_this.forceSignum && amount >= 0)
- amount = '+' + amount.toLocaleString(this.language);
links.push({
id: flow.id,
originalData: flow,
@@ -323,7 +319,7 @@ var FlowSankeyView = BaseView.extend(
var header = [gettext('origin'), gettext('origin') + '_code', gettext('origin') + '_wkt',
gettext('destination'), gettext('destination') + '_code', gettext('destination') + '_wkt',
- gettext('amount'), gettext('composition')],
+ gettext('amount (t/year)'), gettext('composition')],
rows = [],
_this = this;
rows.push(header.join('\t'));
@@ -340,11 +336,9 @@ var FlowSankeyView = BaseView.extend(
destination = link.target,
originName = origin.name,
destinationName = (!link.isStock) ? destination.name : gettext('Stock'),
- amount = _this.format(link.amount) + ' ' + link.units,
+ amount = _this.format(link.amount, _this.forceSignum),
composition = link.composition;
- if (_this.forceSignum && amount >= 0)
- amount = '-' + amount;
var originCode = origin.code,
destinationCode = (destination) ? destination.code: '',
originWkt = '',
diff --git a/repair/js/views/data-entry/actors-flows.js b/repair/js/views/data-entry/actors-flows.js
index 75479a64a..176ad3eed 100644
--- a/repair/js/views/data-entry/actors-flows.js
+++ b/repair/js/views/data-entry/actors-flows.js
@@ -191,6 +191,9 @@ var FlowsEditView = BaseView.extend(
plugins: ["wholerow", "ui", "types", "themes"]
});
$(this.dataTree).on("select_node.jstree", this.nodeSelected);
+ $(this.dataTree).bind("hover_node.jstree", function (e, data) {
+ $("#" + data.node.id).prop('title', data.node.text);
+ })
this.filterSelect = this.el.querySelector('#included-filter-select');
this.actorsTable = $('#actors-table').DataTable();
$('#actors-table tbody').on('click', 'tr', function () {
diff --git a/repair/js/views/status-quo/workshop-flows.js b/repair/js/views/status-quo/workshop-flows.js
index c882333d8..65ac7158c 100644
--- a/repair/js/views/status-quo/workshop-flows.js
+++ b/repair/js/views/status-quo/workshop-flows.js
@@ -95,6 +95,7 @@ var FlowsWorkshopView = BaseView.extend(
materials: this.materials,
filter: filter
});
+ this.flowsView.loader = this.loader;
this.draw();
},
diff --git a/repair/js/views/strategy/modified-flows.js b/repair/js/views/strategy/modified-flows.js
index 4c273ce5a..7c1393625 100644
--- a/repair/js/views/strategy/modified-flows.js
+++ b/repair/js/views/strategy/modified-flows.js
@@ -118,6 +118,7 @@ var ModifiedFlowsView = BaseView.extend(
filter: filter,
strategy: this.strategy
});
+ this.flowsView.loader = this.loader;
this.draw();
},
diff --git a/repair/js/visualizations/sankey.js b/repair/js/visualizations/sankey.js
index b60fdd332..ab52f7236 100644
--- a/repair/js/visualizations/sankey.js
+++ b/repair/js/visualizations/sankey.js
@@ -39,12 +39,18 @@ class Sankey{
.size([this.width * this.stretchFactor, this.height])
.align(alignment);
this.selectable = options.selectable;
+ this.forceSignum = options.forceSignum;
this.gradient = options.gradient;
this.selectOnDoubleClick = options.selectOnDoubleClick || false;
}
format(d) {
- return d.toLocaleString(this.language);
+ var formatted = d.toLocaleString(this.language);
+ if (this.forceSignum){
+ if (d > 0) formatted = '+' + formatted;
+ if (d == 0) formatted = '+-0';
+ }
+ return formatted;
}
align(alignment){
@@ -175,6 +181,7 @@ class Sankey{
outSum += parseInt(link.amount || link.value);
if (!outUnits) outUnits = link.units;
}
+
var ins = "in: " + _this.format(inSum) + " " + (inUnits || ""),
out = "out: " + _this.format(outSum) + " " + (outUnits || "");
var text = (d.text) ? d.text + '
': '';
diff --git a/repair/templates/common.html b/repair/templates/common.html
index aacd463c0..8db4099fa 100644
--- a/repair/templates/common.html
+++ b/repair/templates/common.html
@@ -4,8 +4,8 @@