Commits

Chris Mutel committed 358ef5e

Improved LCA results and added select test page

Comments (0)

Files changed (5)

 from brightway2 import config, databases, methods, Database, Method, \
     JsonWrapper
 from bw2analyzer import ContributionAnalysis, DatabaseExplorer
-from bw2calc import LCA
+from bw2calc import LCA, ParallelMonteCarlo
 from flask import Flask, url_for, render_template, request, redirect, abort
 from fuzzywuzzy import process
 from jobs import JobDispatch, InvalidJob
 from utils import get_job_id, get_job, set_job_status, json_response
 import itertools
+import numpy as np
 
 app = Flask(__name__)
 
     return render_template("index.html", **context)
 
 
+@app.route('/database/<name>/names')
+def activity_names(name):
+    if name not in databases:
+        return abort(404)
+    db = Database(name)
+    data = db.load()
+    return json_response([{
+        "label": u"%s (%s, %s)" % (
+            value["name"],
+            value.get("unit", "?"),
+            value.get("location", "?")),
+        "value": {
+            "u": value["unit"],
+            "l": value["location"],
+            "n": value["name"],
+            "k": key
+        }} for key, value in data.iteritems() if value["num_cfs"]])
+
+
+def get_tuple_index(t, i):
+    try:
+        return t[i]
+    except IndexError:
+        return "---"
+
+
+@app.route('/select')
+def process_selector():
+    return render_template("select.html",
+        db_names=[x for x in databases.list if x != "biosphere"],
+        lcia_methods=[{
+            "l1": get_tuple_index(key, 0),
+            "l2": get_tuple_index(key, 1),
+            "l3": get_tuple_index(key, 2),
+            "u": value["unit"],
+            "n": value["num_cfs"],
+            "k": key
+        } for key, value in methods.data.iteritems()])
+
+
 @app.route('/hinton')
 def hinton():
     return render_template("hinton.html")
         lca.lcia()
         rt, rb = lca.reverse_dict()
         ca = ContributionAnalysis()
-        context["treemap_data"] = JsonWrapper.dumps(ca.d3_treemap(
-            lca.characterized_inventory.data, rb, rt))
-        context["ia_score"] = "%.2g" % lca.score
-        context["ia_unit"] = methods[method]["unit"]
-        context["ia_method"] = ": ".join(method)
-        context["fu"] = [(ca.get_name(k), "%.2g" % v, ca.db_names[k[0]][k][
-            "unit"]) for k, v in fu.iteritems()]
+        # Monte Carlo
+        mc = np.array(ParallelMonteCarlo(fu, method, iterations=1000, chunk_size=150).calculate())
+        mc.sort()
+        mc_data = [(float(x), float(y)) for x, y in zip(*np.histogram(mc, bins=70))]
+        context.update({
+            "mc_median": float(np.median(mc)),
+            "mc_mean": float(np.average(mc)),
+            "mc_lower": float(mc[125]),
+            "mc_upper": float(mc[-125]),
+            "mc_data": JsonWrapper.dumps(mc_data),
+            "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)
 
 

bw2ui/web/static/css/base.css

     font-family: 'Source Sans Pro', sans-serif;
 }
 
-brightway {
+#brightway {
     color: dimgray;
     font-weight: normal;
 }
 
-two {
+#two {
     color: cornflowerblue;
     font-weight: normal;
 }
     stroke-width: 1;
     shape-rendering: crispEdges;
 }
+
+svg { 
+  padding-top: 10px;
+  padding-bottom: 10px;
+}

bw2ui/web/static/js/interp-histogram.js

   svg.append("svg:g")
       .append("svg:path")
       .attr("class", "indicator")
-      .attr("d", indicator_line([[lower, 0], [lower, y_max * 0.2]]));
+      .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.2) - 5 )
+    .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.4]]));
+      .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.4) - 5 )
+    .attr("y", y(y_max * 0.95) - 5 )
     .text("95% upper");
 
   svg.append("svg:g")

bw2ui/web/templates/lca.html

   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>
 {% endblock %}
 
 {% block body %}
 </div>
 <div class="span-8 last">
 	<h2>Total score:</h2>
-	<p class="large"><span style="font-size: 2.5em; color:#000">{{ ia_score }}</span> {{ ia_unit }}</p>
+	<p class="large"><span style="font-size: 2.5em; color:#000">{{ '%.2g' % ia_score }}</span> {{ ia_unit }}</p>
 </div>
 <hr>
-<div id="chart"></div>
+<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 id="treemap"></div>
+<script type="text/javascript">
+var data = {{ mc_data|safe}};
+
+interpolated_histogram(data, "{{ ia_unit }}", {{ mc_median }}, {{ mc_lower }}, {{ mc_upper }}, "#ihist", 680, 300, 10);
+</script>
 <script type="text/javascript">
 	var width = 950,
 	    height = 200,
 	    .size([width, height])
 	    .value(function(d) { return d.size; });
 
