heavyai-charting/example/example1.html
Jonathan Huang 7251f1d4e3 mapdc as ES6 Modules (#2255)
* [MAPDC] refactor using es6 modules

add logging module

add more charts and mixins

add bubble overlay, heatmap, boxplot

add more charts

finish moving to new folder

beging moving overrides to new folder

replace mapdc src/

update build script

fix tests

fix mapdc import

fix mapdc import

prebuild mapdc css styles

remove console

redrawAll on rangeFilter update

remove grunt, delete dead files

update tests

minor fixes

fix raster-mixin d3 import

lint

clear cache

fix mapdc style import

fix example styles

* remove dc from scatter-mixin
2017-02-13 15:20:37 -08:00

530 lines
19 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<title>MapD</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="css/mapdc.css" />
<link rel="stylesheet" type="text/css" href="css/chart.css" />
<link href='https://fonts.googleapis.com/css?family=Roboto:400,700,300' rel='stylesheet' type='text/css'>
<style>
.title {
font-weight: bold;
text-align:center;
}
.mapd{
position: relative;
top: 2px;
}
.data-count{
padding-right:20px;
}
.filter-count{
font-weight: bold;
color: #45B1E8;
}
</style>
</head>
<body>
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header" style="margin-top:10px">
<img alt="Brand" src="images/favicon.png" height="30" width="30">
<span class="mapd">MapD Demo</span>
</div>
<div class="navbar-text navbar-right">
<div class="data-count">
<span class="total"><span><span class="filter-count"></span></span>
<span>of <span class="total-count"></span> flights</span>
</div>
</div>
</div>
</nav>
<div class="main-container">
<div class="col-xs-6">
<div class="title"> Total Number of Flights by State </div>
<div class="chart1-example"></div>
</div>
<div class="col-xs-6">
<div class="title"> Carrier Departure Delay by Arrival Delay <small>(Minutes)</small> </div>
<div class="chart2-example"></div>
</div>
<div class="col-xs-12">
<div class="title"> Number of Flights by Departure Time </div>
<div class="chart3-example"></div>
</div>
</div>
<script src="js/lodash.js"></script>
<script src="js/d3.min.js"></script>
<script src="js/thrift.js"></script>
<script src="js/mapd.thrift.js"></script>
<script src="js/mapd_types.js"></script>
<script src="js/MapdCon.js"></script>
<script src="js/mapd-crossfilter.js"></script>
<script src="js/mapdc.js"></script>
<script src="js/mapbox-gl.js"></script>
<script src="js/mapboxgl-overrides.js"></script>
<script>
/*
* This is example code that shows how to make 3 cross-filtered charts with the
* dc.mapd.js API. This example is not meant to be a replacement for dc.js
* documentation. For the dc.js API docs, see here
* - https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md.
* For an annotated example of using dc.js - see here:
* https://dc-js.github.io/dc.js/docs/stock.html.
*/
function createCharts(crossFilter) {
var colorScheme = ["#22A7F0", "#3ad6cd", "#d4e666"]
var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0) - 50
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0) - 200
/*
* crossFilter is an object that handles cross-filtered the different
* dimensions and measures that compose a dashboard's charts.
* It has a number of methods on it.
*/
/*
* getColumns() will grab all columns from the table along with metadata about
* those columns.
*/
var allColumns = crossFilter.getColumns();
/*-------------------BASIC COUNT ON CROSSFILTER---------------------------*/
/*
* A basic operation is getting the filtered count and total count
* of crossFilter. This performs that operation. It is built into DC.
* Note that for the count we use crossFilter itself as the dimension.
*/
var countGroup = crossFilter.groupAll();
var dataCount = dc.dataCount(".data-count")
.dimension(crossFilter)
.group(countGroup);
/*------------------------CHART 1 EXAMPLE------------------------------*/
/*
* In crossfilter dimensions can function as what we would like to "group by"
* in the SQL sense of the term. We'd like to create a bar chart of number of
* flights by destination state ("dest_state") - so we create a crossfilter dimension
* on "dest_state"
*
* Here lies one of the chief differences between crossfilter.mapd.js and the
* original crossfilter.js. In the original crossfilter you could provide
* javascript expressions like d.dest_state.toLowerCase() as part of
* dimension, group and order functions. However since ultimately our
* dimensions and measures are transformed into SQL that hit our backend, we
* require string expressions. (i.e "extract(year from dep_timestamp))"
*/
var rowChartDimension = crossFilter.dimension("dest_state");
/*
* To group by a variable, we call group() on the function and then specify
* a "reducer". Here we want to get the count for each state, so we use the
* crossfilter reduceCount() method.
*
* More crossfilter Methods here:
* https://github.com/square/crossfilter/wiki/API-Reference#dimension
* https://github.com/square/crossfilter/wiki/API-Reference#group-map-reduce
* https://github.com/square/crossfilter/wiki/API-Reference#group_reduceCount
*/
var rowChartGroup = rowChartDimension.group().reduceCount();
/*
* We create a horizontal bar chart with the data specified above (count by destination
* state) by using a dc.rowChart (i.e. a horizontal bar chart)
*
* We invoke the following options on the rowChart using chaining.
*
* Height and width - match the containing div
*
* elasticX - a dc option to cause the axis to rescale as other filters are
* applied
*
* cap(20) - Only show the top 20 groups. By default crossFilter will sort
* the dimension expression (here, "dest_state"), by the reduce expression (here, count),
* so we end up with the top 20 destination states ordered by count.
*
* othersGrouper(false) - We only would like the top 20 states and do not want
* a separate bar combining all other states.
*
* ordinalColors(colorScheme) - we want to color the bars by dimension, i.e. dest_state,
* using the color ramp defined above (an array of rgb or hex values)
*
* measureLabelsOn(true) - a mapd.dc.js add-on which allows not only the dimension
* labels (i.e. Texas) to be displayed but also the measures (i.e. the number
* of flights with Texas as dest_state)
*
* Simple Bar Chart Example using DC api here:
* https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md
*/
var dcBarChart = dc.rowChart('.chart1-example')
.height(h/1.5)
.width(w/2)
.elasticX(true)
.cap(20)
.othersGrouper(false)
.ordinalColors(colorScheme)
.measureLabelsOn(true)
.dimension(rowChartDimension)
.group(rowChartGroup)
.autoScroll(true);
/*--------------------------CHART 2 EXAMPLE------------------------------*/
/*
* Bubble Chart Example:
* Here we will create a bubble chart (scatter plot with sized circles).
* We want to make a circle for each airline carrier - i.e. group by
* carrier ("carrier_name" in the dataset), with the x coordinate
* corresponding to average departure delay ("depdelay"), the y coordinate
* corresponding to average arrival delay ("arrdelay"), and the size of the
* circle corresponding to the number of flights for that carrier (the count).
* We will color by the group or key, i.e. carrier_name.
*
*/
var scatterPlotDimension = crossFilter.dimension("carrier_name");
/*
* MapD created a reduceMulti function in order to handle multiple measures.
* It takes an array of objects, each corresponding to a measure.
* Each measure object requires 3 arguments:
* 'expression' which is the measure
* 'agg_mode' which is the calculation to perform.
* 'name' is how to reference the data
*
*/
var reduceMultiExpression1 = [{
expression: "depdelay",
agg_mode:"avg",
name: "x"
},
{
expression: "arrdelay",
agg_mode:"avg",
name: "y"
},
{
expression: "*",
agg_mode:"count",
name: "size"
}];
var popupHeader = [
{ type: "dimension", label: 'carrier_name' },
{ type: "measure", label: 'depdelay', alias: 'x' },
{ type: "measure", label: 'arrdelay', alias: 'y' },
];
/*
* Note the order("size") setter here. By default the bubble chart uses the
* top function which sorts all measures in descending order. This would
* cause the us to take the top n (specified by cap) sorted by x, y, and
* size in descending order. Since we probably do not want to sort
* primarility by departure delay, we override the sort and sort by size
* instead, which corresponds to the count measure - i.e. we take the
* n most popular airlines
*/
var scatterPlotGroup = scatterPlotDimension
.group()
.reduce(reduceMultiExpression1)
.order("size")
/* We create the bubble chart with the following parameters:
*
* Width and height - as above
*
* renderHorizontalGridLines(true)
*
* renderVerticalGridLines(true) - create grid under points
*
* cap(15) - only show top 15 airlines
*
* othersGrouper(false) - do not have a bubble for airlines not in top 15
*
* **Note for all accessors below the variables correspond to variables
* defined in reduceMulti above**
*
* keyAccessor - specify variable in result set associated with key (x-axis in
* bubble chart)
*
* valueAccessor - specify variable in result set associated with value (y-axis in bubble chart)
*
* radiusValueAccessor - specify variable in result set associated with radius of the bubbles
*
* colorAccessor - specify variable in result set associated with color of the
* bubbles. Here we are not coloring by a measure but instead by the groups
* themselves so we specify the first (and only) key, key0, If we were
* grouping by multiple (N) attributes we would have key0, key1... keyN
*
* maxBubbleRelativeSize(0.04) - specifies the max radius relative to length
* of the x axis. This means we cap the bubble radius at 4% of the length of
* the x axis.
*
* transitionDuration(500) - DC (via D3) will animate movement of the points
* between filter changes. This specifies that the animation duration should
* be 500 ms.
*
* xAxisLabel, yAxisLabel - specify the labels of the charts
*
* elasticX(true), elasticY(true) - allow the axes to readjust as filters are
* changed
*
* xAxisPadding('15%'), yAxisPadding('15%') - Without padding the min and max
* points for the x and y scales will be on the edge of the graph. This tells
* the chart to add an extra 15% margin to the axes beyond the min and max of
* that axis
*
* ordinalColors(colorScheme) - we want to color the bars by dimension, i.e. dest_state,
* using the color ramp defined above (an array of rgb or hex values)
*/
dcScatterPlot = dc.bubbleChart('.chart2-example')
.width(w/2)
.height(h/1.5)
.renderHorizontalGridLines(true)
.renderVerticalGridLines(true)
.cap(15)
.othersGrouper(false)
.keyAccessor(function (d) {
return d.x;
})
.valueAccessor(function (d) {
return d.y;
})
.radiusValueAccessor(function (d) {
return d.size;
})
.colorAccessor(function(d) {
return d.key0;
})
.maxBubbleRelativeSize(0.04)
.transitionDuration(500)
.xAxisLabel('Departure Delay')
.yAxisLabel('Arrival Delay')
.setPopupHeader(popupHeader)
.elasticX(true)
.elasticY(true)
.xAxisPadding('15%')
.yAxisPadding('15%')
.ordinalColors(colorScheme)
.dimension(scatterPlotDimension)
.group(scatterPlotGroup);
/* We create the bubble chart with the following parameters:
* dc.mapd.js allows functions to be applied at specific points in the chart's
* lifecycle. Here we want to re-adjust our chart's x,y and r (radius) scales
* as data is filtered in an out to take into account the changing range of
* the data along these different measures. Here we set the charts scale
* using standard d3 functions - telling dc.mapd.js to do this before each
* render and redraw */
var setScales = function(chart, type){
chart.on(type, function(chart) {
chart.x(d3.scale.linear().domain(d3.extent(chart.data(), chart.keyAccessor())));
chart.y(d3.scale.linear().domain(d3.extent(chart.data(), chart.valueAccessor())));
chart.r(d3.scale.linear().domain(d3.extent(chart.data(), chart.radiusValueAccessor())));
});
}
setScales(dcScatterPlot, "preRender");
setScales(dcScatterPlot, "preRedraw");
/*---------------------TIME CHART (CHART 3) EXAMPLE------------------------------*/
/*
* First we want to determine the extent (min,max) of the time variable so we
* can set the bounds on the time chart appropriately.
*
* If you know the bounds a priori you can do this manually but here we will
* do it dymaically via a query sent to the backend through the crossfilter
* api.
*
* We create a reduceMulti expression that will get the min and max of the
* variable dep_timestamp.
*
*/
var reduceMultiExpression2 =
[{
expression: "dep_timestamp",
agg_mode:"min",
name: "minimum"
},
{
expression: "dep_timestamp",
agg_mode:"max",
name: "maximum"}
]
/* Note than when we are doing aggregations over the entire dataset we use
* the crossfilter object itself as the dimension with the groupAll method
*
* valuesAsync(true) gets the values for our groupAll measure (here min and max
* of dep_timestamp) - true means to ignore currently set filters - i.e.
* get a global min and max
*/
crossFilter
.groupAll()
.reduceMulti(reduceMultiExpression2)
.valuesAsync(true).then(function(timeChartBounds) {
var timeChartDimension = crossFilter.dimension("dep_timestamp");
/* We would like to bin or histogram the time values. We do this by
* invoking setBinParams on the group. Here we are asking for 400 equal
* sized bins from the min to the max of the time range
*/
var timeChartGroup = timeChartDimension.group()
.reduceCount()
.setBinParams({
numBins: 400,
binBounds: [timeChartBounds.minimum,timeChartBounds.maximum]
});
/* We create the time chart as a line chart
* with the following parameters:
*
* Width and height - as above
*
* elasticY(true) - cause the y-axis to scale as filters are changed
*
* renderHorizontalGridLines(true) - add grid lines to the chart
*
* brushOn(true) - Request a filter brush to be added to the chart - this
* will allow users to drag a filter window along the time chart and filter
* the rest of the data accordingly
*
*/
var dcTimeChart = dc.lineChart('.chart3-example')
.width(w)
.height(h/2.5)
.elasticY(true)
.renderHorizontalGridLines(true)
.brushOn(true)
.xAxisLabel('Departure Time')
.yAxisLabel('# Flights')
.dimension(timeChartDimension)
.group(timeChartGroup);
/* Set the x and y axis formatting with standard d3 functions */
dcTimeChart
.x(d3.time.scale.utc().domain([timeChartBounds.minimum,timeChartBounds.maximum]))
.yAxis().ticks(5);
dcTimeChart
.xAxis().orient('top');
/* Calling dc.renderAllAsync() will render all of the charts we set up. Any
* filters applied by the user (via clicking the bar chart, scatter plot or dragging the time brush) will automagically call redraw on the charts without any intervention from us
*/
dc.renderAllAsync()
/*--------------------------RESIZE EVENT------------------------------*/
/* Here we listen to any resizes of the main window. On resize we resize the corresponding widgets and call dc.renderAll() to refresh everything */
window.addEventListener("resize", debounce(reSizeAll, 100));
function reSizeAll(){
var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0) - 50
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0) - 200
dcBarChart
.height(h/1.5)
.width(w/2)
dcScatterPlot
.height(h/1.5)
.width(w/2)
dcTimeChart
.width(w)
.height(h/2.5)
dc.renderAllAsync();
}
});
}
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
function init() {
/*
* mapdcon is a monad.
*
* It provides a MapD specific API to Thrift. Thrift is used to connect to our
* database backend.
*/
/* Before doing anything we must set up a mapd connection, specifying
* username, password, host, port, and database name */
new MapdCon()
.protocol("http")
.host("kali.mapd.com")
.port("9092")
.dbName("mapd")
.user("mapd")
.password("HyperInteractive")
.connect(function(error, con) {
/*
* This instaniates a new crossfilter.
* Pass in mapdcon as the first argument to crossfilter, then the
* table name, then a label for the data (unused in this example).
*
* to see all availables -- con.getTables()
*/
crossfilter.crossfilter(con, "flights").then(createCharts)
/*
* Pass instance of crossfilter into our reateCharts.
*/
});
}
document.addEventListener('DOMContentLoaded', init, false);
</script>
</body>
</html>