Change x scale of path dynamically d3.js - javascript

I am trying to change the x-scale of already plotted path in d3.js
Also, i am able to change the x-scale of circles using following code.
var s = d3.event.selection || xTimeScale.range();
xTimeScale.domain(s.map(xDateScale.invert, xDateScale));
d3.selectAll(".dot").transition().duration(10).attr("cx",function(d){ return xTimeScale(d.date); })
As you can see i have changed the domain of xTimeScale with new values. and then select all the circles with class(.dot) and replot the x and y with changed xTimeScale.
Now i also want to change the path with this new scale.
Here is the code when my path first plotted.
var lineFunction = d3.line().x(function(d) { return x(d.date); }).y(function(d) { return y(d.value); })
var lineGraph = svg.append("path").attr("d",lineFunction(data)).attr("stroke", "blue")
.attr("stroke-width", 2).attr("fill", "none").attr("class","dotsLine");

Since you're just changing the scale used by the line generator you don't need to rebind the data (by the way, I see that you are not binding any data), you just need to pass the new scale to the line generator and, then, update the d attribute of the path.
Look at this demo. There is a x scale, named xScale1, used by the line generator:
var line = d3.line()
.x(function(d) {
return xScale1(d)
})
When you click the button, the line generator uses another scale...
line.x(function(d) {
return xScale2(d)
})
... and the path d attribute is updated:
path.transition()
.duration(1000)
.attr("d", line(data));
Here is the demo:
var svg = d3.select("svg");
var data = [12, 130, 45, 60, 110, 21];
var yScale = d3.scaleLinear()
.domain(d3.extent(data))
.range([140, 10]);
var xScale1 = d3.scalePoint()
.domain(data)
.range([10, 290]);
var xScale2 = d3.scalePoint()
.domain(data.concat(d3.range(6)))
.range([10, 290]);
var line = d3.line()
.x(function(d) {
return xScale1(d)
})
.y(function(d) {
return yScale(d)
})
.curve(d3.curveBasis);
var path = svg.append("path")
.attr("d", line(data))
.attr("fill", "none")
.attr("stroke", "black");
d3.select("button").on("click", function() {
line.x(function(d) {
return xScale2(d)
})
path.transition()
.duration(1000)
.attr("d", line(data));
})
<script src="https://d3js.org/d3.v4.min.js"></script>
<button>Click me</button>
<br>
<svg></svg>

Related

d3 choropleth map colors

I'm trying to recreate the map shown here using D3 but I'm having trouble binning the values from my data and mapping them to colors. Currently I'm using scale.quantile that I believe sets the number of bins according to the range which should be 8 since I have 8 colors. So it would bin up the fertility values into 8 different bins and map each bin to each color but the colors are incorrect. In my data Sweden has a fertility rate of 1.89 and Russia 1.7 but they are the same color on my map which looks like this with my current code. What am I doing wrong?
var width5 = 700;
var height5 = 500;
buckets = 8,
colors = ['#ff1a1a','#ff471a','#ffd633','#ffff1a','#ccff33',' #66ff66','#00ff00',' #009900'];
var projection = d3.geo.mercator()
.center([ 13, 52 ])
.translate([ width5/2.5, height5/1.7 ])
.scale([ width5/1.5 ]);
var path = d3.geo.path()
.projection(projection);
var mapchart = d3.select("#mapchartarea")
.append("svg")
.attr("width", width5)
.attr("height", height5);
d3.json("data/europe_geo_fertility.json", function(error,collection) {
if(error) throw error;
console.log(d3.min(collection.features, function(d) { return d.properties.fertility;}))
// Sets color for each country according to fertility rate
var colorScale = d3.scale.quantile()
.domain([0, buckets -1, d3.max(collection.features, function(d) { return d.properties.fertility;})])
.range(colors);
// Draws Map
mapchart.selectAll("path")
.data(collection.features)
.enter()
.append("path")
.attr("d", path)
.attr("stroke", "rgba(8, 81, 156, 0.2)")
.attr("fill", "rgba(8, 81, 156, 0.6)")
.style("fill", function(d) { return colorScale(d.properties.fertility); });
// Adds name of each country
mapchart.selectAll("text")
.data(collection.features)
.enter()
.append("svg:text")
.text(function(d){
return d.properties.name;
})
.attr("x", function(d){
return path.centroid(d)[0];
})
.attr("y", function(d){
return path.centroid(d)[1];
})
.attr("text-anchor","middle")
.attr('font-size','6pt');
});

How do I make a scatter plot of lines in D3?