-	var div = d3.select("#chart").append("div")
+	var div = d3.select("#treemap").append("div")
 	    .style("position", "relative")
 	    .style("width", width + "px")
 	    .style("height", height + "px");

bw2ui/web/templates/select.html

+{% extends "base.html" %}
+
+{% block extrahead %}
+<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
+<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.9.4/jquery.dataTables.min.js"></script>
+<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.9.0/themes/ui-lightness/jquery-ui.css" type="text/css" media="screen, projection">
+<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.9.4/css/jquery.dataTables.css" type="text/css" media="screen, projection">
+<style type="text/css">
+    table.dataTable tr.row_selected td {
+        background-color: salmon !important;
+    }
+</style>
+{% endblock %}
+
+{% block body %}
+<h1>Define the functional unit to assess</h1>
+<div class="span-7 colborder">
+    <p>
+        <h3>1. Chose database</h3>
+        <br>
+        {% for name in db_names %}
+        <input type="radio" name="database-select" value="{{ name }}"> {{ name }}<br>
+        {% endfor %}
+    </p>
+    <h3>2. Search by name:</h3>
+    <input id="activity-input" type="text" size=40>
+</div>
+<div class="span-16 last">
+    <h3>Selected activities:</h3>
+    <p>(click to change amounts)</p>
+    <table id="selected_activities">
+        <thead>
+            <tr>
+                <th>Amount</th>
+                <th>Unit</th>
+                <th>Name</th>
+                <th>Location</th>
+                <th>Key</th>
+            </tr>
+        </thead>
+        <tbody>
+            <tr>
+                <td>Not yet!</td>
+                <td></td>
+                <td></td>
+                <td></td>
+                <td></td>
+            </tr>
+        </tbody>
+    </table>
+</div>
+<div class="clear span-24">
+    <h1>Chose the LCIA method</h1>
+    <h3>Chosen method: <span id="chosen-method">(click below to chose a method)</span></h3>
+    <table id="lcia_methods">
+        <thead>
+            <tr>
+                <th>Level 1</th>
+                <th>Level 2</th>
+                <th>Level 3</th>
+                <th># CFs</th>
+                <th>Unit</th>
+                <th>Key</th>
+            </tr>
+        </thead>
+        <tbody>{% for m in lcia_methods %}
+            <tr>
+                <td>{{m.l1}}</td>
+                <td>{{m.l2}}</td>
+                <td>{{m.l3}}</td>
+                <td>{{m.n}}</td>
+                <td>{{m.u}}</td>
+                <td>{{m.k}}</td>
+            </tr>{% endfor %}
+        </tbody>
+    </table>
+</div>
+<script>
+$(document).ready(function() {
+    selected_method = null;
+    $('#selected_activities').dataTable();
+    $('#lcia_methods').dataTable();
+    $('#selected_activities').dataTable().fnSetColumnVis(4, false);
+    $('#lcia_methods').dataTable().fnSetColumnVis(5, false);
+
+    $('input[name=database-select]:radio').change(function () {
+        var url = "/database/" + $(this).val() + "/names";
+        $.getJSON(url, function(result) {
+            $("#activity-input").autocomplete("option", "disabled", false);
+            $("#activity-input").autocomplete("option", "source", result);
+        });
+    });
+
+    $("#activity-input").autocomplete({
+        disabled: true,
+        source: ["foo", "bar", "baz"],
+        select: function( event, ui ) {
+            var table = $("#selected_activities").dataTable();
+            table.fnAddData([
+                1.0, ui.item.value.u, ui.item.value.n, ui.item.value.l, ui.item.value.k
+            ]);
+            if (table.fnGetData(0)[0] === "Not yet!") {
+                table.fnDeleteRow(0);
+            };
+            $("#activity-input").html("");
+            return false;
+        },
+        focus: function( event, ui ) { return false; }
+    });
+
+    $("#lcia_methods tbody tr").click( function( e ) {
+        if ( $(this).hasClass('row_selected') ) {
+            $(this).removeClass('row_selected');
+        }
+        else {
+            $('#lcia_methods').dataTable().$('tr.row_selected').removeClass('row_selected');
+            $(this).addClass('row_selected');
+        }
+        $("#chosen-method").html(this.cells[0].textContent + " : " + this.cells[1].textContent + " : " + this.cells[2].textContent);
+        console.log(this);
+        selected_method = this.cells[4].textContent;
+        console.log(selected_method);
+    });
+
+});
+</script>
+{% endblock %}