How to make xscales and xaxis from this data D3 V4 - d3.js

I am working on D3 V4.
I have this data
dataset = [{"Time": "33:10"},{"Time": "33:12"}]
How do I make scaleTime from this?
Also this approach is wrong:
var max = new Date(d3.max(dataset, function(d){return d["Time"]}));
var min = new Date(d3.min(dataset, function(d){return d["Time"]}));
var xScale = d3.scaleTime()
.domain([min,max])
.range([padding, width-padding]);
Since - it can't create correct Date object from this format:
"33:12"

My comments inline:
For D3 V3 time parsing
dataset = [{"Time": "33:10"},{"Time": "33:12"}]
//First convert your data to date object like this:
var myParser = d3.time.format("%M:%S");
//run for loop and use parser to parse the date.
dataset.forEach(function(d){
d.Time = myParser.parse(d.Time);//now its a dateObject
})
//Now get your max and min from the date Object
var max = new Date(d3.max(dataset, function(d){return d["Time"]}));
var min = new Date(d3.min(dataset, function(d){return d["Time"]}));
var xScale = d3.scaleTime()
.domain([min,max])
.range([padding, width-padding]);
For D3 V4 time parsing
dataset = [{"Time": "33:10"},{"Time": "33:12"}]
//First convert your data to date object like this:
var myParser = d3.timeParse("%M:%S");
//run for loop and use parser to parse the date.
console.log(myParser)
dataset.forEach(function(d){
d.Time = myParser(d.Time);//now its a dateObject
})
//Now get your max and min from the date Object
var max = new Date(d3.max(dataset, function(d){return d["Time"]}));
var min = new Date(d3.min(dataset, function(d){return d["Time"]}));

Related

d3 static Cubism chart - can't get data input right

I'm trying to make a static cubism chart like this http://bl.ocks.org/bae25/10797393
The csv file ("cubism_test.csv") looks something like this:
date,one,two,three,four,five
2018-06-01,132.54,18.44,68.36,0,56.63
2018-06-02,146.64,19.18,71.74,0,59.66
2018-06-03,160.77,117.98,75.15,0,62.71
2018-06-04,193.29,171.53,78.59,0,65.76
2018-06-05,275.92,78.64,82.05,0,68.82
<script>
// create context and horizon
var context = cubism.context()
.size(30)
.stop();
var horizon = context.horizon()
.extent([0,2]);
d3.csv("cubism_test.csv", function(data)
{
var format = d3.time.format("%Y-%m-%d");
data.forEach(function(d, i)
{
d.date = format.parse(d.date);
d.one= +d.one;
d.two= +d.two;
d.three= +d.three;
d.four= +d.four;
d.five= +d.five;
})
console.log(data);
// define metric accessor
context.metric(function(start,stop,step,callback)
{
var values = data;
console.log(values);
callback(null, values);
}, name);
d3.select("#graph").selectAll(".horizon")
.data(data)
.enter()
.append("div")
.attr("class", "horizon")
.call(horizon);
// set rule
d3.select("#body").append("div")
.attr("class", "rule")
.call(context.rule());
// set focus
context.on("focus", function(i) {
d3.selectAll(".value")
.style( "right", i == null ? null : context.size() - i + "px");
});
// set axis
var axis = context.axis()
d3.select("#graph").append("div").attr("class", "axis").append("g").call(axis);
});
</script>
Obviously this isn't working, but I don't know to fix it. I can't find a proper recourse on how to work with d3 data. The ones I've found are very basic and tell you how to use data to make simple circles, but not time series.
I don't know how to tell d3 to use the column headers as names or get it to use the values in the columns as the values for each cubism/horizon chart.
Your advice would be highly appreciated.

DC.js barChart not displaying with date axis

