How to bundle dc.js plot with rollup? - dc.js

I'm working on an application that uses d3 to create some interactive
maps and have successfully used rollup to bundle the javascript. I
have used dc.js in the past, and wanted to incorporate a bunch of dc.js plots
into the application. However I have been unable to figure out how to get
dc.js to work with rollup. It is mentioned in some discussions in the
dc.js issue tracker (example) , so I'm pretty sure it can be done. I'm hoping
someone can point out my mistake.
I have create a minimal example that demonstrates the issue(s) using a
single, simple dc.barChart modified from here: dc Bar Chart Example. When
I call rollup -c, bundle.js is created but:
a warning that "dc.barChart is not exported by node_modules\dc\dc.js" and
when the html page loads, the figure does not appear and the
console says: "Uncaught TypeError: Cannot
add property box, object is not extensible". "box" appears to be
referring to d3.box, but I have no idea why.
Here is my minimal index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>dc.js Rollup</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dc/3.0.7/dc.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css" />
</head>
<body>
<div id="container" class="container" >
<h3>A dc.js bar graph:</h3>
<div id="test"></div>
<p>modified from this example.</p>
</div>
<script type="text/javascript" src="bundle.js"></script>
</body>
</html>
Here is main.js:
import * as d3 from 'd3';
import crossfilter from 'crossfilter2';
import * as dc from 'dc';
let chart = dc.barChart('#test');
d3.csv('morley.csv').then(function(experiments) {
experiments.forEach(function(x) {
x.Speed = +x.Speed;
});
let ndx = crossfilter(experiments);
let runDimension = ndx.dimension(function(d) {return +d.Run;});
let speedSumGroup = runDimension
.group().reduceSum(function(d)
{return d.Speed * d.Run / 1000;});
chart
.width(768)
.height(480)
.x(d3.scaleLinear().domain([6,20]))
.brushOn(false)
.yAxisLabel('This is the Y Axis!')
.dimension(runDimension)
.group(speedSumGroup)
.on('renderlet', function(chart) {
chart.selectAll('rect').on('click', function(d) {
console.log('click!', d);
});
});
chart.render();
});
export { dc, d3, crossfilter };
and finally here is rollup.config.js:
import resolve from 'rollup-plugin-node-resolve';
import globals from 'rollup-plugin-node-globals';
import commonjs from 'rollup-plugin-commonjs';
import json from 'rollup-plugin-json';
import sourcemaps from 'rollup-plugin-sourcemaps';
function onwarn (warning, warn) {
if (warning.code === 'CIRCULAR_DEPENDENCY') return;
warn(warning);
}
export default {
input: 'main.js',
output: {
name: 'dcjs_rollup',
file: 'bundle.js',
format: 'iife',
sourceMap: true,
globals: {
'd3': 'd3',
'dc': 'dc',
'crossfilter2': 'crossfilter'
}
},
onwarn: onwarn,
plugins: [
resolve({
jsnext: true,
main: true,
browser: true
}),
sourcemaps(),
json(),
commonjs(),
globals(),
]
};
I'm hoping that I am missing something simple in my configuration
file or just need to include another plugin, but I am completely out
of ideas.
Any suggestions?
Adam

Related

How to show the unhighlighted/ not selected data points on scatter plots when using brush/group in dc.js? And is multiple brushes possible in dc.js

I have two questions.
Is it possible to still show the not selected data in corresponding scatter plot. Where there can be two scatters around the selected data points that the other data points stay or if there can be a color.
Is it possible to have multiple brushes in dc.js. Where I can select one part of data and do that again on another place in the same scatter plot.
For question 1
This is before the selection:
This after selection on graph. I would still like the not selected one to still appear:
What I would like for question 1
Here is my code sample:
<!DOCTYPE html>
<html lang="en">
<head>
<title>dc.js - Scatter Plot Brushing Example</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="../css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="../css/dc.css"/>
</head>
<body>
<div class="container">
<script type="text/javascript" src="header.js"></script>
<p>Brush on one chart to see the points filtered on the other.</p>
<div id="test1"></div>
<div id="test2"></div>
<script type="text/javascript" src="../js/d3.js"></script>
<script type="text/javascript" src="../js/crossfilter.js"></script>
<script type="text/javascript" src="../js/dc.js"></script>
<script type="text/javascript">
var chart1 = dc.scatterPlot("#test1");
var chart2 = dc.scatterPlot("#test2");
var data = "x,y,z\n" +
"1,1,3\n" +
"5,2,11\n" +
"13,13,13\n"+
"5,3,20\n"+
"12,12,10\n"+
"3,6,8\n"+
"15,2,9\n"+
"8,6,14\n"+
"1,4,9\n"+
"8,8,12\n";
var data = d3.csvParse(data);
data.forEach(function (x) {
x.x = +x.x;
x.y = +x.y;
x.z = +x.z;
});
var ndx = crossfilter(data),
dim1 = ndx.dimension(function (d) {
return [+d.x, +d.y];
}),
dim2 = ndx.dimension(function (d) {
return [+d.y, +d.z];
}),
group1 = dim1.group(),
group2 = dim2.group();
chart1.width(300)
.height(300)
.x(d3.scaleLinear().domain([0, 20]))
.yAxisLabel("y")
.xAxisLabel("x")
.clipPadding(10)
.dimension(dim1)
.excludedOpacity(0.5)
.group(group1);
chart2.width(300)
.height(300)
.x(d3.scaleLinear().domain([0, 20]))
.yAxisLabel("z")
.xAxisLabel("y")
.clipPadding(10)
.dimension(dim2)
.excludedColor('#ddd')
.group(group2);
dc.renderAll();
</script>
</div>
</body>
</html>
A1) That will be pretty difficult because dc.js sets the d of the paths of the not selected symbols in the other chart to d="M0,0". That means no path at all and all the symbols are now in the origin of the chart.
Edit
Looking at the code and after a little experiment I found if you add these then the other dots are visible
.emptySize(3)
.emptyOpacity(0.5)
The name is not very explanatory.

