D3.js Multiple GeoJSON objects - javascript

I am trying to transition between two GeoJSON objects, but have been unable to find any information on how to include more than one GeoJSON file. I am happy with the final transformation, but cannot find anything on multiple GeoJSON files.
I can currently plot one map like so:
d3.json("goldatt2.json", function (data) {
var group = canvas.selectAll("g")
.data(data.features)
.enter()
.append("g")
var path = d3.geo.path().projection(d3.geo.equirectangular());
var areas = group.append("path")
.attr("d", path)
How would I change this so that two GeoJSON files are called and can be transformed?
I found this example, http://bl.ocks.org/mbostock/3081153 but in this example there is only GeoJSON object that is then transformed to a circle.

Getting the Data is separate task with respect to transforming it.
So you could, in theory, have multiple ajax calls to fetch the data you need before you decide to do whatever with that data.
Mike Bostock has a Queue implementation for this purpose.
If you are using JQuery with D3, you could look into Deferred an example of which is posted here.
Once you have the data-sets that you need, you can now decide how you want to transform the data or provide transitions between them.
Pseudo-code:
var files = ["file1.json", "file2.json"];
//Fetch Data for both files and create a data set object of this format
var dataset = {
"file1.json": {/*geojson data for file1*/},
"file2.json": {/*geojson data for file2*/}
}
for(var item in dataset) {
var data = dataset[item];
//Do whatever transformation you need
}

Related

Fetching and processing data with semicolon delimiters and no headers

I have had some trouble understanding the D3.JS fetch documentation:
My data source is:
20180601 000000;1.168200;1.168240;1.168140;1.168230;0;
20180601 000100;1.168220;1.168230;1.168190;1.168190;0;
20180601 000200;1.168180;1.168180;1.168080;1.168120;0;
20180601 000300;1.168130;1.168160;1.168130;1.168140;0;
where the format is:
%Y%m%d %H%M%S;number1;number2;number3;number4;number5;
My difficulties are:
Adding headers to the data
Dealing with semicolons as the delimiter instead of commas
1) From what I can work out I need to read the file without parsing it, then join a text string to the beginning of the file then finally parse the data.
d3.text(data.csv, function(error, textString){});
var headers = ["date","time","data1","data2"].join("\t");
d3.csv.parse(headers + textString);
2) I can use the dsv format and set the delimiter to semicolons?
d3.dsv(";", "text/plain")
The rough code I ended up with is:
var time_parse = d3.timeParse( '%Y%m%d %H%M%S');
var time_format = d3.timeFormat('%H%M');
d3.text(data.csv, function(error, textString){
var headers = ["time;number1;number2;number3;number4;number5;"].join("\t")
d3.csv.parse(headers + textString)
d3.dsv(";", "text/plain")
data.forEach(function(e,i){
data[i].time = time_parse(e.date);
})
})
Ideally I want the data to look like this when logged:
Time, Number1, Number2, Number3, Number4, Number5
00:00, 1.168200, 1.168240, 1.168140, 1.168230, 0
etc
What is the flaw in my thinking and can anyone offer advice on how to solve my problem and similar problems in the future?
Note: I am new to Javascript and d3 and although I have been able to work through most of the documentation involving drawing svgs, creating axis and scales, transitions etc with no problems, I am struggling to get my head around actually getting data from real sources (e.g the internet) and processing them into something workable. Please heavily critique anything I have said and offer advice, I want to learn.
It's not clear what version of d3 you are using, you reference the fetch API, but some of the code you have looks like d3v3 and v4 in the question code (which could be the problem) which doesn't use the fetch API. In any event, I'll go through v5, but also versions 4 and 3.
In all of these your thoughts look pretty close based on the code blocks you have. We need to:
we read in the dsv as text,
add headers (with an end of line \n),
and run everything through a dsv format function that will use a ; as a delimiter.
no need for d3.csv.parse though as in your question code block
In all the below I drop the date formatting for simplicity (oops, left it in the v5 demo).
Because of the use of d3-fetch module in d3v5, this approach is a bit different than the more closely related d3v3/v4 (closely related in that they both use the d3-request module, otherwise there's a fair bit of difference).
d3-fetch: d3v5
With d3v5, using the d3-fetch module the process could look like:
var dsv = d3.dsvFormat(";");
var headers = ["time;number1;number2;number3;number4;number5;\n"]
d3.text("dsv.dsv").then(function(text) {
var data = dsv.parse(headers+text);
console.log(data);
console.log(data.columns);
})
Example
d3-request: d3v4
There's a bit more flexibility with d3v4 for this.
If we look at the API docs, we see that d3.csv is equivalent to:
d3.request(url)
.mimeType("text/csv")
.response(function(xhr) { return d3.csvParse(xhr.responseText, row); });
(docs)
So if we create a new format with d3.dsvFormat we can run the content through the format and get our data, we can also tack on the headers in this process, all in one step:
var dsv = d3.dsvFormat(";");
var headers = ["time;number1;number2;number3;number4;number5;\n"]
d3.request("dsv.dsv")
.mimeType("text/plain")
.response(function(data) { return dsv.parse(headers + data.response) })
.get(function(data) {
// use data here:
console.log(data);
console.log(data.columns);
});
Example
This might be the more atypical approach, so we could emulate the way I did it with v5 above:
var psv = d3.dsvFormat(";");
var headers = ["time;number1;number2;number3;number4;number5;\n"]
d3.text("dsv.dsv", function(error,data) {
var data = psv.parse(headers + data.reponse)
console.log(data);
console.log(data.columns);
})
Example
d3-request: d3v3
As with the second option in d3v4 above and d3v5, we can parse in text and then run it through the dsv format function (here we only need to account for changes in d3 namespace between v3/v4):
var dsv = d3.dsv(";","text/plain");
var headers = ["time;number1;number2;number3;number4;number5;\n"]
d3.text("dsv.dsv", function(error,text) {
var data = dsv.parse(headers+text);
console.log(data);
// console.log(data.columns) // -> no columns property in v3
})
Example
Note
The ; at the end of each row will create an empty column as a value is expected after it before the next row.

creating D3 Word Cloud by using an array of json objects instead of reading from json file

I am quite new to D3 and I have a D3 word cloud template that reads from a json file and then creates a word cloud. The part that reads from json file and inputs the keys and values into chart is :
d3.json("testdata.json", data => {
var chart = renderChart()
.svgHeight(600)
.container('#myGraph')
.data({ values: data })
.responsive(true)
.run()
})
What I wish to do is populate this word cloud from an array of json objects that are created by the program dynamically during the program execution that is why I cannot write it into a json file manually.
One of the many codes that I tried to use was this:
test =>{
var chart = renderChart()
.svgHeight(600)
.container('#myGraph')
.data({ values: test})
.responsive(true)
.run()
}
where test is my array of json objects.
The code is working with no errors but it is displaying nothing.
Any help much appreciated !
Fixed! code has to be:
var chart = renderChart()
.svgHeight(600)
.container('#myGraph')
.data({ values: test})
.responsive(true)
.run()

Json to Map Unsing Amcharts

I need to creat a Tunisia map using Amcharts with my json data
Code in my json / id in tunisiaLow
nbre in my json / value in tunisialow
i change in tunisiaLow like my json data but not work
i need samthink like this
pic
pleas help me
this is my code in plunker plnkr.co/edit/6aDJREhcFYSfM5JW99mX?p=preview
The biggest issue with your code is that you modified the AmCharts map JS file in such a way that it completely breaks with the library. The JS files should not be modified unless you know what you're doing and follow the directions on creating your own map files tutorial. Your modified file removes the required id attribute that makes the map function.
Ideally you should modify your data to match the map format, not the other way around. Going by your last ticket, you seem to be unable to change your data, so the solution is the same as the last - remap your data to conform with AmCharts' format.
The original JS/SVG map has a list of IDs for each province. Since your dataset's titles don't exactly match the titles within the original map, you'll want to create a lookup object that uses your titles to link up to the internal map IDs, for example, using your French titles:
var areaDataMapping = {
"TUNIS": "TN-11",
"ARIANA": "TN-12",
"BEN AROUS": "TN-13",
"MANOUBA": "TN-14",
"NABEUL": "TN-21",
"ZAGHOUAN": "TN-22",
"BIZERTE": "TN-23",
"BEJA": "TN-31",
"JENDOUBA": "TN-32",
"KEF": "TN-33",
"SILIANA": "TN-34",
"KAIROUAN": "TN-41",
"KASSERINE": "TN-42",
"SIDI BOUZID": "TN-43",
"SOUSSE": "TN-51",
"MONASTIR": "TN-52",
"MAHDIA": "TN-53",
"SFAX": "TN-61",
"GAFSA": "TN-71",
"TOZEUR": "TN-72",
"KEBILI": "TN-73",
"GABES": "TN-81",
"MEDENINE": "TN-82",
"TATAOUINE": "TN-83"
};
From there, you can remap your parsed JSON file to create the correct area object array with the required properties such as id, title and value and then assign the result to your code:
var remappedAreas = AmCharts.parseJSON( areas ).map(function(area) {
return {
id: areaDataMapping[area.libelleFr],
title: area.libelleAr,
code: area.code,
value: area.nbre
}
});
var map = AmCharts.makeChart("...", {
// ...
"dataProvider": {
// ...
"areas": remappedAreas,
// ...
},
// ...
});
Here's an updated plunkr, which uses the official AmCharts JS for Tunisia instead of your version.

D3 : Retrieve data from SVG

Is it possible to retrieve data from an svg via d3?
I have following scenario:
on page Resize I need to update the widths of an svg which was generated on a server via d3 . So for example the x-axis. However the client side d3 library has no knowledge of the svg. I noticed that with each DOM object there is a __ chart__ object. Is there some way i can access the range and domain for example and update them accordingly?
When you create an SVG on the server and transfer it to the client, only the actual SVG DOM gets transferred, not any javascript objects or properties (such as the d3 __data__ property) that you used in creating it.
So in order to attach data to the SVG elements that actually gets passed with the file, you would need to create an attribute of that element that contains the data. Then you can select the element client side and parse the data attribute.
Example:
/*** Server Side ***/
/* if `bars` is a d3 selection of rectangles in a bar graph */
bars.attr("data-name", function(d){return d.name;})
.attr("data-value", function(d) {return d.value;});
/*** Client Side ***/
var bars = d3.selectAll("rect.bar")
.datum(function(){
return {
name: this.getAttribute("data-name"),
value: this.getAttribute("data-value")
}
})
.on("click", function(d,i){
/* do something with the data */
});
That works if the data in question is simply a few numbers or names that you want to use in tooltips or similar interaction. It doesn't work for a complex object like a chart function. If you're need to redraw/resize the chart client-side, I really don't see any performance benefit in trying to draw the graphs server-side.
You can create server scripts to parse all your data into a ready-to-use format, maybe even run the d3 layout functions to create a ready-to-draw JSON array. But then draw the graph client-side.

Drawing lines with geoJSON data in D3.js

I'm trying to draw US state outlines with the D3 framework (http://mbostock.github.com/d3/) but am having issues generating the actual SVG data. I've written my code to follow the Chloropleth example (as it most closely resembles what this project needs), made sure the supplied data is in geoJSON format, and AFAIK have the backend half of this working fine.
The problem is that when I view the DOM, the <svg> object contains only one <g> element (which I created manually, per the example), and none of the child <path> elements that should under it. My code seems fairly identical to the example, and my data appears to look correct, though I am outputting MultiPolygons instead of the Polygon object that the example uses.
Our app is a RoR project with jQuery (we're only using D3 for the SVG and geography features). The test page tries to create an <svg> element under a div called theArea, based upon the selection from a dropdown select of U.S. states:
$(document).ready( function() {
$("#chooser_state").change( function() {
var status = "#status";
var statebox = "#chooser_state";
var theArea = "#theArea"
var url = "/test/get_state_geom";
var data = { state: $(statebox).val() };
$(status).text("Request sent...");
$.post(url, jQuery.param(data), function(resp) {
$(status).text("Received response: " + resp["message"]);
$(theArea).empty();
var path = d3.geo.path();
var svg = d3.select(theArea).append("svg");
var state = svg.append("g").attr("id", "state_view");
var features = resp.payload.features;
$(status).text("Created SVG object");
state.selectAll("path")
.data(features)
.enter()
.append("path")
.attr("d", path );
});
});
});
The data we're feeding D3 looks like this:
{
'type' => 'Feature',
'id' => '01',
'properties' => {
'name' => 'Colorado'
},
'geometry' => {
'type' => 'MultiPolygon',
'coordinates' => [
[
[
[
-106.190553863626,
40.9976070173843
],
[
-106.061181,
40.996998999999995
],
< -- and so on -- >
]
]
]
}
}
Can someone clue me in to what we're doing wrong? I am new to geo and GIS stuff. I suspect the problem lies with the data() function, as it looks like it should be creating the blank <path> objects for each Feature (though we have only one, at the moment), but the D3 documentation seems unclear (and difficult to understand).
EDIT: Just wanted to add that the geoJSON we generate was created by the geoJSON extension for the GeoRuby gem. The actual map lines were sourced from the consolidated data that US Census Bureau's cartographic boundary files, which were converted to SQL and saved with postGIS. Part of me suspects the geoJSON extension is doing something wrong, so that is my next avenue of attack.
After giving up on this and then coming back, I noticed that my FeaturesCollection was not, in fact, a collection. There's a small detail that is easy to overlook when examining geoJSON samples: the contents of the FeaturesCollection is an array of hashes, not a single hash.

Categories

Resources