Select a month in bar chart from dc.js - dc.js

I have a time series with a date, an amount and a count column. I just want to plot the aggregate of amount by month and select a month by clicking on the bar, not using the brush.
I thought my objective was pretty simple, but I'm rummaging for days without success. The main issue is that I apply a filter on the chart, but the filter is not taken into account when a redraw the chart.
Thanks for your help.
I'm using :
dc.js 2.0.2
d3.js 3.5.17
crossfilter 1.4
This is my code :
<!DOCTYPE html>
<html lang="en">
<head>
<title>Just selecting a month </title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="../static/lib/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="../static/lib/css/dc.css"/>
</head>
<body>
<div>
Month selector
<a class="reset" href='javascript:chart.filterAll();dc.redrawAll();'> Reset</a>
<div id="time-chart"></div>
</div>
<script type="text/javascript" src="../static/lib/js/d3.js"></script>
<script type="text/javascript" src="../static/lib/js/crossfilter.js"></script>
<script type="text/javascript" src="../static/lib/js/dc.js"></script>
<script type="text/javascript">
var dateFormat_in = d3.time.format.utc("%Y-%m-%d");
var chart = dc.barChart("#time-chart");
d3.csv('setdates.csv', function(error, dataset) {
if(error)
throw new Error(error);
dataset.forEach(function(d) {
d["date"] = dateFormat_in.parse(d["date"]);
d["amount"] = +d["amount"];
});
var ndx = crossfilter(dataset);
var monthDim = ndx.dimension(d => d3.time.month(d["date"]));
var monthGroup = monthDim.group().reduceSum(d => d["amount"]);
var minDate = monthDim.bottom(1)[0]["date"];
var maxDate = monthDim.top(1)[0]["date"];
minDate=d3.time.day.offset(minDate, -40);
//console.log([minDate,maxDate]);
chart
.width(400)
.height(260)
.x(d3.time.scale().domain([minDate, maxDate]))
.xUnits(d3.time.months)
.dimension(monthDim)
.group(monthGroup)
.margins({left: 50, top: 20, right: 0, bottom: 20})
.elasticY(true)
.gap(60)
.centerBar(true).xAxisPadding(15).xAxisPaddingUnit('month')
.on('pretransition', function(ichart) {
ichart.selectAll("rect.bar").on("click", function (d) {
console.log([d.data.key,new Date(2016,d.data.key.getMonth()+1,1)]);
chart.filter([d.data.key,new Date(2016,5,1)]).redraw();
console.log(chart.filters())
//dc.renderAll();
});
})
.brushOn(false)
.clipPadding(20);
chart.centerBar(true).xAxisPadding(15).xAxisPaddingUnit('month')
dc.renderAll();
});
</script>
These are my data :
date,amount,count
2016-04-28,93.54,3.89
2016-04-29,94.42,3.94
2016-04-30,95.30,3.99
2016-05-02,97.06,4.08
2016-05-03,98.50,4.11
2016-05-04,99.94,4.13
2016-05-06,102.82,4.18
2016-05-07,104.26,4.20
2016-05-09,107.14,4.25
2016-05-10,109.27,4.26
2016-05-11,111.40,4.26
2016-05-12,113.53,4.27
2016-05-13,115.66,4.27
2016-05-14,117.78,4.28
2016-05-17,124.17,4.30
2016-05-18,126.30,4.30
2016-05-19,128.43,4.31
2016-05-20,130.56,4.32
2016-05-21,132.68,4.32
2016-05-23,136.94,4.33
2016-05-24,139.14,4.40
2016-05-25,141.35,4.48
2016-05-26,143.55,4.55
2016-05-27,145.75,4.62
2016-05-28,147.96,4.69
2016-05-30,152.36,4.83
2016-05-31,153.70,4.88
2016-06-01,155.04,4.93
2016-06-02,156.38,4.98
2016-06-03,157.73,5.02
2016-06-04,159.07,5.07
2016-06-06,161.75,5.17
2016-06-07,161.22,5.15
2016-06-08,160.70,5.14
2016-06-09,160.17,5.13
2016-06-10,159.64,5.12
2016-06-11,159.11,5.11
2016-06-13,158.06,5.08
2016-06-14,156.32,5.06
2016-06-15,154.59,5.04
2016-06-16,152.85,5.01
2016-06-17,151.12,4.99
2016-06-18,149.38,4.96

Interesting solution to this problem.
You probably want .redrawGroup() instead of .redraw() inside that handler, and you'll also need to wrap your range inside a dc.js filter object, specifically RangedFilter: unlike crossfilter's dimension.filter() dc.js's chart.filter() takes an object not an array.
Initial Range selection in DC.js chart

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.

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

Can't get jqplot.DateAxisRenderer to work with hours

I'm trying to plot the values over 24 hours. I'm working from this example on the jqplot site. I can't see what I'm doing wrong.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript" src="javascript/jqplot/jquery.jqplot.js"></script>
<link rel="stylesheet" href="javascript/jqplot/jquery.jqplot.css" type="text/css" />
<script type="text/javascript" src="javascript/jqplot/plugins/jqplot.dateAxisRenderer.min.js"></script>
<div id="chart1"></div>
<script type="text/javascript">
$(document).ready(function(){
var line2=[['2008-06-30 8:00AM',4], ['2008-06-30 9:00AM',6.5], ['2008-06-30 10:00AM',5.7], ['2008-06-30 11:00AM',9], ['2008-06-30 12:00PM',8.2]];
var plot2 = $.jqplot('chart1', [line2], {
title:'Customized Date Axis',
gridPadding:{right:35},
axes:{
xaxis:{
renderer:$.jqplot.DateAxisRenderer,
tickOptions:{formatString:'%r'}
}
},
series:[{lineWidth:4, markerOptions:{style:'square'}}]
});
});
</script>
I was trying to plot a Date axis with version: 1.0.4 Revision: 1121 and could not get it to plot the graph when I had hours as a time unit for plotting the points (all my points were plotting at the very end of the X axis)
Workaround for me was comment out this line -
min = min.getTime() + min.getUtcOffset(); from jqplot.dateAxisRenderer.js
Not sure if this is a bug but the plot did work for me after this code change.

Resources