Projecting topoJSON using D3 shows tiny [duplicate] - d3.js

This question already has an answer here:
D3.js Map with Albers Projection: How to rotate it?
(1 answer)
Closed 3 years ago.
I have been pounding my head for several hours to how does my map shows super small in D3.
I've tried adjusting the scale but it doesn't seam to project correctly.
Here's my code.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Manda</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/topojson.v1.min.js"></script>
<style>
.states :hover {
fill: red;
}
.state-borders {
fill: none;
stroke: #fff;
stroke-width: 0.5px;
stroke-linejoin: round;
stroke-linecap: round;
pointer-events: none;
}
svg {
background: rgb(201, 197, 197);
}
</style>
</head>
<body>
<svg></svg>
</body>
<script>
var w = 960,
h = 600;
var svg = d3.select("svg");
svg.attr("width", w).attr("height", h);
var projection = d3
.geoAlbers()
.scale(200)
.translate([w / 2, h / 2]);
var path = d3.geoPath().projection(projection);
d3.queue()
.defer(d3.json, "NCR/Mandaluyong/MandaTopo.json")
.await(ready);
function ready(err, data) {
if (err) return console.log(err);
var brgys = topojson.feature(data, data.objects.Mandaluyong).features;
svg
.selectAll(".brgy")
.data(brgys)
.enter()
.append("path")
.attr("class", "brgy")
.attr("d", path)
.attr("stroke", "black");
}
</script>
</html>
I added an stroke to emphasize the map.
Here's the MandaTopo.json. https://raw.githubusercontent.com/popoy2k/MandaLightMap/master/NCR/Mandaluyong/MandaTopo.json
Here's what i see in the svg
Click me

The projection you're using is d3.geoAlbers, which the documentation says is:
a U.S.-centric configuration of d3.geoConicEqualArea
Since it looks like your data is in the Philippines, maybe a different projection would work better for you.
I tried replacing the line var projection = d3.geoAlbers... with the following, which seemed to work pretty well:
var projection = d3
.geoMercator()
.scale(900000)
.center([121.038505, 14.588329]);

Related

D3 Map not rendering on DOM (topojson file)

I think I've hit a wall here. Not sure why my map isn't displaying at all.
I've converted the topojson file to geojson with the topojson client (https://github.com/topojson/topojson-client/blob/master/README.md)
Here's my JS file (I'm seeing my #map and background color, but nothing is rendering inside.)
var width = 900,
height = 600;
var svg = d3.select('#map')
.append('svg')
.attr('width', width)
.attr('height', height);
var projection = d3.geoAlbersUsa()
var path = d3.geoPath()
.projection(projection);
d3.json("https://gist.githubusercontent.com/Lupi7000/d770ce6f2985c3a7bac1099688e4f772/raw/d327f59834fb0f9f2201ad71c3f1711ecb5bf6de/NYTest.json")
.then(function(d) {
console.log(d)
var counties = topojson.feature(d, d.objects.cb_2015_new_york_county_20m)
console.log(counties)
svg.selectAll('path').data(counties.features)
.enter().append('path')
.attr('d', path);
});
Here's my HTML
<html>
<head>
<meta charset="UTF-8">
<title> NYS Map</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="https://unpkg.com/topojson#3.0.2/dist/topojson.min.js"></script>
<script src="https://unpkg.com/topojson-client#3"></script>
<script src="NYmap.js"></script>
<link href="style.css" rel="stylesheet" type="text/css">
</head>
<body>
<h3> NYS MAP CLICKABLE AND SHIT... EVENTUALLY</h3>
<div id="map"><!-- MAP CONTAINER --></div>
</body>
</html>
And my stylesheet
body {
margin: 25px;
}
#map {
width: 900px;
height: 600px;
border: 1px solid black;
background: whitesmoke;
}
path {
fill: black;
}
Any help would be appreciated, thanks!
I've console logged my data so it's coming through, but I'm not sure what I need to do to make it show up.

Cannot get D3 .on('mouseover', ...) to work

I'm learning D3 and I'm trying to display data infomation on a scatterplot by hovering on the SVG circles. I take the data from a csv file (data is on the Solar System, with planet names, masses and radiuses) and all the circles show up correctly but when I try to console.log the data information (for instance the mass) on mouseover it does not log anything. The mouseover action is functioning OK but the console tells me that the value requested is "undefined".
Where did I mess up? This is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<style type="text/css">
body{
background-color: black;
}
#chart{
background-color: black;
width: 800px;
height: 500px;
border: solid 1px white;
}
svg{
background-color: white;
}
.dot{
stroke: red;
stroke-width: 1px;
}
</style>
<script type="text/javascript" src="https://d3js.org/d3.v6.min.js"></script>
</head>
<body>
<div id="chart"></div>
<script type="text/javascript">
var width = 800;
var height = 500;
var circles;
var svg = d3.select('#chart')
.append('svg')
.attr('width', width + 'px')
.attr('height', height + 'px');
d3.csv('astro.csv').then(function(data){
xScale = d3.scaleLinear()
.domain([0,500])
.range([0, 800]);
circles = svg.selectAll('.dot')
.data(data)
.enter()
.append('circle')
.attr('class', '.dot')
.attr('cx', function(d){
return xScale(d.mass);
})
.attr('cy', 100)
.attr('r', 20)
.on('mouseover', function(d){
console.log(d.mass);
})
});
</script>
</body>
</html>
Since D3 V6, all mouse event handlers has an event passed as the first argument and data as the second. In the V5 or earlier, your code will work.
V6 or higher:
.on('mouseover', (event, d) => console.log(d.mass));
V5 or earlier:
.on('mouseover', d => console.log(d.mass));