I'm trying to display a bar chart showing with a count of dates but the bars will not draw and I'm getting a NaN error in the console.
Please can someone tell me where I am going wrong?
var data1=[{budget:1,billed:1,fees:1,feeVariance:0,Documents:"URL",date:"01 February 2017"},
{budget:7,billed:6,fees:1,feeVariance:3,Documents:"URL",date:"01 February 2018"},
{budget:10,billed:1,fees:4,feeVariance:3,Documents:"URL",date:"01 May 2017"},
{budget:14,billed:2,fees:4,feeVariance:2,Documents:"URL",date:"15 May 2017"},
{budget:2,billed:1,fees:1,feeVariance:0,Documents:"URL",date:"02 June 2016"}];
var facts = crossfilter(data1);
var dateDimension = facts.dimension(function(d) { return new Date(d.date); });
var dateGroup = dateDimension.group().reduceCount(function(d){return new Date(d.date);});
var minDate = dateDimension.bottom(1)[0].date;
var maxDate = dateDimension.top(1)[0].date;
dc.barChart("#chart1")
.width(800)
.dimension(dateDimension)
.group(dateGroup)
.brushOn(false)
.x(d3.time.scale().domain([minDate,maxDate]))
.xUnits(d3.time.months);
dc.renderAll();
you need to firstly determine the date format so dc.js can understand it as a date rather than simply a string.
So firstly, create a variable to set the date format:
var dateFormat = d3.time.format('%d %B %Y');
then a function to make our date and month fields:
data1.forEach(function(d) {
d.date = dateFormat.parse(d.date);
d.month = d3.time.month(d.date);
});
Then change the dimension and group to use d.month
var dateDimension = facts.dimension(function(d) { return d.month; });
var dateGroup = dateDimension.group().reduceCount(function(d){return
d.month;});
This will group by month and provide a count/total by month also.
Here's the full code:
var dateFormat = d3.time.format('%d %B %Y');
var data1=[{budget:1,billed:1,fees:1,feeVariance:0,Documents:"URL",date:"01
February 2017"},
{budget:7,billed:6,fees:1,feeVariance:3,Documents:"URL",date:"01 February 2018"},
{budget:10,billed:1,fees:4,feeVariance:3,Documents:"URL",date:"01 May 2017"},
{budget:14,billed:2,fees:4,feeVariance:2,Documents:"URL",date:"15 May 2017"},
{budget:2,billed:1,fees:1,feeVariance:0,Documents:"URL",date:"02 June 2016"}];
var facts = crossfilter(data1);
data1.forEach(function(d) {
d.date = dateFormat.parse(d.date);
d.month = d3.time.month(d.date);
});
var dateDimension = facts.dimension(function(d) { return d.month; });
var dateGroup = dateDimension.group().reduceCount(function(d){return d.month;});
var minDate = dateDimension.bottom(1)[0].date;
var maxDate = dateDimension.top(1)[0].date;
dc.barChart("#chart1")
.width(800)
.dimension(dateDimension)
.group(dateGroup)
.brushOn(false)
.x(d3.time.scale().domain([minDate,maxDate]))
.xUnits(d3.time.months);
dc.renderAll();
I've added some extra properties to the chart to ensure all the bars are shown correctly:
.gap(2)
.outerPadding(5)
.centerBar(true)
.elasticX(true)
.xAxisPadding(20)
jsfiddle example:
jsfiddle

d3 Xscale returning nan even on setting scale properly

I am creating a d3 line chart, but my XScale is returning nan.
My lines are in ascending order of timestamp
I am setting x domain as:
var lastIndex = line_data[0].length -1;
var minDate = line_data[0][0]['date'];
var maxDate = line_data[0][lastIndex]['date'];
x.domain([minDate,maxDate]);
later I am trying to access it as:
.x(function(d) { console.log('d for x is',d.date);
console.log(x(d.date));
return x(d.date); })
Why is it returning nan?
Here is my fiddle
https://jsfiddle.net/james222/yw3Le6yb/
You are converting a date to a string when populating line_data.
var parser = d3.time.format("%m/%d/%Y %H:%M:%S");
abc[i]['date'] = parser(dateLabel);
line_data[counter] = abc;
Just use the date here.
abc[i]['date'] = dateLabel;

geoJSON projection with d3.js and dc.js for South Africa and provinces

I have been struggling for a few days trying to use dc.js with d3.js projection to draw a map of South Africa and the provinces. I have exhausted my search as most results incorporate the path used for SVG when not using dc.js and I can't seem to find a suitable example for correcting a projection in dc.js.
I can't seem to find the map thats being drawing and I don't know how to correct my projection.
I really really don't know what i'm missing, and anyone that can assist will be appreciated.
UPDATE: I have geoJson that ive tested in mapshaper and it works so the geojson is fine. I am just struggling with the projection.
zaMap = zaMapString
//new array
var zaMapData = [];
for(var p in zaMap["features"])
{
console.log("ndx2 province data " + zaMap["features"][p]["properties"]["name"]);
zaMapData.push({
province: zaMap["features"][p]["properties"]["name"],
donation: 1000
})
};
//crossfilter instance
var ndx2 = crossfilter(zaMapData);
//dimensions and group for dc/d3
var provinceDim = ndx2.dimension(function(d) {console.log("province d " + d["province"]); return d["province"];});
var donationsByProvince = provinceDim.group().reduceSum(function(d) {
return d["donation"];
});
//geoChoroplethChart
var zaChart = dc.geoChoroplethChart("#map");
//start of chart code using d3 and dc
zaChart.dimension(provinceDim)
.group(donationsByProvince)
.width(1000)
.height(330)
.colors(["#E2F2FF", "#C4E4FF", "#9ED2FF", "#81C5FF", "#6BBAFF", "#51AEFF", "#36A2FF", "#1E96FF", "#0089FF", "#0061B5"])
.projection(d3.geo.mercator()
.scale(26778)
.translate([8227, 3207]))
.overlayGeoJson(zaMap["features"], "name", function (d) {
return d.properties.name;
});
dc.renderAll();
$("#progress").css({"display": "none"});
})
UPDATE 2: I switched from fiddle to codepen so I could upload the geoJson file as a asset. The geoJson takes a while to load but using code from an existing stackoverflow question, I have gotten the map to draw and projection to correct itself automatically. The d3.js function is not wrapping the dc.js to tie in with crossfilter.js as yet but I am working on that. But this is progress :)
In http://jsfiddle.net/Jimmypoo/f67xo5ry/1/, you are trying to use JSON.parse to parse an zaMapString, which is already a JS object. You don't need to parse it, it's not a string.
Secondly, d3.json is meant for passing in a remote URL, which d3 grabs for you. You are trying to pass in a JS object, which already exists. So you can remove that function, and simply use .overlayGeoJson(zaMap["features"], "name", function (d) { inside.
You also forgot to include jQuery, yet you use it in $("#progress").css({"display": "none"});. You'll need to wrap the entire JS section in a $(document).ready as well.
Also, you are including the scripts multiple times, in both minified and unminified forms.You only need one instance of each library.
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/dc/1.7.0/dc.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/dc/1.7.0/dc.min.js"></script>
You are also trying to include dc's CSS as JavaScript.
<script src="http://cdnjs.cloudflare.com/ajax/libs/dc/1.7.0/dc.css"></script>
It should be added in JsFiddle's left-hand side resource panel instead.
I also don't think assigning #map directly to the body of your document is going to make things easier for you either..would recommend including something interior of that like <div id="map" style="width:100%;height:300px"></div>
These suggestions don't solve all your problems but get you most of the way along.You still have projection issues. Here is an forked fiddle to move from - http://jsfiddle.net/uggtjem6/
I have gotten the geoJson to work with d3.js, dc.js and crossfiler.
var width = 300;
var height = 400;
var zaMapData = [];
//geoChoroplethChart
var zaChart = dc.geoChoroplethChart("#map");
d3.json("https://s3-us-west-2.amazonaws.com/s.cdpn.io/384835/layer1.json", function(json) {
var zaMap = JSON.stringify(json);
console.log(zaMap);
for (var i = 0; i < json.features.length; i++) {
console.log("ndx2 province data " + json["features"][i]["properties"]["PROVINCE"]);
zaMapData.push({
province: json["features"][i]["properties"]["PROVINCE"],
donation: i*1000
})
};
//crossfilter instance
var ndx2 = crossfilter(zaMapData);
//dimensions and group for dc/d3
var provinceDim = ndx2.dimension(function(d) {console.log("province d " + d["province"]); return d["province"];});
var donationsByProvince = provinceDim.group().reduceSum(function(d) {
return d["donation"];
});
var max_province = donationsByProvince.top(1)[0].value;
// create a first guess for the projection
var center = d3.geo.centroid(json)
var scale = 150;
var offset = [width/2, height/2];
var projection = d3.geo.mercator().scale(scale).center(center)
.translate(offset);
// create the path
var path = d3.geo.path().projection(projection);
// using the path determine the bounds of the current map and use
// these to determine better values for the scale and translation
var bounds = path.bounds(json);
var hscale = scale*width / (bounds[1][0] - bounds[0][0]);
var vscale = scale*height / (bounds[1][1] - bounds[0][1]);
var scale = (hscale < vscale) ? hscale : vscale;
var offset = [width - (bounds[0][0] + bounds[1][0])/2,
height - (bounds[0][1] + bounds[1][1])/2];
// new projection
projection = d3.geo.mercator().center(center)
.scale(scale).translate(offset);
path = path.projection(projection);
//create dc.js chart
zaChart.dimension(provinceDim)
.group(donationsByProvince)
.width(width)
.height(height)
.colors(["#E2F2FF", "#C4E4FF", "#9ED2FF", "#81C5FF", "#6BBAFF", "#51AEFF", "#36A2FF", "#1E96FF", "#0089FF", "#0061B5"])
.colorDomain([0, max_province])
.projection(d3.geo.mercator()
.center(center)
.scale(scale)
.translate(offset))
.overlayGeoJson(json["features"], "PROVINCE", function (d) {
return d.properties.PROVINCE;
})
.title(function (p) {
return "Province: " + p["key"]
+ "\n"
+ "Total Donations: R " + Math.round(p["value"])
});
dc.renderAll();
});
My codepen here.

D3: Is there a simple way to enlarge a map statically?

I am attempting to create a map of my city but the default map is too small. I don't want to do anything like zooming (yet) but I would like to double the size displayed.
Here is an extract of the script
var projection;
var w=1200;
var h=800;
var x=-14100;
var y=7300;
var scale=66700;
projection=d3.geo.albers()
.translate([x,y])
.scale([scale]);
var path=d3.geo.path()
.projection(projection);
var svg=d3.select("#data-div")
.append("svg")
.attr("width",w)
.attr("height",h);
var category;
// GROUPS
var paths = svg.append("g"),
circles = svg.append("g");
// TORONTO MAP JSON
d3.json("d3_files/json/new-toronto.json",function(error, data){
paths.selectAll("path")
.data(data.features)
.enter()
.append("path")
.attr("d",path)
.attr("name",function(data){
return"<strong>name</strong>"
}) // end name attr
.style("fill",function(data){
return"lightgrey";
}) // end fill style
.style("stroke","#000")
}); // end toronto json
Instead of:
var scale=66700;
do:
var scale= 33350;
This will 'zoom' the projection out. From the API:
The scale factor corresponds linearly to the distance between
projected points

Resources