Commit a1f124526ebd44f5e09b69bb99510b3de930b81c

Authored by Antoine Goutenoir
1 parent 77ff53d6
Exists in master

Add the new content from @dbarret

Fix #14
1 1
2 # Travel Carbon Footprint Calculator 2 # Travel Carbon Footprint Calculator
3 3
  4 +- https://travel-footprint-calculator.apps.goutenoir.com (private demo)
  5 +- http://travel-footprint-calculator.irap.omp.eu (official, for later)
  6 +
  7 +
4 ## Overview 8 ## Overview
5 9
6 - Content is in `content.yml`. 10 - Content is in `content.yml`.
@@ -599,6 +599,22 @@ estimate: @@ -599,6 +599,22 @@ estimate:
599 It may take from a few seconds up to a few minutes, 599 It may take from a few seconds up to a few minutes,
600 depending on the amount of locations you provided. 600 depending on the amount of locations you provided.
601 601
  602 + help:
  603 + first_name: Fill these to say hello.
  604 + last_name: We will never share your data with anyone.
  605 + origin_addresses: |
  606 + Use <code>en_US</code> city and country names, without diacritics.
  607 + &nbsp;
  608 + The comma matters.
  609 + <br>
  610 + This is either a home city and a country
  611 + or the cities and countries of the participants to the conference, meeting…
  612 + destination_addresses: |
  613 + This is either the cities and countries to travel to
  614 + or the host city and country of the conference, meeting…
  615 + <br>
  616 + Please provide multiple cities and countries to compute the location
  617 + of the minimum emission.
602 618
603 # Labels accept HTML, but not markdown 619 # Labels accept HTML, but not markdown
604 # Descriptions accept neither, since we use the HTML title attribute 620 # Descriptions accept neither, since we use the HTML title attribute
@@ -677,6 +693,23 @@ estimation: @@ -677,6 +693,23 @@ estimation:
677 Sorry about that. Please find the error message below. 693 Sorry about that. Please find the error message below.
678 <br> 694 <br>
679 Thank you for using our service. 695 Thank you for using our service.
  696 + lolliplot:
  697 + one_to_one: |
  698 + The carbon dioxide equivalent emission is provided for each city of destination.
  699 + Identical trips (i.e. identical destinations) are summed
  700 + and the cumulative distance is provided.
  701 + one_to_many: |
  702 + The carbon dioxide equivalent emission is provided for each city of destination.
  703 + Identical trips (i.e. identical destinations) are summed
  704 + and the cumulative distance is provided.
  705 + many_to_one: |
  706 + The carbon dioxide equivalent emission is provided for each city of origin.
  707 + Identical trips (i.e. identical origins) are summed and the cumulative distance is provided.
  708 + many_to_many: |
  709 + The carbon dioxide equivalent emission is summed
  710 + over all cities of origin and provided for each city of destination.
  711 + The cumulative distance to each city of destination is provided.
  712 + Duplicates in the destinations are removed.
680 713
681 footer: 714 footer:
682 credits: | 715 credits: |
flaskr/controllers/main_controller.py
@@ -9,7 +9,7 @@ from os.path import join @@ -9,7 +9,7 @@ from os.path import join
9 9
10 from flaskr.extensions import cache, basic_auth 10 from flaskr.extensions import cache, basic_auth
11 from flaskr.forms import LoginForm, EstimateForm 11 from flaskr.forms import LoginForm, EstimateForm
12 -from flaskr.models import db, User, Estimation, StatusEnum 12 +from flaskr.models import db, User, Estimation, StatusEnum, ScenarioEnum
13 from flaskr.geocoder import CachedGeocoder 13 from flaskr.geocoder import CachedGeocoder
14 14
15 from flaskr.core import generate_unique_id, get_emission_models 15 from flaskr.core import generate_unique_id, get_emission_models
@@ -366,6 +366,7 @@ def compute(): # process the queue of estimation requests @@ -366,6 +366,7 @@ def compute(): # process the queue of estimation requests
366 # for each of the Emission Models, and present a mean of all Models. 366 # for each of the Emission Models, and present a mean of all Models.
367 # 367 #
368 if 1 == len(origins): 368 if 1 == len(origins):
  369 + estimation.scenario = ScenarioEnum.one_to_many