Why are my axes not positioning over my bar chart in this d3.js graph?

I am working on a project to teach myself d3.js where I'm building a bar graph using an API of US GDP. However, now that I've added my axes, the axes place where I expected them to. However, they have pushed my bars down below them. Can anyone explain to me why my axes and bars are behaving this way, and what I can do to fix this?
let apiUrl = "https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/GDP-data.json"
GDPGraph ()
function GDPGraph () {
fetch(apiUrl)
.then(response => response.json())
.then(data => {
// document.getElementById('GDP').innerHTML = JSON.stringify(data.data);
var width = document.documentElement.clientWidth,
height = document.documentElement.clientHeight * .8,
margin = 10;
var GDPbyQuarter = [],
yearQuarter =[]
const svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
for(i = 0; i < data.data.length; i++){
GDPbyQuarter.push(data.data[i][1])
}
for(i = 0; i < data.data.length; i++){
yearQuarter.push(data.data[i][0])
}
console.log(yearQuarter)
// console.log('calculated width:',((1/GDPbyQuarter.length)*width),'calculated legnth:', GDPbyQuarter.length, 'total width:', width)
const maxNumber = d3.max(GDPbyQuarter)
console.log(maxNumber);
const xScale = d3.scaleLinear()
.domain([0, GDPGraph.length])
.range([0, width]);
const yScale = d3.scaleLinear()
.domain([0, maxNumber])
.range([0, height]);
d3.select('body')
.selectAll('div')
.data(GDPbyQuarter)
.enter()
.append('svg')
.attr('class', 'bar')
.style('height', (d) => yScale(d)+'px')
.style('width', ((1/(GDPbyQuarter.length+margin)*width)+'px'))
.append('title')
.attr('class', 'title')
.text((d, i) => yearQuarter[i]+': ' + d)
const xAxis = d3.axisBottom(xScale);
const yAxis = d3.axisLeft(yScale);
svg.append("g")
.call(xAxis)
.attr("transform", "translate(0," + (height -100) + ")");
svg.append('g')
.attr('transform', 'translate(10,0)')
.call(yAxis)
})
}
.bar {
width: 25px;
height: 100px;
display: inline-block;
background-color: red;
}
.bar:hover {
background-color: blue;
}
.title {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://d3js.org/d3.v5.min.js"></script>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div>
<h1>US GDP By Quarter</h1>
<h3>FreeCodeCamp</h3>
</div>
<div id="GDP">
</div>
<script src='js/app.js'></script>
</body>
</html>
You are creating an svg node for each bar. Try inspecting the DOM using the Chrome Dev tools
The answer is that I had to fix my positioning. I ended up making the containing div position:relative; and then my elements within the div position:absolute;
#GDP {
position: relative;
}
#GDP > * {
position: absolute;
}
g {
position: absolute;
}

nvd3 line graph: How to create a sorted values on interactive guideline

I have a NVD3 line graph based on a json file. It seems that the interactive guideline is sorted by the order in which each series appears in the JSON file. Is there any way to make this tooltip sorted by y value (at any given x-value) in decending order? One way to do this would be to manually sort the order in which the series data appears in the JSON file but I'm hoping there is perhaps some attributes in the interactiveguideline that would allow me to do this in NVD3 directly?
My html file looks like this:
<html>
<head>
<meta charset="utf-8">
<link href="nvd3/build/nv.d3.css" rel="stylesheet" type="text/css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.2/d3.min.js" charset="utf-8"></script>
<script src="nvd3/build/nv.d3.js"></script>
<style>
text {
font: 12px sans-serif;
}
svg {
display: block;
}
html, body, #chart, svg {
margin: 0px;
padding: 0px;
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="chart" class='with-3d-shadow with-transitions'>
<svg></svg>
</div>
<script>
d3.json("distance.json",function(error,data) {
nv.addGraph(function() {
var chart = nv.models.lineWithFocusChart()
.x(function(d,i) { return d[0] })
.y(function(d,i) {return d[1] });
chart.xAxis.tickFormat (function(d) {
return d3.time.format('%x')(new Date(d))
});
chart.x2Axis.tickFormat (function(d) {
return d3.time.format('%x')(new Date(d))
});
chart.yAxis.tickFormat(d3.format(',.2f'));
chart.y2Axis.tickFormat(d3.format(',.2f'));
chart.useInteractiveGuideline(true)
;
d3.select('#chart svg')
.datum(data)
.transition().duration(500)
.call(chart)
;
nv.utils.windowResize(chart.update);
return chart;
});
});
</script>
</body>
</html>

