Points on a map with D3.js - javascript

I have a geoJSON of zip code centroid points that I am plotting on a D3.js map. I can get them to display but I am unable to adjust the size of the points. I was assuming that .attr("r", 1) would be doing that but I must be missing something.
d3.json("ZipPoints.json", function (zipPoints) {
svg.selectAll("g")
.data(zipPoints.features)
.enter()
.append("path")
.attr("d", path)
.attr("r", 1)
.style("fill", "red");
});
EDIT:
d3.json("ZipPoints.json", function (zipPoints) {
points.selectAll("circle")
.data(zipPoints.features)
.enter()
.append("circle")
.attr("r", 1.5)
.attr("transform", function(d, i) {
return "translate(" + projection(zipPoints.features[i].geometry.coordinates) + ")";
})
.style("fill", "red")
.classed("point", true);
});

You could try the following.
var pins = svg.append("g");
d3.json("ZipPoints.json", function(zipPoints) {
pins.selectAll("circle")
.data(zipPoints.features)
.enter()
.append("circle")
.attr("r", 5)
.style("fill", "red")
.classed("pin", true);
});
You may need transformation on these points to render them correctly (I guess).
In that case you could use the following bit of code. (The transformation function I used was required to plot data that had lat, long information on a map built using a specific projection).
.attr("transform", function(d) {
/*whatever transformation that needs to be done*/
return "translate(" + projection([ d.lon, d.lat ]) + ")";
})

Related

How can I get one circle for every three months

I'm using this link to learn D3.Js
I want to draw circles, but I want a circle for every three months
I tried to create a new data sub of the original data, but this didn't work
https://d3-graph-gallery.com/graph/area_lineDot.html
temp =[]
for (i=0; i< data.length; i=i+3) {
temp.push(data[i]);
}
I need to modify this code
svg.selectAll("myCircles")
.data(data)
.enter()
.append("circle")
.attr("fill", "red")
.attr("stroke", "none")
.attr("cx", function(d) { return x(d.date) })
.attr("cy", function(d) { return y(d.value) })
.attr("r", 3)
Try this:
svg.selectAll("myCircles")
.data(temp) // <---------- Use 'temp' instead of 'data'
.enter()
.append("circle")
.attr("fill", "red")
.attr("stroke", "none")
.attr("cx", function(d) { return x(d.date) })
.attr("cy", function(d) { return y(d.value) })
.attr("r", 3)
I got this working now the issue was the way I was reading the d.date and d.value the data has string need to be change to int
thank you Simon

d3.js line chart - updating the points values

How i can execute this code repetitively with a interval of 1 sec? The idea is update a d3.js line chart and move (smooth) the points in y axis of the chart.
Add line with random data:
var randomNumber = Math.floor(Math.random() * 6) + 1;
data = [
[{'x':0,'y':0},{'x':5,'y':0},{'x':10,'y':0},{'x':15,'y':3},{'x':20,'y':7},{'x':25,'y': randomNumber}]
];
var path = svg.selectAll('.d3-line')
.data(data)
.enter()
.append("path")
.attr("d", line)
.attr("class", "d3-line d3-line-medium")
.style('stroke-width', 3)
.style('stroke', function(d,i){
return colors[i%colors.length];
});
Add points of the line:
// Group dots
var points = svg.selectAll('.d3-dots')
.data(data)
.enter()
.append("g")
.attr("class", "d3-dots");
// Add dots
points.selectAll('.d3-dot')
.data(function(d, index) {
var a = [];
d.forEach(function(point,i) {
a.push({'index': index, 'point': point});
});
return a;
})
.enter()
.append('circle')
.attr('class', 'd3-dot')
.attr("r", 0)
.attr("transform", function(d) {
return "translate(" + x(d.point.x) + "," + y(d.point.y) + ")"; }
)
.style("fill", "#fff")
.style("stroke-width", 0)
.style('stroke', function(d,i){
return colors[d.index%colors.length];
})
.style("cursor", "pointer");
Regards,
Add this to your code to give line chart a smooth transition:
First add an id to the line as stated below:
var path = svg.selectAll('.d3-line')
.data(data)
.enter()
.append("path")
.attr("id", function(d,i){ return "line"+i;})
.attr("d", line)
.attr("class", "d3-line d3-line-medium")
.style('stroke-width', 3)
.style('stroke', function(d,i){
return colors[i%colors.length];
});
Following the above code add this below snippet:
d3.selectAll(".line").each(function(d,i){
// Get the length of each line in turn
var totalLength = d3.select("#line"+i).node().getTotalLength();
d3.select("#line"+i).attr("stroke-dasharray", totalLength + " " + totalLength)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(2000)
.delay(100*i)
.ease("linear") //linear, quad, bounce... other examples here - http://bl.ocks.org/hunzy/9929724
.attr("stroke-dashoffset", 0);
// .style("stroke-width",3)
});

D3JS Scatter plots refresh speed

