D3 put times in X axis instead of array value - javascript

This question is a bit tricky. I have some example code working with the following data. It plots it on a line graph.
var dataset = [{
y: 0.1
},
{
y: 0.6
},
{
y: 0.6
},
{
y: 0.7
}
];
D3 uses the following code to put this on the X axis:
var xScale = d3.scaleLinear()
.domain([0, n - 1]) // input
.range([0, width]); // output
However I'm really looking to get dat
var dataset = [{
"1pm": 0.1
},
{
"2pm": 0.6
},
{
"3pm": 0.6
},
{
"4pm": 0.7
}
];
How do I put these values into the graph X axis instead of it just being based on the array numbers? When I try the code as it is above it breaks the graph it says:
Error: <path> attribute d: Expected number, "M0,NaNC17.222222222…".
This is the full code:
http://jsfiddle.net/spadez/e6hv9x8m/17/

Here is your modified fiddle.
First off, you can include an additional value in your dataset objects to represent the x value, I've called this date:
var dataset = [{
y: 0.1,
date: new Date(2012,0,1)
},
{
y: 0.6,
date: new Date(2012,0,2)
}
];
Next, the x scale needs to be changed from linear to time:
var minDate = new Date(2012,0,1);
var maxDate = new Date(2012,0,2);
var xScale = d3.scaleTime()
.domain([minDate, maxDate])
.range([0, width]);
And finally, you must update the callback here to pull the date field from the dataset object, rather than just it's position in the array:
var line = d3.line()
.x(function(d, i) {
return xScale(d.date);
}) // set the x values for the line generator
.y(function(d) {
return yScale(d.y);
}) // set the y values for the line generator
.curve(d3.curveMonotoneX) // apply smoothing to the line

Related

Plotlyjs ticktext/tickvals not showing xaxis labels

I have been trying to utilize the tickvals/ticktext on plotlyjs to be able to show duplicate values on a graph for the xaxis. It works in the aspect of separating the data (having multiple duplicate values be on the xaxis, but a 1:1 data point) -- the issue that I am having is that no xaxis tick marks or xaxis labels show up for the ticks.
Here is a code pen of my problem:
https://codepen.io/hiquetj/pen/yLeBNjJ
Here is the code for easier reading:
var trace1 = {
y: [1323,1070,849,1312,1214,1264,680,2006,1625,0,1199,1770,1880,708,603,649,1384,732,2312,92,1377,1125,1219,1757,1207,2397,1190,1818,2846,1200,1685,1563,1203,1059,820,4303,812,3640,1924,4185,1269,2263,1140,1210,1638,1362,4915,1594,683,1222],
mode: 'markers'
};
var trace2 = {
y: [5870,1574,1372,2093,1361,1388,615,1927,947,,1040,,,638,546,542,1051,637,4161,289,1103,0,1308,1658,1340,2198,1245,1568,2392,1297,1583,1281,1282,697,482,3633,653,3233,2096,3815,1401,2116,867,1232,1420,1010,4091,478,208,1262],
mode: 'lines'
};
var trace3 = {
y: [1141,1324,424,668,414,407,494,1763,1100,,522,360,108,474,145,621,689,234,154,40,303,364,407,1133,347,1527,358,1745,1223,345,1131,1024,365,754,614,1894,287,5332,363,568,335,1545,1294,383,1255,1107,2090,612,66,390],
mode: 'lines+markers'
};
var data = [ trace1, trace2, trace3 ];
var layout = {
xaxis: {
ticktext: [24346247,24346247,24346247,24346247,24332892,24332892,24332892,24332670,24332670,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24316962,24316962,24316962,24290013,24290013,24290013,24290013,24290013,23738933,23738933,23738933,23738933,23738933,23738933,23738933,23738933,23738933,23738933,23738933,23738933,23738933,23738933],
tickvals: [24346247,24346247,24346247,24346247,24332892,24332892,24332892,24332670,24332670,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24330025,24316962,24316962,24316962,24290013,24290013,24290013,24290013,24290013,23738933,23738933,23738933,23738933,23738933,23738933,23738933,23738933,23738933,23738933,23738933,23738933,23738933,23738933],
},
};
Plotly.newPlot('myDiv', data, layout, {showSendToCloud: true});
Example of x axis labels not showing up through codepen.
If you do not set x values for your traces, they are automatically assigned x values from 0 to n. Your ticktexts will therefore only be visible if your tickval array is [0, 1, 2, 3, ..., n], see this jsFiddle: https://jsfiddle.net/9okdx4b2/

How to draw y-axis from nested array using d3.js?

