Przeglądaj źródła

Fix graph and coloring when ordinal/time scales are used

Adjusts the y-axis and coloring for when ordinal (and as a derivative,
time scales) are the only y-axis in the graph.  Previously, a number-
only axis was required to draw the plot.

Also fixes a bug where selecting ordinal/time scale would not select
the lines.

Closes #54
Zachary Tong 12 lat temu
rodzic
commit
ac9bfca6e9
1 zmienionych plików z 85 dodań i 16 usunięć
  1. 85 16
      panels/parallelcoordinates/module.js

+ 85 - 16
panels/parallelcoordinates/module.js

@@ -241,7 +241,16 @@ angular.module('kibana.parallelcoordinates', [])
           //.fade class hides the "inactive" lines, helps speed up rendering significantly
           directive.foregroundLines.classed("fade", function(d) {
             return !actives.every(function(p, i) {
-              var inside = extents[i][0] <= d[p] && d[p] <= extents[i][1];
+
+              var pointValue;
+
+              if (directive.ordinals[p] === true) {
+                pointValue = directive.y[p](d[p]);
+              } else {
+                pointValue = d[p];
+              }
+
+              var inside = extents[i][0] <= pointValue && pointValue <= extents[i][1];
               return inside;
             });
           });
@@ -305,32 +314,53 @@ angular.module('kibana.parallelcoordinates', [])
           directive.y = {};
 
           directive.line = d3.svg.line().interpolate('cardinal');
-          directive.axis = d3.svg.axis().orient("left");
+          directive.axis = d3.svg.axis().orient("left").ticks(5);
+          directive.ordinals = {};
 
+          scope.panel.fields.forEach(function(d) {
+            var firstField = scope.data[0][d];
 
-          var colorExtent = d3.extent(scope.data, function(p) { return +p[scope.panel.fields[0]]; });
+            if (_.isString(firstField)) {
+              if (isValidDate(new Date(firstField))) {
 
-          directive.colors = d3.scale.linear()
-            .domain([colorExtent[0],colorExtent[1]])
-            .range(["#4580FF", "#FF9245"]);
+                //convert date timestamps to actual dates
+                _.map(scope.data, function(v) {
+                  v[d] = new Date(v[d]);
+                });
 
+                var extents = d3.extent(scope.data, function(p) { return p[d]; });
 
-          scope.panel.fields.forEach(function(d) {
+                directive.y[d] = d3.time.scale()
+                  .domain([extents[0],extents[1]])
+                  .range([directive.h, 0]);
+
+              } else {
+                directive.ordinals[d] = true;
 
-            //If it is a string, setup an ordinal scale.
-            //Otherwise, use a linear scale for numbers
-            if (_.isString(scope.data[0][d])) {
+                var value = function(v) { return v[d]; };
+                var values = _.map(_.uniq(scope.data, value),value);
 
-              var value = function(v) { return v[d]; };
-              var values = _.map(_.uniq(scope.data, value),value);
+                directive.y[d] = d3.scale.ordinal()
+                  .domain(values)
+                  .rangePoints([directive.h, 0]);
 
-              directive.y[d] = d3.scale.ordinal()
-                .domain(values)
-                .rangeBands([directive.h, 0]);
-            } else if (_.isNumber(scope.data[0][d])) {
+              }
+
+            } else if (_.isNumber(firstField)) {
               directive.y[d] = d3.scale.linear()
                 .domain(d3.extent(scope.data, function(p) { return +p[d]; }))
                 .range([directive.h, 0]);
+
+            } else if (_.isDate(firstField)) {
+              //this section is only used after timestamps have been parsed into actual date objects...
+              //avoids reparsing
+
+              var extents = d3.extent(scope.data, function(p) { return p[d]; });
+
+              directive.y[d] = d3.time.scale()
+                .domain([extents[0],extents[1]])
+                .range([directive.h, 0]);
+
             }
 
             directive.y[d].brush = d3.svg.brush()
@@ -338,6 +368,8 @@ angular.module('kibana.parallelcoordinates', [])
               .on("brush", brush);
           });
 
+          //setup the colors for the lines
+          setColors();
 
           //pull out the actively selected columns for rendering the axis/lines
           var activeData = _.map(scope.data, function(d) {
@@ -439,6 +471,43 @@ angular.module('kibana.parallelcoordinates', [])
 
         }
 
+        function setColors() {
+
+          var firstPanelField = scope.data[0][scope.panel.fields[0]];
+          var extents = d3.extent(scope.data, function(p) { return p[scope.panel.fields[0]]; });
+
+          if (_.isString(firstPanelField)) {
+
+            var value = function(v) { return v[firstPanelField]; };
+            var values = _.map(_.uniq(scope.data, value),value);
+
+            values = scope.data;
+            directive.colors = d3.scale.ordinal()
+              .domain(values)
+              .range(d3.range(values.length).map(d3.scale.linear()
+                .domain([0, values.length - 1])
+                .range(["red", "blue"])
+                .interpolate(d3.interpolateLab)));
+
+          } else if (_.isNumber(firstPanelField)) {
+            directive.colors = d3.scale.linear()
+              .domain([extents[0],extents[1]])
+              .range(["#4580FF", "#FF9245"]);
+
+          } else if (_.isDate(firstPanelField)) {
+            directive.colors = d3.time.scale()
+              .domain([extents[0],extents[1]])
+              .range(["#4580FF", "#FF9245"]);
+          }
+
+        }
+
+        function isValidDate(d) {
+          if ( Object.prototype.toString.call(d) !== "[object Date]" )
+            return false;
+          return !isNaN(d.getTime());
+        }
+
       }
     };
   });