I was wondering if there is a way to change the Scatter plots refresh speed?
As you can see in this link the scatter plots gets updated but the time gap between the appearance and disappearance is unreasonable, it look like they are flashing dots.... I tried moving the circle.remove() function right above the circle.transition but it makes no difference.
Below is the relevant code of the refresh function. Thanks!
function updateData() {
// Get the data again
data = d3.json("2301data.php", function(error, data) {
data.forEach(function(d) {
d.dtg = parseDate(d.dtg);
d.temperature = +d.temperature;
// d.hum = +d.hum; // Addon 9 part 3
});
// Scale the range of the data again
x.domain(d3.extent(data, function(d) { return d.dtg; }));
y.domain([0, 60]);
var svg = d3.select("#chart1").select("svg").select("g");
svg.select(".x.axis") // change the x axis
.transition()
.duration(750)
.call(xAxis);
svg.select(".y.axis") // change the y axis
.transition()
.duration(750)
.call(yAxis);
svg.select(".line") // change the line
.transition()
.duration(750)
.attr("d", valueline(data));
var circle = svg.selectAll("circle").data(data);
circle.remove() //remove old dots
// enter new circles
circle.enter()
.append("circle")
.filter(function(d) { return d.temperature > 35 })
.style("fill", "red")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.dtg); })
.attr("cy", function(d) { return y(d.temperature); })
// Tooltip stuff after this
.on("mouseover", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
div.transition()
.duration(200)
.style("opacity", .9);
div .html(
d.temperature + "C" + "<br>" +
formatTime(d.dtg))
.style("left", (d3.event.pageX + 8) + "px")
.style("top", (d3.event.pageY - 18) + "px");})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
circle.transition().attr("cx", function(d) { return x(d.dtg); });
// exit
circle.exit();
});
}
Looking at your example as it runs, you appear to have loads more circles in the dom than are visible. This is because you add circles for all the data, but then only give positions to those that meet the filter criteria you set.
There was a related question the other day about data filtering versus d3 filtering - Filtering data to conditionally render elements . Use data filtering if you don't want to add something full stop, use d3.filter if you want to isolate some elements for special treatment (transitions, different styling etc).
At the moment you're filtering the d3 selection once all the circles are added, but in your case I'd suggest filtering the data before it gets to that stage is best (and as suggested by others in that other question). This may make it run faster (but you're also at the mercy of db updates by the look of your example?)
data = data.filter (function(d) { return d.temperature > 35; }); // do filtering here
var circle = svg.selectAll("circle").data(data);
circle.exit().remove() //remove old dots
// enter new circles
circle.enter()
.append("circle")
.style("fill", "red")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.dtg); })
.attr("cy", function(d) { return y(d.temperature); })
...
PS. It's a bit confusing what you're trying to do with the circle.remove() and circle.exit(). circle.remove() will remove all existing circles (even ones that exist and have new data), circle.exit() at the end will then have no effect. I'd just have circle.exit().remove() to replace the two calls you make.
Also, without a key function - https://bost.ocks.org/mike/constancy/ - on your .data() call, you may find dots move around a bit. If your data points have ids, use them.
var circle = svg.selectAll("circle").data(data, function(d) { return d.id; /* or d.dtg+" "+d.temperature; if no id property */});
Thanks to mgraham the problem was solved.! Below is the revised code in case someone else needs it.
function updateData() {
// Get the data again
data = d3.json("data.php", function(error, data) {
data.forEach(function(d) {
d.dtg = parseDate(d.dtg);
d.temperature = +d.temperature;
});
// Scale the range of the data again
x.domain(d3.extent(data, function(d) { return d.dtg; }));
y.domain([0, 60]); // Addon 9 part 4
var svg = d3.select("#chart1").select("svg").select("g");
svg.select(".x.axis") // change the x axis
.transition()
.duration(750)
.call(xAxis);
svg.select(".y.axis") // change the y axis
.transition()
.duration(750)
.call(yAxis);
svg.select(".line") // change the line
.transition()
.duration(750)
.attr("d", valueline(data));
data = data.filter (function(d) { return d.temperature > 35; });
var circle = svg.selectAll("circle").data(data, function(d) { return d.dtg+" "+d.temperature;});
circle.exit().remove() //remove old dots
// enter new circles
circle.enter()
.append("circle")
.style("fill", "red")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.dtg); })
.attr("cy", function(d) { return y(d.temperature); })
// Tooltip stuff after this
.on("mouseover", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
div.transition()
.duration(200)
.style("opacity", .9);
div .html(
d.temperature + "C" + "<br>" +
formatTime(d.dtg))
.style("left", (d3.event.pageX + 8) + "px")
.style("top", (d3.event.pageY - 18) + "px");})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
circle.transition().attr("cx", function(d) { return x(d.dtg); });
});
}
</script>

How redraw labels in D3 maps?