I am playing with d3.js to draw a curve like the below. The below was drawn in Excel. As I am trying to achive the below result, I am facing an issue where my Y axis data lives in nested array and I am having a trouble to expose that.
Using the code below, I am able to get the x axis but whenever I try to bring my y axis, the data would come up as undefined.
var w = 900;
var h = 180;
var margin = {
'top': 5,
'right': 20,
'bottom': 20,
'left': 50
};
//creating axis
function buildLine(data) {
var xScale = d3.scale.linear()
.domain([100, d3.max(data, function(d) {
return d.spend;
})])
.range([margin.left, w - margin.right], 100);
/*var yScale=d3.scale.linear()
.domain([0,d3.max(data.arr,function(d){return d.y})])
.range([h-padding,10])
.nice();*/ //getting error as it is nested
var xAxisGen = d3.svg.axis().scale(xScale).orient("bottom").ticks(15);
/* var yAxisGen=d3.svg.axis().scale(yScale).orient("left");*/
var svg = d3.select("body").append("svg").attr({
width: w,
height: h
});
/*var yAxis= svg.append("g")
.call(yAxisGen)
.attr("class","axis")
.attr("transorm","translate("+padding+",0)");*/
var xAxis = svg.append("g")
.call(xAxisGen)
.attr("class", "axis")
.attr("transorm", "translate(" + padding + ",0)");
}
d3.json("sample-data.json", function(error, data) {
//check the file loaded properly
if (error) { //is there an error?
console.log(error); //if so, log it to the console
} else { //If not we're golden!
//Now show me the money!
ds = data; //put the data in the global var
}
buildLine(data);
data.forEach(function(jsonData) {
var lineData = d3.range(0, jsonData.spend, 100)
.map(x => [x, jsonData.alpha * (1 - 2.71828 * (-jsonData.beta * x))]);
/* console.log("this is the data:",lineData);*/
//i think line date returns an array with each item in it also an array of 2 items
var arr = [];
for (var i = 0; i < lineData.length; i++) {
arr.push({
x: lineData[i][0],
y: lineData[i][1]
});
}
jsonData.arr = arr;
console.log(jsonData);
});
});
*********The data structure as below ******************
So there is one object and there needs to be a line for each object and therefore each object has nested array which holds x, y and I need to get the Y to build y.axis. My brain feels like a marshmallow right now.
{x: 10000, y: 286.89585120000004}
{x: 10100, y: 288.364809712}
{x: 10200, y: 289.833768224}
{x: 10300, y: 291.30272673600007}
{x: 10400, y: 292.771685248}

How do you create a d3 line function that will draw 2 lines for x, y1, y2 data?

I have an array of data in this format:
var data = [{x:0,y1:1, y2:2}, {x:1, y1:2, y2:2},...]
I'd like to use d3 to plot this with the help of the line function.
So, I created 2 paths on my svg container...
var path1 = svg.append("path");
var path2 = svg.append("path");
Now, to draw the first line, I have used:
var lineFunction = d3.svg.line()
.x(function(d){return d.x}
.y(function(d){return d.y1}
.interpolate("linear")
and
path1.attr("d", lineFunction(data))
And that worked great. However, how do I now draw the second line? I can of course create a new lineFunction that returns d.y2 for the y value, but that goes completely against the DRY principle. I think my workflow is not quite the right way to do it, so may I ask how are you actually supposed to do it? In other words, how should I create a line function that will work with both the y1 and y2 data?
To expand on the commend from #Lars, the trick here is to first pivot your data to be an array of objects that each represents an individual line.
var newData = [
{
name: "y1",
points: [ { x:0, y:1},{x:1,y:2}]
},
{
name: "y2",
points: [ { x:0, y:2},{x:1,y:2}]
},
];
Your lineFunction can then operate generically on x and y:
var lineFunction = d3.svg.line()
.x(function(d){return d.x}
.y(function(d){return d.y}
.interpolate("linear")
You can then bind this data to the elements in your visualisation and add a path for each data entry:
var lines = svg.selectAll(".line").data(newData);
lines.enter().append("path")
.attr("class","line")
.attr("d",function(d) {
return lineFunction(d.points);
});

Updating Nvd3 chart priodically

I'm working with Nvd3 charts from the examples from their official website. Now I want a line chart to update periodically based on data sent from server but I couldn't found any useful Example for this on internet.
I have created a function which re-draws the chart when new data is arrived but i want to append every new point to the existing chart (like we can do in highcharts) but i'm stuck.
Here is the code I'm using for Updating the chart.
var data = [{
"key" : "Long",
"values" : getData()
}];
var chart;
function redraw() {
nv.addGraph(function() {
var chart = nv.models.lineChart().margin({
left : 100
})
//Adjust chart margins to give the x-axis some breathing room.
.useInteractiveGuideline(true) //We want nice looking tooltips and a guideline!
.transitionDuration(350) //how fast do you want the lines to transition?
.showLegend(true) //Show the legend, allowing users to turn on/off line series.
.showYAxis(true) //Show the y-axis
.showXAxis(true);
//Show the x-axis
chart.xAxis.tickFormat(function(d) {
return d3.time.format('%x')(new Date(d))
});
chart.yAxis.tickFormat(d3.format(',.1%'));
d3.select('#chart svg').datum(data)
//.transition().duration(500)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
}
function getData() {
var arr = [];
var theDate = new Date(2012, 01, 01, 0, 0, 0, 0);
for (var x = 0; x < 30; x++) {
arr.push({
x : new Date(theDate.getTime()),
y : Math.random() * 100
});
theDate.setDate(theDate.getDate() + 1);
}
return arr;
}
setInterval(function() {
var long = data[0].values;
var next = new Date(long[long.length - 1].x);
next.setDate(next.getDate() + 1)
long.shift();
long.push({
x : next.getTime(),
y : Math.random() * 100
});
redraw();
}, 1500);

D3 time scale from array index

I am attempting to map an array index to a time range in d3.js as I do not have individual dates for the array - I just know the values are between 1900 and 2000.
var data = [45,678,490...]; // length 820
var x = d3.time.scale().range([0, width]).domain([new Date(1900, 0, 0), new Date(2000, 0, 0)]);
// line function
var line = d3.svg.line()
.x(function(d,i) {
// here map i to date between domain min / max
return x(i);
})
.y(function(d) {
return y(d);
});
Is there a smarter way of doing this than manually calculating a date for each array value? Perhaps calculating the step and incrementing?
Use another scale to map from the index value to date:
var arrayScale = d3.time.scale()
.domain([0, data.length])
.range([new Date(1900, 0, 0), new Date(2000, 0, 0)]);

Categories