Reading DOT files in javascript/d3

Is there a standard way to read and parse DOT graph files in javascript, ideally in way that will work nicely in d3?
Currently, the only thing I can think of doing is reading plain text and doing my own parsing. Hopefully this'd be reinventing the wheel though.
d3.text("graph.dot", function(error, dotGraph) {
....
)};
⚠ Solution proposed here depends on two libraries marked as unsupported by their authors.
To get Graphviz DOT files rendered in Javascript, combine the graphlib-dot and dagre-d3 libraries.
The graphlibDot.read() method takes a graph or digraph definition in DOT syntax and produces a graph object. The dagreD3.render() method can then output this graph object to SVG.
You can then use additional D3 methods to add functionality to the graph, retrieving additional node and edge attributes from the graphlib graph object as needed.
A trivial self-contained example is:
window.onload = function() {
// Parse the DOT syntax into a graphlib object.
var g = graphlibDot.read(
'digraph {\n' +
' a -> b;\n' +
' }'
)
// Render the graphlib object using d3.
var render = new dagreD3.render();
render(d3.select("svg g"), g);
// Optional - resize the SVG element based on the contents.
var svg = document.querySelector('#graphContainer');
var bbox = svg.getBBox();
svg.style.width = bbox.width + 40.0 + "px";
svg.style.height = bbox.height + 40.0 + "px";
}
svg {
overflow: hidden;
}
.node rect {
stroke: #333;
stroke-width: 1.5px;
fill: #fff;
}
.edgeLabel rect {
fill: #fff;
}
.edgePath {
stroke: #333;
stroke-width: 1.5px;
fill: none;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://dagrejs.github.io/project/graphlib-dot/v0.6.4/graphlib-dot.min.js"></script>
<script src="https://dagrejs.github.io/project/dagre-d3/v0.5.0/dagre-d3.min.js"></script>
<html>
<body>
<script type='text/javascript'>
</script>
<svg id="graphContainer">
<g/>
</svg>
</body>
</html>
Late to the party, but if you're still interested, here's a way to do it with the new d3-graphviz plug-in that I just released:
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="http://viz-js.com/bower_components/viz.js/viz-lite.js"></script>
<script src="https://github.com/magjac/d3-graphviz/releases/download/v0.0.4/d3-graphviz.min.js"></script>
<div id="graph" style="text-align: center;"></div>
<script>
d3.select("#graph").graphviz()
.renderDot('digraph {a -> b}');
</script>
Same example, using latest version of graphlib-dot and dagre-d3.
window.onload = function() {
// Parse the DOT syntax into a graphlib object.
var g = graphlibDot.read(
'digraph {\n' +
' a -> b;\n' +
' }'
)
// Render the graphlib object using d3.
var renderer = dagreD3.render();
d3.select("svg g").call(renderer, g);
// Optional - resize the SVG element based on the contents.
var svg = document.querySelector('#graphContainer');
var bbox = svg.getBBox();
svg.style.width = bbox.width + 40.0 + "px";
svg.style.height = bbox.height + 40.0 + "px";
}
svg {
overflow: hidden;
}
.node rect {
stroke: #333;
stroke-width: 1.5px;
fill: #fff;
}
.edgeLabel rect {
fill: #fff;
}
.edgePath {
stroke: #333;
stroke-width: 1.5px;
fill: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="http://cpettitt.github.io/project/graphlib-dot/latest/graphlib-dot.min.js"></script>
<script src="http://cpettitt.github.io/project/dagre-d3/latest/dagre-d3.js"></script>
<html>
<body>
<script type='text/javascript'>
</script>
<svg id="graphContainer">
<g/>
</svg>
</body>
</html>
The question asks for a possibility to visualise .dot files einther in javascript or D3js. I think the solution from the highest rated answer will work for most of you.
I was unhappy because of these 3 reasons:
It involves libraries like lowdash, dagre and graphlib additionally to D3js and is heavyweight.
Parser output is not a D3js "friedly" data-structure.
Usage (API) in not D3js style.
That's why I created an adapter which will basically allow you to use .dot files with any of thousands of D3js samples by changing just one statement. If you have some D3js visualisation working on following data-structure:
{
"nodes": [ {"id": "Myriel"}, {"id": "Napoleon"}],
"links": [ {"source": "Myriel"}, {"target": "Napoleon"}]
}
Just include following script and call d3.dot:
<script src="https://cdn.jsdelivr.net/gh/gmamaladze/d3-dot-graph#1.0.0/build/d3-dot-graph.min.js"></script>
<script>
d3.dot(url, function(graph) {
...
});
</script>
instead of:
d3.json(url, function(graph) {...});
GitHub repository with code and examples

Resources