I have a series of paired xy coordinates that create 58 lines. I want to plot them on a Cartesian graph, values are between -5 and 5 on both axis, essentially making a scatter plot of lines. I have made something similar in matplotlib using the quiver function, but I want to be able to do this in D3. I would also like to be able to label each line, or each line that meets a length threshold. The code I have come up with below. Thanks.
var lisa = [["Eloy",0.0169808,-0.695317,-0.0510301,-0.6995938],
["Florence",-0.3465685,-0.6790588,-0.5869514,-0.6762134],
["Phoenix",0.677068,-0.5754814,-0.6052215,-0.6158059],
["Tucson",-0.663848,0.4111043,-0.6722116,0.011639]]
var w = 200;
var h = 200;
//create the svg element and set the height and width parameters
var svg = d3.select("div").select("div")
.append("svg")
.attr("height",h)
.attr("width", w)
.style("border", "1px solid black");
//Create the scale for the scatter plot
var xScale = d3.scale.linear()
.domain([d3.min(dataset, function(d) { return d[0];}),d3.max(dataset, function(d) { return d[0];})])
.range([-1,1]);
var yScale = d3.scale.linear()
.domain([d3.min(dataset, function(d) { return d[1];}),d3.max(dataset, function(d) { return d[1];})])
.range([-1,1]);
//This is the function that creates the SVG lines
var line = svg.selectAll("line")
.data(lisa)
.enter()
.append("line");
//This gets the cooresponding x,y cordinates from the dataset
line.attr("x1", function(d) {
return xScale(d[0]);
})
.attr("y1", function(d) {
return yScale(d[1]);
})
.attr("x2", function(d) {
return xScale(d[2]);
})
.attr("y2", function(d) {
return yScale(d[3]);
})
.attr("stroke", "black");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Your code has some problems:
First, your range right now ([-1, 1]) makes no sense. This should be the domain instead (I changed the ranges to [0, w] and [0, h]).
In your real code, the domain should be [-5, 5] and the range should be the limits of the plot, something like [leftLimit, rightLimit] and [topLimit, bottomLimit] (have in mind that, in an SVG, the 0 position for the y axis is the top, not the bottom).
Second, given this array:
["Tucson",-0.663848,0.4111043,-0.6722116,0.011639]
your x and y positions should be the indices 1,2,3 and 4, not 0, 1, 2 and 3.
Besides that changes, I added the labels:
var text = svg.selectAll(".text")
.data(dataset)
.enter()
.append("text");
text.attr("font-size", 10)
.attr("x", function(d) {
return xScale(d[1]);
})
.attr("y", function(d) {
return yScale(d[2]);
})
.text(d => d[0]);
Here is the demo with the corrections:
var dataset = [["Eloy",0.0169808,-0.695317,-0.0510301,-0.6995938],
["Florence",-0.3465685,-0.6790588,-0.5869514,-0.6762134],
["Phoenix",0.677068,-0.5754814,-0.6052215,-0.6158059],
["Tucson",-0.663848,0.4111043,-0.6722116,0.011639]];
var color = d3.scale.category10();
var w = 400;
var h = 300;
//create the svg element and set the height and width parameters
var svg = d3.select("body")
.append("svg")
.attr("height",h)
.attr("width", w)
.style("border", "1px solid black");
//Create the scale for the scatter plot
var xScale = d3.scale.linear()
.domain([-1,1])
.range([0,w]);
var yScale = d3.scale.linear()
.domain([-1,1])
.range([0,h]);
//This is the function that creates the SVG lines
var line = svg.selectAll("line")
.data(dataset)
.enter()
.append("line");
//This gets the cooresponding x,y cordinates from the dataset
line.attr("x1", function(d) {
return xScale(d[1]);
})
.attr("y1", function(d) {
return yScale(d[2]);
})
.attr("x2", function(d) {
return xScale(d[3]);
})
.attr("y2", function(d) {
return yScale(d[4]);
})
.attr("stroke-width", 2)
.attr("stroke", (d,i)=>color(i));
var text = svg.selectAll(".text")
.data(dataset)
.enter()
.append("text");
text.attr("font-size", 10)
.attr("x", function(d) {
return xScale(d[1])+2;
})
.attr("y", function(d) {
return yScale(d[2]) + 4;
})
.text(d=>d[0]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

updating multi series area graph in d3

I am creating an area graph using d3.
This code works, but I am not happy with the data structure in the update method (toggle), indeed I don't understand what I am doing wrong.
When creating the graph I pass in the data via:
data([nsw,qld])
// then draw the chart
When I update the graph I pass in the data via:
chart.data([nsw]);
// draw the nsw series in the chart
chart.data([qld]);
// draw the qld series in the chart
Surely I can update the data by passing it in in the correct format of [nsw,qld]
<script type="text/javascript" src="lib/d3.min.js" charset="utf-8"></script>
<svg id="chart"></svg>
<script>
var NSW = "NSW";
var QLD = "QLD";
var width = 400;
var height = 400;
var years = [1,2,3,4,5];
var data = years.map(function(){ return [Math.random(),Math.random()]; }); // generate bogus data
var nsw = data.map(function(d) { return d[0];}); // extract new south wales data
var qld = data.map(function(d) { return d[1];}); // extract queensland data
var chart = d3.select("#chart").attr("width", width).attr("height", height).append("g");
var x = d3.scale.linear().domain([0, years.length]).range([0, width]);
var y = d3.scale.linear().domain([0, d3.max(data, function(d){ return Math.max(d[0], d[1]); })]).range([height,0]);
var area = d3.svg.area().x(function(d,i) { return x(i); }).y0(height).y1(function(d, i) { return y(d); });
console.log([nsw,qld])
chart
.selectAll("path.area")
.data([nsw,qld]) // !!! here i can pass both arrays in.
.enter()
.append("path")
.attr("fill", "rgba(0,0,0,0.5)")
.attr("class", function(d,i) { return [NSW,QLD][i]; })
.attr("d", area);
chart.on("click", function() {
data = years.map(function(){return [ Math.random(),Math.random()];}); // switch in some new random data
var nsw = data.map(function(d) { return d[0];})
var qld = data.map(function(d) { return d[1];})
y.domain([0, d3.max(data, function(d){ return Math.max(d[0], d[1]); })]).range([height, 0]);
var svg = chart.transition();
/*
svg
.selectAll("path")
.data([nsw,qld]) // !!! this doesn't work.
.duration(750)
.attr("d", function(d) { return area(d); });
*/
chart.data([nsw]); // !!! here i'm only passing in one!
svg.select("path.NSW")
.duration(750)
.attr("d", function(d) {return area(d); });
chart.data([qld]); // !!! ...and then another
svg.select("path.QLD")
.duration(750)
.attr("d", function(d) { return area(d); });
});
</script>
Link to fiddle:
http://jsfiddle.net/MLA3x/
The problem is that you're using a transition in the update part and not a selection. That is, you're calling .data() on a transition, which you can't do. It works fine if you add the transition after updating the data:
chart
.selectAll("path")
.data([nsw,qld])
.transition()
.duration(750)
.attr("d", function(d) { return area(d); });
Complete demo here.

D3.js category color scale not working properly

So I have one view that creates paths and I'm trying to have it so that each line that I draw has a random color.
I'm currently doing this-
var color = d3.scale.category20();
//other code that does stuff
this.path = svg.append("path")
.attr("d", line(newData))
.style("stroke", function(d,i) {
var colorIndex = Math.random() * (20 - 0) + 0;
return color(colorIndex); })
.attr("fill","none")
.attr("class","line");
This does not draw lines with different colours. Further, when I do this
this.path = svg.append("path")
.attr("d", line(newData))
.style("stroke", function(d,i) {
return color(4); })
.attr("fill","none")
.attr("class","line");
The color is still blue.
Why is that happening?
This is happening because domain was not set -
d3.scale.category10() not behaving as expected
has the answer
I have set up a minimal fiddle to show you the proper way to set up the line function. I also changed the color scheme to category(10) to show more contrasting colors (you can still use category20 and see a difference in colors though). Here is the FIDDLE.
var lineFunction = d3.svg.line()
.x(function (d) {
return d.x;
})
.y(function (d) {
return d.y;
})
.interpolate("linear");

D3 lines getting rendered as polygons

I am trying to use D3 to render lines, but when I try to do this, the lines get rendered as polygons. I am not sure why. I included a screenshot to show you what it looks like.
Here is the code:
// Creates a time scale using the x_extent
// defined above
var x_scale = d3.time.scale()
.range([margin, width - margin])
.domain(x_extent);
// Creates a similarity scale using the y_extent.
// defined above.
var y_scale = d3.scale.linear()
.range([height - margin, margin])
.domain(y_extent);
// Construct a line.
var line = d3.svg.line()
.x(function(d) {
return x_scale(d.date);
})
.y(function(d) {
return y_scale(d.similarity);
});
// Render a line.
d3.select("svg")
.append("path")
.attr("d", line(data));
Try setting fill and stroke explicitly when appending the path, i.e.
d3.select("svg")
.append("path")
.attr("fill", "none")
.attr("stroke", "black")
.attr("d", line(data));

Categories

Resources