[tor-commits] [atlas/master] Refactoring for the map view

irl at torproject.org irl at torproject.org
Fri Jan 12 08:32:49 UTC 2018


commit e66f00562eb39b549c6e68a8321efbc693faf125
Author: Iain R. Learmonth <irl at fsfe.org>
Date:   Fri Jan 12 00:26:26 2018 +0000

    Refactoring for the map view
    
    There were a number of "special cases" for the consensus weight vs.
    advertised bandwidth that this commit tries to reduce. As a result the
    semantics of the map analysis have changed although not with any
    noticable difference to the results.
    
    In the previous version the value for each country was determined by the
    total of the consensus weight to the total of the advertised bandwidth.
    This commit changes this to make the value for each country a mean
    average of the ratios for individual relays, and now excludes relays
    with an advertised bandwidth of 0 (or missing advertised bandwidth) and
    those relays that are not yet measured by at least 3 bandwidth
    authorities.
    
    During refactoring, tooltips have also been added to display values when
    hovering over a country.
---
 js/collections/aggregates.js | 14 +++++--
 js/models/aggregate.js       |  2 +
 js/views/aggregate/map.js    | 95 ++++++++++++++++++++++++++------------------
 templates/aggregate/map.html |  2 +-
 4 files changed, 71 insertions(+), 42 deletions(-)

