1. Chris Mutel
  2. brightway2-ui

Commits

Chris Mutel  committed cf0db1e

0.5: LCA calculations now triggered asynchronously. Reports can be viewed anytime.

  • Participants
  • Parent commits be9b7a9
  • Branches default

Comments (0)

Files changed (8)

File bw2ui/web/app.py

View file
  • Ignore whitespace
 from __future__ import division
 from brightway2 import config, databases, methods, Database, Method, \
     JsonWrapper, reset_meta
-from bw2analyzer import ContributionAnalysis, DatabaseExplorer
+from bw2analyzer import ContributionAnalysis, DatabaseExplorer, \
+    SerializedLCAReport
 from bw2calc import LCA, ParallelMonteCarlo
 from bw2calc.speed_test import SpeedTest
 from bw2data.io import EcospoldImporter, EcospoldImpactAssessmentImporter
                 request.form["activity"])
             ])
         method = tuple(JsonWrapper.loads(request.form["method"]))
-        context = {}
-        lca = LCA(fu, method)
-        lca.lci()
-        lca.lcia()
-        rt, rb = lca.reverse_dict()
-        ca = ContributionAnalysis()
-        # Monte Carlo
-        iterations = 10000
-        mc = np.array(ParallelMonteCarlo(fu, method, iterations=iterations
-            ).calculate())
-        mc.sort()
-        # Filter out the outliers
-        one_percent = int(0.01 * iterations)
-        mc = mc[one_percent:-one_percent]
-        mc_data = [(float(x), float(y)) for x, y in zip(*np.histogram(
-            mc, bins=max(100, min(20, int(math.sqrt(iterations))))))]
-        context.update({
-            "mc_median": float(np.median(mc)),
-            "mc_mean": float(np.average(mc)),
-            "mc_lower": float(mc[int(0.025 * iterations)]),
-            "mc_upper": float(mc[int(0.975 * iterations)]),
-            "mc_data": JsonWrapper.dumps(mc_data),
-            "herfindahl": ca.herfindahl_index(
-                lca.characterized_inventory.data, lca.score),
-            "concentration_ratio": ca.concentration_ratio(
-                lca.characterized_inventory.data, lca.score),
-            "hinton_data": JsonWrapper.dumps(ca.hinton_matrix(lca)),
-            "treemap_data": JsonWrapper.dumps(ca.d3_treemap(
-                lca.characterized_inventory.data, rb, rt)),
-            "ia_score": float(lca.score),
-            "ia_unit": methods[method]["unit"],
-            "ia_method": ": ".join(method),
-            "fu": [(ca.get_name(k), "%.2g" % v, ca.db_names[k[0]][k][
-                "unit"]) for k, v in fu.iteritems()],
-            })
-        return render_template("lca.html", **context)
+        iterations = config.p.get("iterations", 10000)
+        cpu_count = config.p.get("cpu_cores", None)
+        report = SerializedLCAReport(fu, method, iterations, cpu_count)
+        report.calculate()
+        report.write()
+        # TODO: upload?
+        return report.uuid
+
+
+@app.route('/report/<uuid>')
+def report(uuid):
+    data = open(os.path.join(
+        config.dir, "reports", "report.%s.json" % uuid)).read()
+    return render_template("report.html", data=data)
 
 
 #############

File bw2ui/web/static/css/base.css

View file
  • Ignore whitespace
     fill: none;
 }
 
