I'm having issues getting D3v4 to show lines on a chart. I might be getting v3/v4 syntax confused.
I have the data nested as there are 5 lines.
// Chart Canvas Dimentions
var margin = {top: 20, right: 80, bottom: 30, left: 50};
var width = 900;
var height = 600;
// Time Parse
var parseTime = d3.time.format("%Y-%m-%d %H:%M:%S");
// Chart Axis Sizes
yAxisMax = Math.max.apply(Math, data.map(function(o){return o.value;})) * 1.1;
yAxisMin = Math.min.apply(Math, data.map(function(o){return o.value;})) - (this.yAxisMax * 0.1);
xAxisMax = width * 0.99;
console.log('yAxisMax: '+yAxisMax);
console.log('yAxisMin: '+yAxisMin);
console.log('xAxisMax: '+xAxisMax);
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
chartLine = d3.svg.line()
.x(function(d){ return x(parseTime(d.date)) })
.y(function(d){ return y(d.value) })
.interpolate("basis");
// Nest Entries by Name (Groups the Lines by Names - Seperate Entities)
var nestedData = d3.nest()
.key(function(d) { return d.name; })
.entries(data);
// D3 Chart - This is the Context to Work With
var context = d3.select("#chartContainer").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("id", "D3lineChart")
.attr("class", "D3EventScopeContainer")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Interactive HoverLine
var hoverLine = context
.append('g')
.attr('class', 'hoverLineGroup')
.append("line")
.attr('transform', 'translate(70,0)')
.attr('class', 'interactiveHoverLine hidden')
.attr("x1", 0).attr("x2", 0)
.attr("y1", 0).attr("y2", height);
// Loop through data
nestedData.forEach(function(d,i) {
console.dir(d)
console.dir(d.values)
// Add Line
context
.append('g')
.attr('class', 'lineGroup')
.append('path')
.attr('transform', 'translate(70,0)')
.attr('class', 'chartLinesGroup tag'+ d.key.replace(/\s+/g, '').replace('.', '').replace('-', '').toLowerCase())
.style("stroke", function() { return d.color = color(d.key); }) // Add the colours dynamically
.style("stroke-opacity", 1)
//.attr('d', chartLine(d.values))
.on("mouseover", function() {
d3.select(this)
.style("stroke-width", 7.5)
})
.on("mouseout", function() {
d3.select(this)
.style("stroke-width", 2.5)
});
});
It fails when I enable the line
.attr('d', chartLine(d.values))
This function must not be formated correctly to use the data.
The error I get is - related to date processing:
Any advice would be greatly appreciated.
I'm essentially trying to get the the lines to show on the chart.
thanks
*** I get around the error message by adding .parse to the end of the time format line:
// Time Parse
var parseTime = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
Still nothing showing on the screen - div/svg has height/width set...
hummmmm
You need to read API;) But at first u must try :
var x = d3.scaleTime()
.range([0, width]);
var y = d3.scaleLinear()
.range([height, 0]);
var color = d3.scaleOrdinal(d3.schemeCategory10);
var xAxis = d3.axisBottom(x).tickFormat(d3.timeFormat("%H:%M:%S.%L"));
var yAxis = d3.axisLeft(y);
parseTime = d3.timeParse("%Y-%m-%d %H:%M:%S.%L");
chartLine = d3.line()
.curve(d3.curveMonotoneX)
.x(function(d){ return x(parseTime(d.date)) })
.y(function(d){ return y(d.value) });
Hope its help
Related
I am able to see glucose readings but time shows up as: 0NaN-NaN-NaNTNaN:NaN:NaN.NaNZ
I am trying to parse a dataset of time of the format "Y-M-D H:M:S.MS". I need it to be formatted properly so that I can show it on the x axis. I have attached sample dataset to this code.
My code looks like this:
<script>
function overview(){
// Set the dimensions of the canvas / graph
var margin = {top: 10, right: 20, bottom: 30, left: 30},
width = 600 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// // Parse the date / time
var parseDate = d3.utcFormat("%Y-%m-%dT%H:%M:%S.%LZ");
var x = d3.scaleTime()
.range([0, width]);
var y = d3.scaleLinear()
.range([height, 0]);
var xAxis = d3.axisBottom()
.tickFormat(d3.timeFormat("%H"));
var yAxis = d3.axisLeft();
// Define the line
var valueline = d3.line()
.x(function(d) { return x(d.time); })
.y(function(d) { return y(d.glucoseReading); });
// Adds the svg canvas
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Get the data
d3.csv("glucose.csv", function(error, data) {
data.forEach(function(d) {
d.time = parseDate(d.time);
d.glucoseReading = +d.glucoseReading;
console.log(d.time);
console.log(d.glucoseReading);
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.time; }));
y.domain([0, d3.max(data, function(d) { return d.glucoseReading; })]);
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// Add the scatterplot
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.time); })
.attr("cy", function(d) { return y(d.glucoseReading); });
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
});
}
overview();
</script>
My Dataset looks like:
You want to convert (parse) strings to dates, not the other way around. Therefore, instead of d3.utcFormat(), you have to use d3.utcParse(). On top of that, your specifier is incorrect: there is no timezone in your strings.
So, this should be your parseDate function and specifier:
var parseDate = d3.utcParse("%Y-%m-%d %H:%M:%S.%L")
Here is it working (check your browse console, not the snippet's one):
var parseDate = d3.utcParse("%Y-%m-%d %H:%M:%S.%L")
var string = "2017-08-23 00:03:52.591";
console.log(parseDate(string))
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
I'm following the D3 tutorial but adding the axis makes half of my data disappear and I don't understand why. I thought that maybe the axis is taking up the space that's meant for the data so I added an extra 10px to the transform property, but it doesn't make any difference.
var GIST = "https://gist.githubusercontent.com/charisseysabel/f8f48fbf11b8a1b0d62cbe2d6bdc2aa6/raw/2ead1537adb822fbd59a666afd5334d525480a13/nano-2017.tsv"
var width = 1000,
height = 550,
margin = {top: 20, right: 30, bottom: 30, left: 4};
var y = d3.scaleLinear()
.range([height, 0]);
var yScale = d3.scaleLinear()
.range([height, 0]);
var xScale = d3.scaleLinear()
.range([0, width]);
var xAxis = d3.axisLeft(yScale);
var yAxis = d3.axisBottom(xScale);
var chart = d3.select(".chart")
.attr("width", width)
.attr("height", height);
chart.append("g")
.attr("transform", "translate(10, 0)")
.call(xAxis);
chart.append("g")
.attr("transform", "translate(0, 540)")
.call(yAxis);
d3.tsv(GIST, type, function(error, data) {
y.domain([0, d3.max(data, function(d) { return d.value; })]);
var barWidth = width / data.length;
var bar = chart.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d, i) {
return "translate(" + ((i * barWidth) + 10) + ",0)"; }
);
bar.append("rect")
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.attr("width", barWidth - 1);
bar.append("text")
.attr("x", (barWidth / 2) - 2)
.attr("y", function(d) { return y(d.value) + 3; })
.attr("dy", ".75em")
.text(function(d) { return d.value; });
});
function type(d) {
d.value = +d.value;
return d;
}
When you do this...
var bar = chart.selectAll("g").etc...
... you're selecting group elements that already exist in the SVG, which are the axes, and binding your data to them.
There are two easy solutions:
Move your code that creates the axes to the bottom of the d3.tsv, that is, after you have appended the bars.
Select something that doesn't exist, like
var bar = chart.selectAll(null).etc. To read more about the logic behind selectAll(null), have a look at my answer here.
histogram
I want to plot histogram using d3.js where i have dataset of around 13000 points which is divided into 2 clusters . I want to color both of them but when i use category color it only shows first one.In the input file i have Droplet_no, Amplitude, Cluster.
Here is my code :
<script type="text/javascript">
d3.csv("test_F06.csv",function type(d){
d.Droplet_no = +d.Droplet_no;
d.Amplitude = +d.Amplitude;
return d;} , function(data){
var width = 600;
height = 500;
padding = 50;
var colorColumn = "Cluster";
var map = data.map(function(i){return parseInt(i.Amplitude);})
var x = d3.scale.linear()
.domain([0, d3.max(map)])
.range([0, width]);
var xAxis = d3.svg.axis()
.scale(x);
var numbins = 3000;
var histogram = d3.layout.histogram()
.bins(x.ticks(numbins))
(map);
var y = d3.scale.linear()
.domain([0, d3.max(histogram.map(function(i){return i.length;}))])
.range([0, height/2]);
var colorScale = d3.scale.category10();
var canvas = d3.select("body").append("svg")
.attr("width", width+padding)
.attr("height", height+ padding)
.append("g")
.attr("transform", "translate(20,0)")
var bars = canvas.selectAll(".bar")
.data(histogram)
.enter()
.append("g")
.attr("class", "bar")
var group = canvas.append("g")
.attr("tansform","translate(0, " + height + ")")
bars.append("rect")
.attr("x", function(d){return x(d.x);})
.attr("y", function(d){return 500-y(d.y);})
.attr("width", function(d){return d.dx;})
.attr("height", function(d){ return y(d.y);})
.attr("fill", function(d){return colorScale(d[colorColumn]);});
})
</script>
Can anyone help me?
I am attaching image of the plot as well
I'm trying to get 2 completely different d3 charts (2 line charts but totally different data - one with several lines and negative data, other with one line positive data) on the same page.
Right now, I only get the first one to be generated and shown correctly on the HTML page, the second chart doesn't show at all (not even svg container is generated).
Here is my code:
(function() {
// Get the data
d3.json("../assets/js/json/temperature.json", function(data) {
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 25},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var valueline = d3.svg.line()
.x(function(d) { return x(d.temps); })
.y(function(d) { return y(d.temperature); });
// prepare data
data.forEach(function(d) {
d.temps = parseDate(d.temps);
d.temperature = +d.temperature;
});
// Adds the svg canvas
var svg = d3.select("#graphTemp")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Scale the range of the data on domain
x.domain(d3.extent(data, function(d) { return d.temps; }));
y.domain([0, d3.max(data, function(d) { return d.temperature; })]);
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Temperatures");
});
})();
(function(){
// loads the data and loads it into chart - main function
d3.json("../assets/js/json/maitrise.json", function(data) {
var m = {top: 20, right: 5, bottom: 30, left: 40},
w = 70 - m.left - m.right,
h = 30 - m.top - m.bottom;
var x = d3.scale.linear().domain([0, data.length]).range([0 + m.left, w - m.right]);
var y = d3.scale.linear()
.rangeRound([h, 0]);
var line = d3.svg.line()
.interpolate("cardinal")
.x(function(d,i) { return x(i); })
.y(function (d) { return y(d.value); });
var color = d3.scale.ordinal()
.range(["#28c6af","#ffd837","#e6443c","#9c8305","#d3c47c"]);
var svg2 = d3.select("#maitrisee").append("svg")
.attr("width", w + m.left + m.right)
.attr("height", h + m.top + m.bottom)
.append("g")
.attr("transform", "translate(" + m.left + "," + m.top + ")");
// prep axis variables
var xAxis2 = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis2 = d3.svg.axis()
.scale(y)
.orient("left");
//console.log("Inital Data", data);
var labelVar = 'id'; //A
var varNames = d3.keys(data[0])
.filter(function (key) { return key !== labelVar;}); //B
color.domain(varNames); //C
var seriesData = varNames.map(function (name) { //D
return {
name: name,
values: data.map(function (d) {
return {name: name, label: d[labelVar], value: +d[name]};
})
};
});
console.log("seriesData", seriesData);
y.domain([
d3.min(seriesData, function (c) {
return d3.min(c.values, function (d) { return d.value; });
}),
d3.max(seriesData, function (c) {
return d3.max(c.values, function (d) { return d.value; });
})
]);
var series = svg2.selectAll(".series")
.data(seriesData)
.enter().append("g")
.attr("class", function (d) { return d.name; });
series.append("path")
.attr("class", "line")
.attr("d", function (d) { return line(d.values); })
.style("stroke", function (d) { return color(d.name); })
.style("stroke-width", "2px")
.style("fill", "none");
});
})();
OK, I found where the error was coming from. There was a piece of javascript in the middle of the HTML page that stopped d3 to generate the second graph further down in the page.
Thanks for all the help!
My X-Axis tick number is scaling to the full width of the svg and not just the graph (without the margin area), so it overlaps.
http://i.stack.imgur.com/SHiIj.png The top image has margin so the labels are shown, the bottom one shows that with no margin, the ticks appear correctly
How can I make the X-axis ticks scale to the graph width instead of the svg width?
var margin = {top: 10, right: 0, bottom: 50, left: 0},
width = windowWidth * 0.28 - margin.left - margin.right,
height = 150 - margin.top - margin.bottom;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(4);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(4);
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.trials); });
var svg = d3.select("#data-graph").insert("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var masterLabelList = ['Total','Completed']
d3.tsv("/static/data.tsv" + '?time=' + new Date().getTime(), function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
data.forEach(function(d) {
d.date = new Date(+d.date);
});
var category = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, trials: +d[name]};
})
};
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(category, function(c) { return d3.min(c.values, function(v) { return v.trials; }); }),
d3.max(category, function(c) { return d3.max(c.values, function(v) { return v.trials; }); })
]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.style("fill", "#999999")
.call(xAxis);
Set margin's right property to a value greater than 0.
Then replace
var x = d3.time.scale()
.range([0, width]);
with
var x = d3.time.scale()
.range([0, width - margin.right]);