diff --git a/js/collections/aggregates.js b/js/collections/aggregates.js
index 163d7fb..b7354f4 100644
--- a/js/collections/aggregates.js
+++ b/js/collections/aggregates.js
@@ -7,7 +7,7 @@ define([
 ], function($, _, Backbone, aggregateModel){
   var aggregatesCollection = Backbone.Collection.extend({
     model: aggregateModel,
-    baseurl: 'https://onionoo.torproject.org/details?running=true&type=relay&fields=country,guard_probability,middle_probability,exit_probability,consensus_weight,consensus_weight_fraction,advertised_bandwidth,flags,as_number,as_name',
+    baseurl: 'https://onionoo.torproject.org/details?running=true&type=relay&fields=country,guard_probability,middle_probability,exit_probability,consensus_weight,consensus_weight_fraction,advertised_bandwidth,flags,as_number,as_name,measured',
     url: '',
     aType: 'cc',
     lookup: function(options) {
@@ -70,14 +70,19 @@ define([
           if (!asAggregate) {
             if (relay.as_number !== 0) aggregates[aggregateKey].as.add(relay.as_number);
           }
-
           aggregates[aggregateKey].relays++;
           if ((typeof relay.guard_probability) !== "undefined") aggregates[aggregateKey].guard_probability += relay.guard_probability;
           if ((typeof relay.middle_probability) !== "undefined") aggregates[aggregateKey].middle_probability += relay.middle_probability;
           if ((typeof relay.exit_probability) !== "undefined") aggregates[aggregateKey].exit_probability += relay.exit_probability;
           if ((typeof relay.consensus_weight) !== "undefined") aggregates[aggregateKey].consensus_weight += relay.consensus_weight;
           if ((typeof relay.consensus_weight_fraction) !== "undefined") aggregates[aggregateKey].consensus_weight_fraction += relay.consensus_weight_fraction;
-          if ((typeof relay.advertised_bandwidth) !== "undefined") aggregates[aggregateKey].advertised_bandwidth += relay.advertised_bandwidth;
+          if ((typeof relay.advertised_bandwidth) !== "undefined" && relay.advertised_bandwidth > 0) {
+            aggregates[aggregateKey].advertised_bandwidth += relay.advertised_bandwidth;
+            if (relay.measured) {
+              aggregates[aggregateKey].consensus_weight_to_bandwidth_count++;
+              aggregates[aggregateKey].consensus_weight_to_bandwidth += ((relay.consensus_weight*1024)/relay.advertised_bandwidth); // This is divided by number of relays for which data existed below to provide a mean average
+            }
+          }
           _.each(relay.flags, function(flag) {
             if (flag == "Guard") aggregates[aggregateKey].guards++;
             if (flag == "Exit") aggregates[aggregateKey].exits++;
@@ -104,6 +109,9 @@ define([
               });
             }
           }
+          if (aggregate.consensus_weight_to_bandwidth_count > 0) {
+            aggregate.consensus_weight_to_bandwidth = aggregate.consensus_weight_to_bandwidth/aggregate.consensus_weight_to_bandwidth_count;
+          }
           aggregatesArr.push(aggregate);
         });
         collection[options.add ? 'add' : 'reset'](aggregatesArr, options);
diff --git a/js/models/aggregate.js b/js/models/aggregate.js
index 0b85050..50740df 100644
--- a/js/models/aggregate.js
+++ b/js/models/aggregate.js
@@ -15,6 +15,8 @@ define([
           advertised_bandwidth: 0,
           consensus_weight: 0,
           consensus_weight_fraction: 0,
+          consensus_weight_to_bandwidth: 0,
+          consensus_weight_to_bandwidth_count: 0,
           relays: 0,
           guards: 0,
           exits: 0
diff --git a/js/views/aggregate/map.js b/js/views/aggregate/map.js
index 4141e7b..fce1e61 100644
--- a/js/views/aggregate/map.js
+++ b/js/views/aggregate/map.js
@@ -23,7 +23,7 @@ define([
         "middle_probability": "This map shows the total middle probability of each country's relays as a percentage of the middle probabilities of all relays in the network. This probability is calculated based on consensus weights, relay flags, and bandwidth weights in the consensus. Path selection depends on more factors, so that this probability can only be an approximation.",
         "exit_probability": "This map shows the total exit probability of each country's relays as a percentage of the exit probabilities of all relays in the network. This probability is calculated based on consensus weights, relay flags, and bandwidth weights in the consensus. Path selection depends on more factors, so that this probability can only be an approximation.",
         "advertised_bandwidth": "This map shows the total <a href=\"https://metrics.torproject.org/glossary.html#advertised-bandwidth\" target=\"_blank\">advertised bandwidth</a> of each country's relays.",
-        "cw_bw": "This map shows the ratio of total consensus weight versus total advertised bandwidth for each country. Countries shown in purple have greater advertised bandwidth than consensus weight, indicating that they are underweighted. Countries shown in green have greater consensus weight than advertised bandwidth and so are over weighted."
+        "consensus_weight_to_bandwidth": "This map shows the average ratio of consensus weight to advertised bandwidth for relays in each country. Countries shown in purple have greater consensus weight than advertised bandwidth, indicating that they are overweighted. Countries shown in green have greater advertised bandwidth than consensus weight and so are underweighted. Relays that did not have an advertised bandwidth or advertise a bandwidth of zero are not included in this analysis. Relays that have not yet been measured by at least three bandwidth authorities are also not included in this map as their consensus weight is not based on bandwidth measurement yet."
     },
     initialize: function() {
       this.collection = new aggregatesCollection;
@@ -62,37 +62,55 @@ define([
       var maximum_value = Number.NEGATIVE_INFINITY;
       var minimum_value = Number.POSITIVE_INFINITY;
 
-      if (aggregate_property == "cw_bw") {
-        _.each(aggregates, function(aggregate) {
-          if (aggregate["advertised_bandwidth"] == 0) current_val = 0;
-            else current_val = (aggregate["consensus_weight"]/(aggregate["advertised_bandwidth"]/1024));
-          if (current_val > maximum_value) maximum_value = current_val;
-          if (current_val < minimum_value) minimum_value = current_val;
-       });
-       var getCountryAggregate = function(code, aggregate_property) {
-         var found = 0;
-         _.each(aggregates, function(aggregate) {
-           if (aggregate.country.toUpperCase() == code)
-           if (aggregate["advertised_bandwidth"] == 0) found = 0;
-           else found=aggregate["consensus_weight"]/(aggregate["advertised_bandwidth"]/1024);
-         });
-         if (found < 1 && found > 0) {
-           return 1/(Math.sqrt(found/minimum_value));
-         } else {
-           return 0-Math.sqrt(found/maximum_value);
-         }
-       }
-     } else {
+      _.each(aggregates, function(aggregate) {
+        current_val = aggregate[aggregate_property];
+        if (current_val > maximum_value) maximum_value = current_val;
+        if (current_val !== 0 && current_val < minimum_value) minimum_value = current_val;
+      });
+
+      var getCountryAggregate = function(code, aggregate_property) {
+        var found = 0;
         _.each(aggregates, function(aggregate) {
-          if (aggregate[aggregate_property] > maximum_value) maximum_value = aggregate[aggregate_property];
+          if (aggregate.country.toUpperCase() == code) found = aggregate[aggregate_property];
         });
-        var getCountryAggregate = function(code, aggregate_property) {
-          var found = 0;
-          _.each(aggregates, function(aggregate) {
-            if (aggregate.country.toUpperCase() == code) found = aggregate[aggregate_property];
-          });
-        return (found == 0) ? found : Math.sqrt(found/maximum_value);
+        return found;
+      }
+
+      var getCountryFillOpacity = function(code, aggregate_property) {
+        found = getCountryAggregate(code, aggregate_property);
+        if (aggregate_property == "consensus_weight_to_bandwidth") {
+          if (found == 0) {
+            return 0;
+          } else {
+            return (found < 1) ? -(1/found)/(1/minimum_value) : found/maximum_value;
+          }
+        } else {
+          return found/maximum_value;
+        }
+      }
+
+      var getCountryTooltip = function(code, aggregate_property) {
+        found = getCountryAggregate(code, aggregate_property);
+        text = CountryCodes[code.toLowerCase()] + " (" + code + ") - ";
+        switch (aggregate_property) {
+          case "consensus_weight_fraction":
+          case "guard_probability":
+          case "middle_probability":
+          case "exit_probability":
+              text += (found*100).toFixed(3) + "%";
+              break;
+          case "advertised_bandwidth":
+              text += found + "KBps";
+              break;
+          case "consensus_weight_to_bandwidth":
+              if (found == 0) {
+                text += "No relays";
+              } else {
+                text += (found<1) ? "1:" + (1/found).toFixed(1) :
+                                    found.toFixed(1) + ":1";
+              }
         }
+        return text;
       }
 
       d3.json("json/countries.topo.json", function(error, us) {
@@ -119,11 +137,11 @@ define([
         .enter()
           .append("path")
             .attr("id", function(d) { return d.id; })
-            .style("fill", function(d) { return (getCountryAggregate(d.id, aggregate_property) > 0) ? "#7d4698" : "#68b030"; })
-            .style("fill-opacity", function(d) { return Math.abs(getCountryAggregate(d.id, aggregate_property)); })
+            .style("fill", function(d) { return (getCountryFillOpacity(d.id, aggregate_property) > 0) ? "#7d4698" : "#68b030"; })
+            .style("fill-opacity", function(d) { return Math.abs(getCountryFillOpacity(d.id, aggregate_property)); })
             .attr("d", path)
           .append("svg:title")
-            .text( function(d) { return d.id; });
+            .text( function(d) { return getCountryTooltip(d.id, aggregate_property); });
 
 
     function append_legend() {
@@ -151,18 +169,19 @@ define([
           .style("fill", "#484848")
           .text( function() {
             return (aggregate_property == "advertised_bandwidth") ?
-             "" + (Math.pow(i,2)* maximum_value/(1024*1024)).toFixed(2) + "MiB/s" :
-             "" + (Math.pow(i,2)* maximum_value*100).toFixed(3) + "%";
+             "" + (i * maximum_value/(1024*1024)).toFixed(2) + "MiB/s" :
+             "" + (i * maximum_value*100).toFixed(3) + "%";
           });
        }
     }
-  if (aggregate_property == "cw_bw") {
+
+  if (aggregate_property == "consensus_weight_to_bandwidth") {
       legend = (maximum_value > 1) ? 0 : 1;
       current_box = 0;
       for (var i = legend; i <= 2 ; i += 0.2) {
         j = Math.abs(i-1);
-        current_value = (i<1) ? (Math.pow(j,2)*maximum_value) :
-                                (Math.pow(j,2)*(1/minimum_value));
+        current_value = (i<1) ? (j*maximum_value) :
+                                (j*(1/minimum_value));
         if (current_value < 1)
           continue;
         svg.append("rect")
@@ -177,7 +196,7 @@ define([
           .attr("y", height-(current_box*5+1)*20)
           .attr("height", "10")
           .attr("width", "15")
-          .style("fill", function() { return (i>1) ? "#7d4698" : "#68b030"; })
+          .style("fill", function() { return (i<1) ? "#7d4698" : "#68b030"; })
           .style("fill-opacity", function() { return j; })
           .style("stroke", "#484848");
 
diff --git a/templates/aggregate/map.html b/templates/aggregate/map.html
index 2f0a0bb..96716b6 100644
--- a/templates/aggregate/map.html
+++ b/templates/aggregate/map.html
@@ -56,7 +56,7 @@
      <label class="radio-inline"><input type="radio" name="aggregate-property" value="middle_probability"> Middle Probability</label>
      <label class="radio-inline"><input type="radio" name="aggregate-property" value="exit_probability"> Exit Probability</label>
      <label class="radio-inline"><input type="radio" name="aggregate-property" value="advertised_bandwidth"> Advertised Bandwidth</label>
-     <label class="radio-inline"><input type="radio" name="aggregate-property" value="cw_bw"> Consensus Weight versus Bandwidth</label>
+     <label class="radio-inline"><input type="radio" name="aggregate-property" value="consensus_weight_to_bandwidth"> Consensus Weight to Bandwidth Ratio</label>
    </form>
    <a class="btn btn-primary" href="#aggregate/cc<%= (query) ? "/" + query : "" %>">View Table</a>
    <a class="btn btn-secondary" id="save_svg">Save Map</a>





More information about the tor-commits mailing list