No new elements on page using D3

Trying to create simple svg canvas using D3 but looking at elements in the console nothing shows up. D3 seems to be loading because from the console when I type d3. I get the options and methods available in D3. But the svg canvas is not being drawn. What am I missing?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Basic Bar Chart</title>
<style>
</style>
</head>
<body>
<div id="chart"></div>
<script src="d3.v3.js">
var w = 500;
var h = 500;
function drawSVG(s) {
var svg = d3.select("#chart")
.append("svg")
.attr("width",w)
.attr("height",h);
console.log(s);
}
var sampleStr = "hello";
drawSVG(sampleStr);
</script>
</body>
</html>
You've placed your code within the script tag that has its source attribute set to download D3:
<script src="d3.v3.js">
... your code is here
</script>
You need to place your code in its own script tag:
<script src="d3.v3.js"></script>
<script>
... your code should go here
</script>

How to make filter transparent in dc.js charts

I am trying to make a bar chart using dc.js. Users are able to select a portion of the data by clicking and dragging on a filter. However, the difficulty is that when this happens, on my website, the filter is completely black and the data selected is obscured:
What should happen is, the filter should be partially transparent, as in this example from the home page of dc.js, so that the selected data can still be seen.
Here is the sample code which I am using to generate my page. I am using Crossfilter version 1.3.14, d3.js version 3.5.17 and dc.js 2.1.9.
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="static/dc.css.min"/>
</head>
<body>
<div id="graph"></div>
<script type="text/javascript" src="static/d3.js"></script>
<script type="text/javascript" src="static/crossfilter.js"></script>
<script type="text/javascript" src="static/dc.min.js"></script>
<script type="text/javascript">
var data = "data/page.csv";
d3.csv(data, function(error, records) {
var ndx = crossfilter(records);
var keyDimension = ndx.dimension(function(d) {return d.key;});
var valueGroup = keyDimension.group().reduceCount();
var graph = dc.barChart("#graph");
graph.width(500)
.height(300)
.x(d3.scale.linear().domain([0,15]))
.xUnits(function(){return 50;})
.dimension(keyDimension)
.group(valueGroup);
graph.render();
});
</script>
</body>
I replaced the minified dc files (dc.min.css, dc.min.js, dc.min.js.map) with their full equivalents (dc.css, dc.js, dc.js.map) downloaded from Github, and now the filter displays as normal.

Adding a D3.js Liquid Fill gauge in a Leaflet popup