I am following two tutorials to make a map in TOPOJson :
Display countries, borders and cities (dot & labels). Tutorial here.
Move and zoom the map. Tutorial here.
I am able to display the pan, to pan, to zoom, but the names of the cities are not redrawn.
var path = d3.geo.path()
.projection(projection)
.pointRadius(2);
/* What's hapenning here ? */
var svg = d3.select("#vis").append("svg:svg")
.attr("width", width)
.attr("height", height)
.call(d3.behavior.zoom().on("zoom", redraw));
/* Format projected 2D geometry appropriately for SVG or Canvas. */
d3.json("uk.json", function(error, uk) {
svg.selectAll(".subunit")
.data(topojson.feature(uk, uk.objects.subunits).features)
.enter().append("path")
.attr("class", function(d) { return "subunit " + d.id; })
.attr("d", path);
svg.append("path")
.datum(topojson.mesh(uk, uk.objects.subunits, function(a, b) { return a !== b && a.id !== "IRL"; }))
.attr("d", path)
.attr("class", "subunit-boundary");
svg.append("path")
.datum(topojson.mesh(uk, uk.objects.subunits, function(a, b) { return a === b && a.id === "IRL"; }))
.attr("d", path)
.attr("class", "subunit-boundary IRL");
svg.append("path")
.datum(topojson.feature(uk, uk.objects.places))
.attr("d", path)
.attr("class", "place");
svg.selectAll(".place-label")
.data(topojson.feature(uk, uk.objects.places).features)
.enter().append("text")
.attr("class", "place-label")
.attr("transform", function(d) { return "translate(" + projection(d.geometry.coordinates) + ")"; })
.attr("x", function(d) { return d.geometry.coordinates[0] > -1 ? 6 : -6; })
.attr("dy", ".35em")
.style("text-anchor", function(d) { return d.geometry.coordinates[0] > -1 ? "start" : "end"; })
.text(function(d) { return d.properties.name; });
svg.selectAll(".subunit-label")
.data(topojson.feature(uk, uk.objects.subunits).features)
.enter().append("text")
.attr("class", function(d) { return "subunit-label " + d.id; })
.attr("transform", function(d) { return "translate(" + path.centroid(d) + ")"; })
.attr("dy", ".35em")
.text(function(d) { return d.properties.name; });
});
function redraw() {
// d3.event.translate (an array) stores the current translation from the parent SVG element
// t (an array) stores the projection's default translation
// we add the x and y vales in each array to determine the projection's new translation
var tx = t[0] * d3.event.scale + d3.event.translate[0];
var ty = t[1] * d3.event.scale + d3.event.translate[1];
projection.translate([tx, ty]);
// now we determine the projection's new scale, but there's a problem:
// the map doesn't 'zoom onto the mouse point'
projection.scale(s * d3.event.scale);
// redraw the map
svg.selectAll("path").attr("d", path);
// redraw the labels
svg.selectAll(".place-label");
// redraw the x axis
xAxis.attr("x1", tx).attr("x2", tx);
// redraw the y axis
yAxis.attr("y1", ty).attr("y2", ty);
}
I have tried to add this line :
svg.selectAll(".place-label").attr("d", path);
in the redraw function but it did not worked.
Could you tell me which line should I add to refresh their positions ?
Here is my live code : Plunker live example & code
To make the labels move along with the map you need to do this:
On redraw function
svg.selectAll(".place-label")[0].forEach( function(d){
var data = d3.select(d).data()[0];//this will give you the text location data
d3.select(d).attr("transform", "translate("+projection(data.geometry.coordinates)+")" )//pass the location data here to get the new translated value.
});
For subunits do:
svg.selectAll(".subunit-label")
.attr("transform", function(d) { return "translate(" + path.centroid(d) + ")"; })
Working example here
Hope this works!

Changing the symbol in d3's GeoPaths MultiPoints

When I render latitude/longitude points (my_coords) on my globe with:
svg.append("path")
.datum({type: "MultiPoint", coordinates: my_coords})
.attr("class", "points")
.attr("d", path);
I get circles. I can change the color with CSS, but how can I change the symbol from circles to triangles? I've tried:
svg.append("path")
.datum({type: "MultiPoint", coordinates: my_coords})
.attr("class", "point")
.attr("d", d3.svg.symbol().type("triangle-up"));
But this doesn't work.
You can try this:
//define triangle
var arc = d3.svg.symbol().type('triangle-up');
// put a triangle on every city
svg.selectAll(".tripath")
.data(topojson.feature(uk, uk.objects.places).features)
.enter().append("path")
.attr('d',arc)
.attr("transform", function(d) {
return "translate(" + projection(d.geometry.coordinates) + ")"; });
Here the working code: http://jsfiddle.net/6d3ansfn/
Here the SVG Shape reference from Mike's github: https://github.com/mbostock/d3/wiki/SVG-Shapes#symbol
Example code is from Mike: http://bost.ocks.org/mike/map/
If you has a .tsv file width coordinates, use this:
svg.selectAll(".tripath")
.data( my_coords)
.enter().append("path")
.attr('d',arc)
.attr("transform", function(d) {
return "translate(" + projection(d) + ")"; });
remember update proyection on drag and/or zoom.

Categories