You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by cc...@apache.org on 2018/09/05 17:34:49 UTC

[incubator-superset] branch master updated: [SIP-5] Refactor calendar chart (#5760)

This is an automated email from the ASF dual-hosted git repository.

ccwilliams pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 2811498  [SIP-5] Refactor calendar chart (#5760)
2811498 is described below

commit 2811498ec97c55ca74eecb82681c2cda167cef82
Author: Krist Wongsuphasawat <kr...@gmail.com>
AuthorDate: Wed Sep 5 10:34:44 2018 -0700

    [SIP-5] Refactor calendar chart (#5760)
    
    * remove stroke
    
    * update style and annotate data type
    
    * update prop type
    
    * bring back utc code
    
    * add comments
---
 superset/assets/src/explore/controls.jsx           |   2 +-
 superset/assets/src/visualizations/cal_heatmap.css |   4 -
 superset/assets/src/visualizations/cal_heatmap.js  | 120 +++++++++++++++++----
 superset/assets/vendor/cal-heatmap/cal-heatmap.css |   5 -
 4 files changed, 101 insertions(+), 30 deletions(-)

diff --git a/superset/assets/src/explore/controls.jsx b/superset/assets/src/explore/controls.jsx
index 8c063a7..152d4a7 100644
--- a/superset/assets/src/explore/controls.jsx
+++ b/superset/assets/src/explore/controls.jsx
@@ -1078,7 +1078,7 @@ export const controls = {
     isInt: true,
     validators: [v.integer],
     renderTrigger: true,
-    default: 0,
+    default: 2,
     label: t('Cell Padding'),
     description: t('The distance between cells, in pixels'),
   },
diff --git a/superset/assets/src/visualizations/cal_heatmap.css b/superset/assets/src/visualizations/cal_heatmap.css
index b6be2d0..6fd4f5b 100644
--- a/superset/assets/src/visualizations/cal_heatmap.css
+++ b/superset/assets/src/visualizations/cal_heatmap.css
@@ -8,7 +8,3 @@
   margin-left: 20px;
   margin-top: 5px;
 }
-.graph-legend rect {
-  stroke: #aaa;
-  stroke-location: inside;
-}
diff --git a/superset/assets/src/visualizations/cal_heatmap.js b/superset/assets/src/visualizations/cal_heatmap.js
index 97c6e57..af91dce 100644
--- a/superset/assets/src/visualizations/cal_heatmap.js
+++ b/superset/assets/src/visualizations/cal_heatmap.js
@@ -1,31 +1,73 @@
 import d3 from 'd3';
-
+import PropTypes from 'prop-types';
 import { colorScalerFactory } from '../modules/colors';
 import CalHeatMap from '../../vendor/cal-heatmap/cal-heatmap';
-import '../../vendor/cal-heatmap/cal-heatmap.css';
 import { d3TimeFormatPreset, d3FormatPreset } from '../modules/utils';
-import './cal_heatmap.css';
 import { UTC } from '../modules/dates';
+import '../../vendor/cal-heatmap/cal-heatmap.css';
+import './cal_heatmap.css';
 
 const UTCTS = uts => UTC(new Date(uts)).getTime();
 
-function calHeatmap(slice, payload) {
-  const fd = slice.formData;
-  const steps = fd.steps;
-  const valueFormatter = d3FormatPreset(fd.y_axis_format);
-  const timeFormatter = d3TimeFormatPreset(fd.x_axis_time_format);
+const propTypes = {
+  data: PropTypes.shape({
+    // Object hashed by metric name,
+    // then hashed by timestamp (in seconds, not milliseconds) as float
+    // the innermost value is count
+    // e.g. { count_distinct_something: { 1535034236.0: 3 } }
+    data: PropTypes.object,
+    domain: PropTypes.string,
+    range: PropTypes.number,
+    // timestamp in milliseconds
+    start: PropTypes.number,
+    subdomain: PropTypes.string,
+  }),
+  height: PropTypes.number,
+  cellPadding: PropTypes.number,
+  cellRadius: PropTypes.number,
+  cellSize: PropTypes.number,
+  linearColorScheme: PropTypes.string,
+  showLegend: PropTypes.bool,
+  showMetricName: PropTypes.bool,
+  showValues: PropTypes.bool,
+  steps: PropTypes.number,
+  timeFormat: PropTypes.string,
+  valueFormat: PropTypes.string,
+  verboseMap: PropTypes.object,
+};
+
+function Calendar(element, props) {
+  PropTypes.checkPropTypes(propTypes, props, 'prop', 'Calendar');
+
+  const {
+    data,
+    height,
+    cellPadding = 3,
+    cellRadius = 0,
+    cellSize = 10,
+    linearColorScheme,
+    showLegend,
+    showMetricName,
+    showValues,
+    steps,
+    timeFormat,
+    valueFormat,
+    verboseMap,
+  } = props;
 
-  const container = d3.select(slice.selector).style('height', slice.height());
+  const valueFormatter = d3FormatPreset(valueFormat);
+  const timeFormatter = d3TimeFormatPreset(timeFormat);
+
+  const container = d3.select(element)
+    .style('height', height);
   container.selectAll('*').remove();
   const div = container.append('div');
-  const data = payload.data;
 
-  const subDomainTextFormat = fd.show_values ? (date, value) => valueFormatter(value) : null;
-  const cellPadding = fd.cell_padding !== '' ? fd.cell_padding : 2;
-  const cellRadius = fd.cell_radius || 0;
-  const cellSize = fd.cell_size || 10;
+  const subDomainTextFormat = showValues ? (date, value) => valueFormatter(value) : null;
 
   // Trick to convert all timestamps to UTC
+  // TODO: Verify if this conversion is really necessary
+  // since all timestamps should always be in UTC.
   const metricsData = {};
   Object.keys(data.data).forEach((metric) => {
     metricsData[metric] = {};
@@ -36,15 +78,16 @@ function calHeatmap(slice, payload) {
 
   Object.keys(metricsData).forEach((metric) => {
     const calContainer = div.append('div');
-    if (fd.show_metric_name) {
-      calContainer.append('h4').text(slice.verboseMetricName(metric));
+    if (showMetricName) {
+      calContainer.text(`Metric: ${verboseMap[metric] || metric}`);
     }
     const timestamps = metricsData[metric];
     const extents = d3.extent(Object.keys(timestamps), key => timestamps[key]);
     const step = (extents[1] - extents[0]) / (steps - 1);
-    const colorScale = colorScalerFactory(fd.linear_color_scheme, null, null, extents);
+    const colorScale = colorScalerFactory(linearColorScheme, null, null, extents);
 
-    const legend = d3.range(steps).map(i => extents[0] + (step * i));
+    const legend = d3.range(steps)
+      .map(i => extents[0] + (step * i));
     const legendColors = legend.map(colorScale);
 
     const cal = new CalHeatMap();
@@ -72,7 +115,7 @@ function calHeatmap(slice, payload) {
         max: legendColors[legendColors.length - 1],
         empty: 'white',
       },
-      displayLegend: fd.show_legend,
+      displayLegend: showLegend,
       itemName: '',
       valueFormatter,
       timeFormatter,
@@ -80,4 +123,41 @@ function calHeatmap(slice, payload) {
     });
   });
 }
-module.exports = calHeatmap;
+
+Calendar.propTypes = propTypes;
+
+function adaptor(slice, payload) {
+  const { selector, formData, datasource } = slice;
+  const {
+    cell_padding: cellPadding,
+    cell_radius: cellRadius,
+    cell_size: cellSize,
+    linear_color_scheme: linearColorScheme,
+    show_legend: showLegend,
+    show_metric_name: showMetricName,
+    show_values: showValues,
+    steps,
+    x_axis_time_format: timeFormat,
+    y_axis_format: valueFormat,
+  } = formData;
+  const { verbose_map: verboseMap } = datasource;
+  const element = document.querySelector(selector);
+
+  return Calendar(element, {
+    data: payload.data,
+    height: slice.height(),
+    cellPadding,
+    cellRadius,
+    cellSize,
+    linearColorScheme,
+    showLegend,
+    showMetricName,
+    showValues,
+    steps,
+    timeFormat,
+    valueFormat,
+    verboseMap,
+  });
+}
+
+export default adaptor;
diff --git a/superset/assets/vendor/cal-heatmap/cal-heatmap.css b/superset/assets/vendor/cal-heatmap/cal-heatmap.css
index 068997c..d6e18bc 100644
--- a/superset/assets/vendor/cal-heatmap/cal-heatmap.css
+++ b/superset/assets/vendor/cal-heatmap/cal-heatmap.css
@@ -4,11 +4,6 @@
   display: block;
 }
 
-.cal-heatmap-container .graph
-{
-  font-family: "Lucida Grande", Lucida, Verdana, sans-serif;
-}
-
 .cal-heatmap-container .graph-label
 {
   fill: #999;