I'm trying to add a D3.js liquid fill gauge (http://bl.ocks.org/brattonc/5e5ce9beee483220e2f6) in a Leaflet popup without succeeding.
Here is my code:
var map = L.map('map').setView([47.261491,-1.549244], 16);
var dataCenterIcon = L.icon({
iconUrl: 'images/datacenter-icon.png',
iconSize: [20, 20] // size of the icon
});
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap'
}).addTo(map);
d3.json("data/datacentersSigma.json",function (data){L.geoJson(data,{
pointToLayer: function (feature,latlng){return L.marker(latlng,{icon:dataCenterIcon});},
onEachFeature : function (feature, layer) {
var div = $('<div class="popupGraph" style="width: 200px; height:200px;"><svg id="gauge"/></svg></div>')[0];
var popup = L.popup().setContent(div);
layer.bindPopup(popup);
// var svg = d3.select(div).select("svg").attr("width", 200).attr("height", 200);
// svg.append("rect").attr("width", 150).attr("height", 150).style("fill", "lightBlue");
loadLiquidFillGauge("gauge",55);
}}).addTo(map);});
d3.json("data/trajetsFibreDCSigma.json",function (data){
L.geoJson(data, {
style: function(feature){return {color : feature.properties.stroke};}
}).addTo(map);
});
<!DOCTYPE html>
<html>
<head>
<title>Yepee</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/leaflet.css" />
<script src="js/leaflet.js"></script>
<script src="js/d3.js"></script>
<script src="js/liquidFillGauge.js"></script>
<script src="js/jquery-1.11.3.min.js"></script>
</head>
<body>
<div id="map" style="width: 800px; height: 600px"></div>
<!-- <svg id="gauge"/>-->
<script src="js/yepee.js" type="text/javascript"></script>
</body>
</html>
When I'm trying to display my map, I can't even see the markers and I've got this error:
TypeError: d3_window(...) is null
I can also load a liquid fill gauge on a svg element which isn't on my map.
I've tried to add just a simple svg square in the popup by following an example (http://jsfiddle.net/2XfVc/132/) and it worked.
The goal is to put that gauge in the leaflet popup and despite searching for a long time, I can't find what the problem is.
Thank you in advance for your answers.
You're trying to initialize the gauge when the actual SVG element isn't added to the DOM yet. Once the popup opens, the content gets added to the DOM, that's when you should initialize the gauge.
// Have same content for all your popups
var content = '<svg id="gauge" width="100" height="100"></svg>'
// Set markers with popup, include content and set value as option
new L.Marker([0, -45]).bindPopup(content, {'value': 33}).addTo(map)
new L.Marker([0, 45]).bindPopup(content, {'value': 66}).addTo(map)
// Catch popup open event
map.on('popupopen', function (e) {
// Initialize the gauge with current popup option's value
loadLiquidFillGauge('gauge', e.popup.options.value);
})
Demo on Plunker: http://embed.plnkr.co/2hMjBt/preview

D3 Dimple - How to show multiple dimple charts on same page?

I'm making an html page with several examples of charts that I will be using. On the page I have a Dimple line graph, a pie chart, a wordcloud etc. When I try to add a second dimple graph - this time a bar graph, the first dimple line graph that I already have on the page is drawn on top of my bar graph:
My HTML file looks like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>D3 Graphs</title>
<link rel="stylesheet" type="text/css" href="_/base.css">
<link rel="stylesheet" type="text/css" href="_/c3CSS.css">
<script type="text/javascript" src="_/d3.min.js"></script>
<script type="text/javascript" src="_/dimple.v2.1.0.min.js"></script>
<script type="text/javascript" src="_/c3.min.js"></script>
<script type="text/javascript" src="_/d3.layout.cloud.js"></script>
</head>
<body>
<div id="chartContainer">
<h1>Hot Topics Line</h1>
<script type="text/javascript" src=CurvyLine.js></script>
</div>
<h1>Hot Topics Pie</h1>
<div id="chart">
<script type="text/javascript" src=Pie.js></script>
</div>
<div id="wordCloud">
<h1>Clickable Word Cloud</h1>
<script type="text/javascript" src=WordCloud.js></script>
</div>
<div id="bar">
<h1>Clickable Word Cloud</h1>
<script type="text/javascript" src=WeekBar.js></script>
</div>
</body>
</html>
Without adding the bar chart at the end, the line graph displays properly at the top of the page above the pie chart. However, with the bar chart added, both the line and bar graph are drawn inside the "bar" div. Can anyone help with this please? Here is my line graph js file:
var svg = dimple.newSvg("#chartContainer", 590, 400);
d3.tsv("data/tweet_example.tsv", function (data) {
//data = dimple.filterData(data, "Owner", ["Aperture", "Black Mesa"])
var myChart = new dimple.chart(svg, data);
myChart.setBounds(60, 30, 505, 305);
var x = myChart.addCategoryAxis("x", "Month");
x.addOrderRule("Date");
myChart.addMeasureAxis("y", "Tweets");
var s = myChart.addSeries("Topic", dimple.plot.line);
s.interpolation = "cardinal";
myChart.addLegend(60, 10, 500, 20, "right");
myChart.draw();
});
and here is my bar graph js file:
var svg = dimple.newSvg("#bar", 800, 410);
d3.tsv("data/tweet_example2.tsv", function (data) {
//data = dimple.filterData(data, "Owner", ["Aperture", "Black Mesa"])
var barChart = new dimple.chart(svg, data);
barChart.addCategoryAxis("x", ["Day", "Topic"]);
barChart.addMeasureAxis("y", "Tweets");
barChart.addSeries("Topic", dimple.plot.bar);
barChart.addLegend(65, 10, 510, 20, "right");
barChart.draw();
barChart.draw();
});
Your problem is that you are using the same global name svg to hold references to two different charts. When your second piece of code runs, it overwrites the svg value that you had from the first piece of code, and when the .tsv() callback returns, it finds a reference to the second graph.
Simplest solution: use different names for svg variable in both pieces of code: svg1 and svg2 will be fine.
Most elegant solution: use some kind of namespace management, such as wrapping both pieces of code in immediately called functions:
function() {
// your first chunk of code here
}()
function() {
// your second chunk of code here
}()
This way you will have two svg variables local to their own scopes

Resources