369 results = compute_one_to_many( 370 results = compute_one_to_many(
370 _origin=origins[0], 371 _origin=origins[0],
371 _destinations=destinations, 372 _destinations=destinations,
@@ -377,6 +378,7 @@ def compute(): # process the queue of estimation requests @@ -377,6 +378,7 @@ def compute(): # process the queue of estimation requests
377 # Same as A for now. 378 # Same as A for now.
378 # 379 #
379 elif 1 == len(destinations): 380 elif 1 == len(destinations):
  381 + estimation.scenario = ScenarioEnum.many_to_one
380 results = compute_one_to_many( 382 results = compute_one_to_many(
381 _origin=destinations[0], 383 _origin=destinations[0],
382 _destinations=origins, 384 _destinations=origins,
@@ -388,6 +390,7 @@ def compute(): # process the queue of estimation requests @@ -388,6 +390,7 @@ def compute(): # process the queue of estimation requests
388 # Run Scenario A for each Destination, and expose optimum Destination. 390 # Run Scenario A for each Destination, and expose optimum Destination.
389 # 391 #
390 else: 392 else:
  393 + estimation.scenario = ScenarioEnum.many_to_many
391 unique_city_keys = [] 394 unique_city_keys = []
392 result_cities = [] 395 result_cities = []
393 for destination in destinations: 396 for destination in destinations:
flaskr/models.py
@@ -24,6 +24,13 @@ class StatusEnum(enum.Enum): @@ -24,6 +24,13 @@ class StatusEnum(enum.Enum):
24 failure = 'failure' 24 failure = 'failure'
25 25
26 26
  27 +class ScenarioEnum(enum.Enum):
  28 + one_to_one = 'one_to_one'
  29 + many_to_one = 'many_to_one'
  30 + one_to_many = 'one_to_many'
  31 + many_to_many = 'many_to_many'
  32 +
  33 +
27 class Estimation(db.Model): 34 class Estimation(db.Model):
28 id = db.Column(db.Integer(), primary_key=True) 35 id = db.Column(db.Integer(), primary_key=True)
29 public_id = db.Column( 36 public_id = db.Column(
@@ -42,12 +49,14 @@ class Estimation(db.Model): @@ -42,12 +49,14 @@ class Estimation(db.Model):
42 origin_addresses = db.Column(db.UnicodeText()) 49 origin_addresses = db.Column(db.UnicodeText())
43 destination_addresses = db.Column(db.UnicodeText()) 50 destination_addresses = db.Column(db.UnicodeText())
44 51
45 - # One slug per line (or blankchar?) 52 + # One slug per line (or blank char?)
46 models_slugs = db.Column(db.UnicodeText()) 53 models_slugs = db.Column(db.UnicodeText())
47 54
48 # Deprecated, we detect this scenario from the amount of locations. 55 # Deprecated, we detect this scenario from the amount of locations.
49 compute_optimal_destination = db.Column(db.Boolean()) 56 compute_optimal_destination = db.Column(db.Boolean())
50 57
  58 + # Outputs
  59 + scenario = db.Column(db.Enum(ScenarioEnum), default=ScenarioEnum.many_to_many)
51 output_yaml = db.Column(db.UnicodeText()) 60 output_yaml = db.Column(db.UnicodeText())
52 warnings = db.Column(db.UnicodeText()) 61 warnings = db.Column(db.UnicodeText())
53 errors = db.Column(db.UnicodeText()) 62 errors = db.Column(db.UnicodeText())
@@ -60,10 +69,20 @@ class Estimation(db.Model): @@ -60,10 +69,20 @@ class Estimation(db.Model):
60 def get_output_dict(self): 69 def get_output_dict(self):
61 if self._output_dict is None: 70 if self._output_dict is None:
62 self._output_dict = yaml_load(self.output_yaml) 71 self._output_dict = yaml_load(self.output_yaml)
63 - return self._output_dict 72 + return self._output_dict
  73 + pass
  74 +
  75 + def is_one_to_one(self):
  76 + return self.scenario == ScenarioEnum.one_to_one
  77 +
  78 + def is_one_to_many(self):
  79 + return self.scenario == ScenarioEnum.one_to_many
  80 +
  81 + def is_many_to_one(self):
  82 + return self.scenario == ScenarioEnum.many_to_one
64 83
65 - def has_many_to_many(self):  
66 - return 'cities' in self.get_output_dict() 84 + def is_many_to_many(self):
  85 + return self.scenario == ScenarioEnum.many_to_many
67 86
68 _models = None 87 _models = None
69 88
@@ -82,6 +101,7 @@ class EstimationView(ModelView): @@ -82,6 +101,7 @@ class EstimationView(ModelView):
82 'first_name', 101 'first_name',
83 'last_name', 102 'last_name',
84 'models_slugs', 103 'models_slugs',
  104 + 'scenario',
85 'origin_addresses', 105 'origin_addresses',
86 'destination_addresses', 106 'destination_addresses',
87 'warnings', 107 'warnings',
flaskr/static/css/common/main.css
@@ -73,7 +73,7 @@ span.required-asterisk { @@ -73,7 +73,7 @@ span.required-asterisk {
73 /** LISTS *********************************************************************/ 73 /** LISTS *********************************************************************/
74 74
75 .numbered-list { 75 .numbered-list {
76 - list-style: upper-roman; 76 + list-style: decimal-leading-zero;
77 } 77 }
78 78
79 79
flaskr/templates/estimate.html
@@ -70,11 +70,11 @@ @@ -70,11 +70,11 @@
70 <div class="form-group row"> 70 <div class="form-group row">
71 <div class="col-md-6"> 71 <div class="col-md-6">
72 {{ render_field(form.first_name) }} 72 {{ render_field(form.first_name) }}
73 - <small class="form-text text-muted">Fill these to say hello.</small> 73 + <small class="form-text text-muted">{{ content.estimate.help.first_name | safe }}</small>
74 </div> 74 </div>
75 <div class="col-md-6"> 75 <div class="col-md-6">
76 {{ render_field(form.last_name) }} 76 {{ render_field(form.last_name) }}
77 - <small class="form-text text-muted">We will never share your data with anyone.</small> 77 + <small class="form-text text-muted">{{ content.estimate.help.last_name | safe }}</small>
78 </div> 78 </div>
79 </div> 79 </div>
80 <div class="form-group"> 80 <div class="form-group">
@@ -83,19 +83,13 @@ @@ -83,19 +83,13 @@
83 <div class="form-group"> 83 <div class="form-group">
84 {{ render_field(form.origin_addresses) }} 84 {{ render_field(form.origin_addresses) }}
85 <small class="form-text text-muted"> 85 <small class="form-text text-muted">
86 - Use <code>en_US</code> city and country names, without diacritics.  
87 - &nbsp;  
88 - The comma matters.  
89 - <br>  
90 - These usually are the addresses of your participants. 86 + {{ content.estimate.help.origin_addresses | safe }}
91 </small> 87 </small>
92 </div> 88 </div>
93 <div class="form-group"> 89 <div class="form-group">
94 {{ render_field(form.destination_addresses) }} 90 {{ render_field(form.destination_addresses) }}
95 <small class="form-text text-muted"> 91 <small class="form-text text-muted">
96 - Provide <strong>multiple destinations</strong> to compare them and <strong>compute optimum</strong>.  
97 - <br>  
98 - These usually are the possible locations for an event. 92 + {{ content.estimate.help.destination_addresses | safe }}
99 </small> 93 </small>
100 </div> 94 </div>
101 {# <div class="form-check form-group">#} 95 {# <div class="form-check form-group">#}
flaskr/templates/estimation.html
@@ -79,21 +79,31 @@ @@ -79,21 +79,31 @@
79 79
80 {% if not estimation.has_failed() %} 80 {% if not estimation.has_failed() %}
81 {#{% set estimation_output = estimation.get_output_dict() %}#} 81 {#{% set estimation_output = estimation.get_output_dict() %}#}
82 -{% if estimation.has_many_to_many() %}  
83 - <div class="col-md-6">  
84 - <p>  
85 - For each destination city, the sum of the travels from all the origins.  
86 - </p> 82 +<div class="col-md-6">
  83 +{% if estimation.is_one_to_one() %}
  84 + {{ content.estimation.lolliplot.one_to_one | markdown | safe }}
  85 +{# <p>#}
  86 +{# For each destination city, the sum of the travels from all the origins.#}
  87 +{# </p>#}
87 {{ render_cities(estimation_output.cities) }} 88 {{ render_cities(estimation_output.cities) }}
88 - </div>  
89 -{% else %}  
90 - <div class="col-md-6">  
91 - <p>  
92 - Carbon footprint for each city.  
93 - </p> 89 +{% elif estimation.is_many_to_one() %}
  90 + {{ content.estimation.lolliplot.many_to_one | markdown | safe }}
  91 +{# <p>#}
  92 +{# For each destination city, the sum of the travels from all the origins.#}
  93 +{# </p>#}
  94 + {{ render_cities(estimation_output.cities) }}
  95 +{% elif estimation.is_one_to_many() %}
  96 + {{ content.estimation.lolliplot.one_to_many | markdown | safe }}
  97 +
  98 + {{ render_cities(estimation_output.cities) }}
  99 +{% elif estimation.is_many_to_many() %}
  100 + {{ content.estimation.lolliplot.many_to_many | markdown | safe }}
  101 +{# <p>#}
  102 +{# Carbon footprint for each city.#}
  103 +{# </p>#}
94 {{ render_cities(estimation_output.cities) }} 104 {{ render_cities(estimation_output.cities) }}
95 - </div>  
96 {% endif %} 105 {% endif %}
  106 +</div>
97 107
98 <div class="col-md-6"> 108 <div class="col-md-6">
99 <ul class="nav"> 109 <ul class="nav">
@@ -153,8 +163,13 @@ @@ -153,8 +163,13 @@
153 {# </pre>#} 163 {# </pre>#}
154 {# </div>#} 164 {# </div>#}
155 {#</div>#} 165 {#</div>#}
156 -{% endif %} 166 +
  167 +{% endif %}{# estimation.has_failed() #}
157 {% endblock %} 168 {% endblock %}
  169 +
  170 +{#############################################################################}
  171 +{#############################################################################}
  172 +
158 {% block js %} 173 {% block js %}
159 <script src="/static/js/vendor/d3.v4.js"></script> 174 <script src="/static/js/vendor/d3.v4.js"></script>
160 <script src="/static/js/vendor/d3-legend.js"></script> 175 <script src="/static/js/vendor/d3-legend.js"></script>