+.isline {
+    stroke: forestgreen;
+    stroke-width: 2;
+    fill: none;
+}
+
 .indicator {
     stroke: red;
     stroke-width: 1;

File bw2ui/web/static/js/stepped-histogram.js

View file
  • Ignore whitespace
+var stepped_histogram = function (data, xlabel, id, w, h, padding) {
+  var y_max = d3.max(data.histogram, function (d) { return d[1]; }),
+    x_max = d3.max(data.histogram, function (d) { return d[0]; }),
+    x_min = d3.min(data.histogram, function (d) { return d[0]; }),
+    median = data.statistics.median,
+    upper = data.statistics.interval[0],
+    lower = data.statistics.interval[1];
+
+  var y = d3.scale.linear()
+    .range([h - padding, padding])
+    .domain([0, y_max * 1.1])
+    .nice();
+
+  var y_axis = d3.svg.axis()
+    .scale(y)
+    .ticks(4)
+    .orient("left");
+
+  var x = d3.scale.linear()
+    .range([padding, w - padding])
+    .domain([x_min, x_max])
+    .nice();
+
+  var x_axis = d3.svg.axis()
+    .scale(x)
+    .ticks(6)
+    .orient("bottom");
+
+  var svg = d3.select(id)
+    .append("svg")
+    .attr("width",w)
+    .attr("height",h);
+
+  var line = d3.svg.line()
+    .x(function(d) { return x(d[0]); })
+    .y(function(d) { return y(d[1]); })
+    .interpolate("linear");
+
+  var histogram_g = svg.append("svg:g")
+    .append("svg:path")
+    .attr("class", "ihline")
+    .attr("d", line(data.histogram));
+
+  var smooth_g = svg.append("svg:g")
+    .append("svg:path")
+    .attr("class", "isline")
+    .attr("d", line(data.smoothed));
+
+  var indicator_line = d3.svg.line()
+    .x(function(d) { return x(d[0]); })
+    .y(function(d) { return y(d[1]); });
+  
+  svg.append("svg:g")
+    .append("svg:path")
+    .attr("class", "indicator")
+    .attr("d", indicator_line([[median, 0], [median, y_max * 1.05]]));
+
+  svg.append("text")
+    .attr("class", "label")
+    .attr("text-anchor", "middle")
+    .attr("x", x(median))
+    .attr("y", y(y_max * 1.05) - 5)
+    .text("Median");
+
+  svg.append("svg:g")
+      .append("svg:path")
+      .attr("class", "indicator")
+      .attr("d", indicator_line([[lower, 0], [lower, y_max * 0.95]]));
+
+  svg.append("text")
+    .attr("class", "label")
+    .attr("text-anchor", "middle")
+    .attr("x", x(lower))
+    .attr("y", y(y_max * 0.95) - 5 )
+    .text("95% lower");
+
+  svg.append("svg:g")
+      .append("svg:path")
+      .attr("class", "indicator")
+      .attr("d", indicator_line([[upper, 0], [upper, y_max * 0.95]]));
+
+  svg.append("text")
+    .attr("class", "x label")
+    .attr("text-anchor", "middle")
+    .attr("x", x(upper))
+    .attr("y", y(y_max * 0.95) - 5 )
+    .text("95% upper");
+
+  svg.append("svg:g")
+    .attr("class", "x axis")
+    .attr("transform", "translate(0," + (h - padding + 2) + ")")
+    .call(x_axis);
+
+  svg.append("svg:g")
+   .attr("class", "y axis")
+   .call(y_axis);
+
+  svg.append("text")
+    .attr("class", "y label")
+    .attr("text-anchor", "end")
+    .attr("transform", "rotate(-90)")
+    .attr("y", padding)
+    .attr("x", padding)
+    .attr("dy", ".5em")
+    .text("Count");
+
+  svg.append("text")
+    .attr("class", "x label")
+    .attr("text-anchor", "end")
+    .attr("x", w)
+    .attr("y", h - padding - 5)
+    .text(xlabel);
+}

File bw2ui/web/templates/import-database.html

View file
  • Ignore whitespace
   $('form[name=path-form]').submit( function (e) {
     e.preventDefault();
     if (($("#dir-file").val() != '') && ($("#hidden-path").val() != '')) {
-      console.log("ready");
-      console.log($(this).serialize());
       $("#in-submission").show();
       $("#select-path").hide();
       $.ajax({

File bw2ui/web/templates/lca.html

  • Ignore whitespace
-{% extends "base.html" %}
-
-{% block extrahead %}
-<style type="text/css">
-.cell {
-  border: solid 1px white;
-  font: 10px sans-serif;
-  line-height: 12px;
-  overflow: hidden;
-  position: absolute;
-  text-indent: 2px;
-}
-</style>
-<script src="{{ url_for('static', filename="js/hinton.js") }}"></script>
-<script src="{{ url_for('static', filename="js/interp-histogram.js") }}"></script>
-<script src="{{ url_for('static', filename="js/hinton.js") }}"></script>
-{% endblock %}
-
-{% block body %}
-<div class="span-15 colborder">
-	<h2 style="margin-bottom: 0">Functional unit:</h2>
-	<ul style="margin-bottom: 0">
-		{% for name, amount, unit in fu %}
-		<li class="large" style="margin-bottom: 0; line-height: 1.2em">{{ name }}: {{ amount }} {{ unit }}</li>
-		{% endfor %}
-	</ul>
-	<h2 style="margin-bottom: 0">Impact assessment method:</h2>
-	<p class="large" style="margin-bottom: 0; line-height: 1.2em">{{ ia_method }}</p>
-</div>
-<div class="span-8 last">
-	<h2>Total score:</h2>
-	<p class="large"><span style="font-size: 2.5em; color:#000">{{ '%.2g' % ia_score }}</span> {{ ia_unit }}</p>
-</div>
-<hr>
-<h1 style="margin-bottom: 0">Monte Carlo results</h1>
-<div class="span-7">
-	<h2 style="margin-bottom: 0">Median</h2>
-	<p class="large"><span style="font-size: 2.5em; color:#000">{{ '%.2g' % mc_median }}</span> {{ ia_unit }}</p>
-	<h2 style="margin-bottom: 0">Average</h2>
-	<p class="large"><span style="font-size: 2.5em; color:#000">{{ '%.2g' % mc_mean }}</span> {{ ia_unit }}</p>
-	<h2 style="margin-bottom: 0">95% interval</h2>
-	<p class="large"><span style="font-size: 2.5em; color:#000">{{ '%.2g' % mc_lower }} - {{ '%.2g' % mc_upper }}</span> {{ ia_unit }}</p>
-</div>
-<div class="span-17 last" id="ihist"></div>
-<hr>
-<div class="span-24" id="treemap"></div>
-<hr>
-<div class="span-14" id="hinton"></div>
-<div class="span-10 last">
-	<h2 style="margin-bottom: 0"><a href="http://en.wikipedia.org/wiki/Concentration_ratio">Concentration index</a></h2>
-	<p class="large" style="font-size: 2.5em; color:#000; margin-bottom: 0">{{ '%.2g' % concentration_ratio }}</p>
-	<h2 style="margin-bottom: 0"><a href="http://en.wikipedia.org/wiki/Herfindahl_index">Herfindahl index</a></h2>
-	<p class="large" style="font-size: 2.5em; color:#000; margin-bottom: 0">{{ '%.2g' % herfindahl }}</p>
-</div>
-
-<script type="text/javascript">
-var hinton_data = {{ hinton_data|safe }};
-hinton_matrix(hinton_data.results, hinton_data.total, hinton_data.xlabels, hinton_data.ylabels, "#hinton", 560, 560, 10);
-
-var mc_data = {{ mc_data|safe }};
-interpolated_histogram(mc_data, "{{ ia_unit }}", {{ mc_median }}, {{ mc_upper }}, {{ mc_lower }}, "#ihist", 680, 300, 10);
-
-var width = 950,
-    height = 200,
-    color = d3.scale.category20();
-
-var treemap = d3.layout.treemap()
-    .size([width, height])
-    .value(function(d) { return d.size; });
-
-var div = d3.select("#treemap").append("div")
-    .style("position", "relative")
-    .style("width", width + "px")
-    .style("height", height + "px");
-
-var treemap_data = {{ treemap_data|safe }};
-
-var cell_color_scale = d3.scale.category20();
-
-div.data([treemap_data]).selectAll("div")
-  .data(treemap.nodes)
-.enter().append("div")
-  .attr("class", "cell")
-  .attr("title", function(d) { return d.children ? null : d.name; })
-  .style("font-size", "14px")
-  .style("background", function(d, i) { return cell_color_scale(i % 20); }) // d.children ? color(d.name) : null; })
-  .call(cell)
-  .text(function(d) { return d.children ? null : d.name; });
-
-function cell() {
-  this
-      .style("left", function(d) { return d.x + "px"; })
-      .style("top", function(d) { return d.y + "px"; })
-      .style("width", function(d) { return Math.max(0, d.dx - 1) + "px"; })
-      .style("height", function(d) { return Math.max(0, d.dy - 1) + "px"; });
-}
-</script>
-{% endblock %}

File bw2ui/web/templates/report.html

View file
  • Ignore whitespace
+{% extends "base.html" %}
+
+{% block extrahead %}
+<style type="text/css">
+.cell {
+  border: solid 1px white;
+  font: 10px sans-serif;
+  line-height: 12px;
+  overflow: hidden;
+  position: absolute;
+  text-indent: 2px;
+}
+</style>
+<script src="{{ url_for('static', filename="js/hinton.js") }}"></script>
+<script src="{{ url_for('static', filename="js/stepped-histogram.js") }}"></script>
+<script src="{{ url_for('static', filename="js/hinton.js") }}"></script>
+{% endblock %}
+
+{% block body %}
+<div class="span-15 colborder">
+	<h2 style="margin-bottom: 0">Functional unit:</h2>
+	<ul style="margin-bottom: 0" id="activity"></ul>
+	<h2 style="margin-bottom: 0">Impact assessment method:</h2>
+	<p class="large" style="margin-bottom: 0; line-height: 1.2em" id="method-name"></p>
+</div>
+<div class="span-8 last">
+	<h2>Total score:</h2>
+	<p class="large"><span style="font-size: 2.5em; color:#000" id="ia-score"></span> <span class="ia-unit"></span></p>
+</div>
+<hr>
+<h1 style="margin-bottom: 0">Monte Carlo results</h1>
+<div class="span-7">
+	<h2 style="margin-bottom: 0">Median</h2>
+	<p class="large"><span style="font-size: 2.5em; color:#000" id="mc-median"></span> <span class="ia-unit"></span></p>
+	<h2 style="margin-bottom: 0">Average</h2>
+	<p class="large"><span style="font-size: 2.5em; color:#000" id="mc-mean"></span> <span class="ia-unit"></span></p>
+	<h2 style="margin-bottom: 0">95% density interval</h2>
+	<p class="large"><span style="font-size: 2.5em; color:#000"> <span id="mc-lower"></span>:<span id="mc-upper"></span></span> <span class="ia-unit"></span></p>
+</div>
+<div class="span-17 last" id="ihist"></div>
+<hr>
+<div class="span-24" id="treemap"></div>
+<hr>
+<div class="span-14" id="hinton"></div>
+<div class="span-10 last">
+	<h2 style="margin-bottom: 0"><a href="http://en.wikipedia.org/wiki/Concentration_ratio">Concentration index</a></h2>
+	<p class="large" style="font-size: 2.5em; color:#000; margin-bottom: 0" id="concentration-ratio"></p>
+	<h2 style="margin-bottom: 0"><a href="http://en.wikipedia.org/wiki/Herfindahl_index">Herfindahl index</a></h2>
+	<p class="large" style="font-size: 2.5em; color:#000; margin-bottom: 0" id="herfindahl"></p>
+</div>
+
+<script type="text/javascript">
+$(document).ready( function() {  
+  var report_data = {{ data|safe }},
+    activity = "";  
+
+  // Replace DOM elements with correct content
+  $('#herfindahl').html(report_data.contribution.herfindahl.toPrecision(2));
+  $('#concentration-ratio').html(report_data.contribution.concentration.toPrecision(2));
+  $('.ia-unit').html(report_data.method.unit);
+  $('#method-name').html(report_data.method.name);
+  $('#ia-score').html(report_data.score.toPrecision(2));
+  $('#mc-median').html(report_data["monte carlo"].statistics.median.toPrecision(2));
+  $('#mc-mean').html(report_data["monte carlo"].statistics.mean.toPrecision(2));
+  $('#mc-lower').html(report_data["monte carlo"].statistics.interval[0].toPrecision(2));
+  $('#mc-upper').html(report_data["monte carlo"].statistics.interval[1].toPrecision(2));
+  for (var i = report_data.activity.length - 1; i >= 0; i--) {
+    activity = activity + "<li class=&quotlarge&quot style=&quotmargin-bottom: 0; line-height: 1.1em&quot>" + report_data.activity[i][0] + ": " + report_data.activity[i][1] + " " + report_data.activity[i][2] + "</li>"
+  };
+  $('#activity').html(activity);
+
+  // Insert graphics
+  hinton_matrix(report_data.contribution.hinton.results, report_data.contribution.hinton.total, report_data.contribution.hinton.xlabels, report_data.contribution.hinton.ylabels, "#hinton", 560, 560, 10);
+  stepped_histogram(report_data["monte carlo"], report_data.method.unit, "#ihist", 680, 300, 10);
+
+  var width = 950,
+      height = 200,
+      color = d3.scale.category20();
+
+  var treemap = d3.layout.treemap()
+      .size([width, height])
+      .value(function(d) { return d.size; });
+
+  var div = d3.select("#treemap").append("div")
+      .style("position", "relative")
+      .style("width", width + "px")
+      .style("height", height + "px");
+
+  var cell_color_scale = d3.scale.category20();
+
+  div.data([report_data.contribution.treemap]).selectAll("div")
+    .data(treemap.nodes)
+  .enter().append("div")
+    .attr("class", "cell")
+    .attr("title", function(d) { return d.children ? null : d.name; })
+    .style("font-size", "14px")
+    .style("background", function(d, i) { return cell_color_scale(i % 20); }) // d.children ? color(d.name) : null; })
+    .call(cell)
+    .text(function(d) { return d.children ? null : d.name; });
+
+  function cell() {
+    this
+        .style("left", function(d) { return d.x + "px"; })
+        .style("top", function(d) { return d.y + "px"; })
+        .style("width", function(d) { return Math.max(0, d.dx - 1) + "px"; })
+        .style("height", function(d) { return Math.max(0, d.dy - 1) + "px"; });
+  }
+});
+</script>
+{% endblock %}

File bw2ui/web/templates/select.html

View file
  • Ignore whitespace
 {% extends "base.html" %}
 
+{% block extrahead %}
+<style>
+.ui-dialog-titlebar-close{
+    display: none;
+}
+</style>
+{% endblock %}
+
 {% block body %}
 <h1>Define the functional unit to assess</h1>
 <div class="span-7 colborder">
 </div>
 <hr>
 <div>
-    <form action="/lca" method="post">
+    <form action="/lca" method="post" name="calculate-form">
         <input type="hidden" name="activity" value="" id="hidden-activity">
         <input type="hidden" name="method" value="" id="hidden-method">
         <button type="submit">Calculate!</button>
     </form>
 </div>
+
+<div id="in-progress" title="Calculation in progress">The LCA calculation has been started. Please wait until it finishes, and you will be redirected to the report.</div>
+
 <script>
 $(document).ready(function() {
+    $("#in-progress").dialog({
+      height: 140,
+      modal: true,
+      autoOpen: false,
+      closeOnEscape: false
+    });
+
+    $('form[name=calculate-form]').submit( function (e) {
+        e.preventDefault();
+        $('#in-progress').dialog("open");
+        $.ajax({
+            type: "POST",
+            url: '{{ url_for('lca') }}',
+            data: $(this).serialize(),
+            success: function (a) {
+              document.location.href='/report/' + a;
+            }
+        });
+    });
+
     $("#activity-input").prop('disabled', true);
     $('#selected-activities').dataTable({
         "bJQueryUI": true

File setup.py

View file
  • Ignore whitespace
 
 setup(
   name='bw2ui',
-  version="0.4.6",
+  version="0.5",
   packages=["bw2ui", "bw2ui.web"],
   package_data={'bw2ui.web': [
     "static/blueprint/*.css",