How to match svg element ids with json keys - javascript

I have an svg (can be viewed here) to which I would like to present some data on click. The Data is in json format and I would like to match each id of svg element with key in json data if both of these are same then do something. For example if Json key is key: china and element id is china then present information of china from json. I have already extracted the desired format of data I just cannot figure out how to match these keys with the element ids.
This is how I am accessing the dataset
var countriesByName = d3.nest()
.key(function (d) {
return d.Country_Names;
})
.entries(data);
// creating dropdown
var data = JSON.stringify(countriesByName)
var data = JSON.parse(data);
//this is the key I would like to match with element ids:
var keys = function( d ) {
return d.key;
}
From this the format of json changes to
[{"key":"Albania",
"values": [{"Continent":"Europe",
"Country_Names":"Albania",
"Total":"3.8",
"Change_total":"-38.7",
"Main activity electricity and heat production":"0.1",
"Main activity electricity plants":"",
"Main activity CHP plants":"","Unallocated autoproducers / Other energy industry own use":"0.1",
"Other":"1.4",
"Manufacturing industries and construction":"1",
"Iron and steel":"0",
"Chemical and petrochemical":"0",
"Machinery":"",
"Mining and quarrying":"",
"Food and tobacco":"0.1",
"Paper, pulp and printing":"",
"Construction":"0",
"Transport":"2.2",
"Road":"2.2",
"Domestic aviation":"",
"Rail":"0",
"Domestic navigation":"0.1",
"Residential":"0.2",
"Commercial and public services":"0",
"Agriculture/forestry":"0.2",
"Sub-bituminous coal / Lignite":"",
"Other bituminous coal":"",
"Natural gas":"0",
"Motor gasoline excl. bio":"0.3",
"Gas/diesel oil excl. bio":"2.2"}]}
fiddle: https://jsfiddle.net/n5v84svm/47/

You can get the JSON data from the remote URL, then you can filter with any key value to get the particular data object form the data source. Please check the below code. Apologies if My solution is wrong for your problem.
//Get Data from the Remote URL
var countryData=$.get("https://gist.githubusercontent.com/heenaI/cbbc5c5f49994f174376/raw/c3f7ea250a2039c9edca0b12a530f108d6304e1c/data.json");
countryData=JSON.parse(countryData.responseText);
//this is the key I would like to match with element ids:
var keys = function( d ) {
var keyData=data.filter(function(value) { return value.Country_Names == d;});
return keyData;
}

Related

Creating array from csv with d3.group without group headers

I am trying to replicate the example here by Nadieh Bremer which is a radar chart made in D3.js.
The data structure which is used in Nadieh's example is:
var data = [
[//iPhone
{axis:"Battery Life",value:20},
{axis:"Brand",value:28},
{axis:"Contract Cost",value:29},
{axis:"Design And Quality",value:17},
{axis:"Have Internet Connectivity",value:22},
{axis:"Large Screen",value:02},
{axis:"Price Of Device",value:21},
{axis:"To Be A Smartphone",value:50}
],[//Samsung
{axis:"Battery Life",value:27},
{axis:"Brand",value:16},
{axis:"Contract Cost",value:35},
{axis:"Design And Quality",value:13},
{axis:"Have Internet Connectivity",value:20},
{axis:"Large Screen",value:13},
{axis:"Price Of Device",value:35},
{axis:"To Be A Smartphone",value:38}
],etc.
];
I want to bring in the data from a CSV file which is set-up like this:
axis,value,type
Battery Life,20,iPhone
Brand,28,iPhone
Contract Cost,29,iPhone
Design And Quality,17,iPhone
Have Internet Connectivity,22,iPhone
Large Screen,02,iPhone
Price Of Device,21,iPhone
To Be A Smartphone,50,iPhone
Battery Life,27,SAmsung
Brand,16,SAmsung
...etc.
In my script, I have:
var tmpArr;
d3.csv("data1.csv", (d) => {
tmp = d;
tmpArr = Array.from(d3.group(tmp, d => d.group));
console.log(tmpArr);
});
This obviously returns an array for each group with the title of the group as the first element of the array and then the contents of the group as the second element in the array.
I would be grateful for help to remove that first element so that I'm simply returned an array of the values I need. I'm pretty sure I need to use d3.map() but I just can't quite work out what to do with it. Thanks in advance.
You can just use a standard .map and for every pair returned from Array.from(d3.group(...)) return the 2nd item of that pair. For the 2nd item in each pair use index [1] because arrays are zero-based indices.
The working example aligns to the data structure in Nadieh Bremer's block:
const csv = `axis,value,type
Battery Life,20,iPhone
Brand,28,iPhone
Contract Cost,29,iPhone
Design And Quality,17,iPhone
Have Internet Connectivity,22,iPhone
Large Screen,02,iPhone
Price Of Device,21,iPhone
To Be A Smartphone,50,iPhone
Battery Life,27,SAmsung
Brand,16,SAmsung
Contract Cost,24,SAmsung
Design And Quality,14,SAmsung
Have Internet Connectivity,22,SAmsung
Large Screen,05,SAmsung
Price Of Device,15,SAmsung
To Be A Smartphone,48,SAmsung
`;
const data = d3.csvParse(csv);
const grouped = Array.from(d3.group(data, d => d.type));
const arrForViz = grouped.map(g => g[1]);
console.log(arrForViz);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>

How to Extract data based on the values in one array after matching the corresponding values from another array in JavaScript?

This is the URL from GeoServer to get feature info
{"type":"FeatureCollection","features":[{"type":"Feature","id":"weather_warning_day_1.fid--418ec0da_178b69d5dfc_-715c","geometry":null,"properties":{"issue_date":"2021-04-09","updated_at":"2021-04-09T09:26:33+05:30","utc_time":0,"state_name":"Odisha","state_id":21,"district_name":"MAYURBHANJ","district_id":232,"api_district_name":"MAYURBHANJ","day_1":"6,9,10","day1_color":3}}],"totalFeatures":"unknown","numberReturned":1,"timeStamp":"2021-04-09T15:38:19.536Z","crs":null}
the data I want to extract is of variable: "day_1":"6,9,10"
which I got from the layer and stored it in the variable as
var warning_day_1 = weather_warning_layer_data.features[0].properties.day_1
so basically the input is "day_1":"6,9,10"
which I have stored in the array as
[{"warning":"6"},{"warning":"9"},{"warning":"10"}]
and corresponding output should be Dust Storm, Heat Wave, Hot Day
Dust Storm, Heat Wave, Hot Day
or if the input was "day_1":"2,5"
then output should have been Heavy Rain, Hailstorm
or if the input was "day_1":"1"
then output should have been No Warning
After reading the data of the string and creating its array, I have to compare it with another array and extract the key values (display) corresponding to the key values (warning) in the 1st array.
var warning_data_split = warning_day_1.split(/[ ,]+/);
var warning_data_from_api_array = new Array;
warning_data_from_api_array.push(warning_data_split);
for (var i = 0; i < warning_data_from_api_array.length; i++) {
var item_in_array_to_compare = warning_data_from_api_array[i];
if(warning_data_from_api_array[item_in_array_to_compare.warning_data_from_api_array])
{warning_data_from_api_array[item_in_array_to_compare.warning_data_from_api_array].push(item_in_array_to_compare);}
else {
warning_data_from_api_array[item_in_array_to_compare.warning_data_from_api_array] = [item_in_array_to_compare];}}
let final_array_to_compare = item_in_array_to_compare
final_array_to_compare = final_array_to_compare.map(x => ({warning: x}));
/// this is the first array ////////////
The values in this array are not static in length, as it keeps on changing like, sometimes the array has value [1] or [1,2], [2,5,8], [4,7,12], etc
so I have to extract the corresponding values of display from the lookup array given below
var warning_code_meaning_list = [
{ warning:"1", display:"No Warning"},
{ warning:"2", display:"Heavy Rain"},
{ warning:"3", display:"Heavy Snow"},
{ warning:"4", display:"Thunderstorm & Lightning, Squall etc"},
{ warning:"5", display:"Hailstorm"},
{ warning:"6", display:"Dust Storm"},
{ warning:"7", display:"Dust Raising Winds"},
{ warning:"8", display:"Strong Surface Winds"},
{ warning:"9", display:"Heat Wave"},
{ warning:"10", display:"Hot Day"},
{ warning:"11", display:"Warm Night"},
{ warning:"12", display:"Cold Wave"},
{ warning:"13", display:"Cold Day"},
{ warning:"14", display:"Ground Frost"},
{ warning:"15", display:"Fog"}
]
The data which I am getting in warning_day_1 (in the very first line of the code) is a string (this couldn’t be saved as float/integer in the database column because sometimes there are more than 1 warning for a specific place, so I have stored this as a text in the database)
Which I’m converting to an array after reading it from the API
Now this string, which I am fetching from API has variable data,
Some time single digit like: 1
Sometime multiple : 1,2,3
And each of the integer present in this array corresponds to the specific text shown in the next array like if the warning is 2 it means the heavy rainfall,
but if the string (later converted to an array, with “warning” as a key) has 2,5 as value, it means: heavy rainfall & Hailstorm
I want that the values which come up in array 1 (the dynamic one) got match with the 2nd array ( a sort of lookup array) and fetch its display value as output.
How to do so?
You could use an object to map your warnings to messages.
Try this:
const data = {"type":"FeatureCollection","features":[{"type":"Feature","id":"weather_warning_day_1.fid--418ec0da_178b69d5dfc_-715c","geometry":null,"properties":{"issue_date":"2021-04-09","updated_at":"2021-04-09T09:26:33+05:30","utc_time":0,"state_name":"Odisha","state_id":21,"district_name":"MAYURBHANJ","district_id":232,"api_district_name":"MAYURBHANJ","day_1":"6,9,10","day1_color":3}}],"totalFeatures":"unknown","numberReturned":1,"timeStamp":"2021-04-09T15:38:19.536Z","crs":null}
var warning_code_meaning_list = {
"1":"No Warning",
"2":"Heavy Rain",
"3":"Heavy Snow",
"4":"Thunderstorm & Lightning, Squall etc",
"5":"Hailstorm",
"6":"Dust Storm",
"7":"Dust Raising Winds",
"8":"Strong Surface Winds",
"9":"Heat Wave",
"10":"Hot Day",
"11":"Warm Night",
"12":"Cold Wave",
"13":"Cold Day",
"14":"Ground Frost",
"15":"Fog",
};
results = data["features"].map(feature => {
return feature.properties.day_1.split(',').map(code => {
return warning_code_meaning_list[code];
});
});
That gives you an array of arrays of the displays:
[ [ 'Dust Storm', 'Heat Wave', 'Hot Day' ] ]

Construct multi column table from key,value pairs

I have the following JSON coming from a database table
[{"name":"field1","value":Jim,"tieRef":1},{"name":"field2","value":120.11,"tieRef":1},
{"name":"field3","value":AAA,"tieRef":1},{"name":"field1","value":Stacy,"tieRef":2},
{"name":"field2","value":34.10,"tieRef":2},{"name":"field3","value":BBB,"tieRef":2}]
And I need to construct an HTML table which looks like the below. The values related to the same row should be identified by the tieRef attribute.
field1 | field2 | field3
-------------------------
JIm | 120.11 | AAA
-------------------------
Stacy | 34.10 | BBB
Column names should be extracted from the "name" attribute. For extracting and summarizing the values under a single column I used the d3.js as listed below
var transformed = d3.nest()
.key(function(d) { return d.name; })
.object(data);
By using this I was able to transform the original JSON in to the following
{"field1":[
{"name":"field1","value":"Jim","tieRef":1},
{"name":"field1","value":"Stacy","tieRef":2}],
"field2":[
{"name":"field2","value":120.11,"tieRef":1},
{"name":"field2","value":34.1,"tieRef":2}],
"field3":[
{"name":"field3","value":"AAA","tieRef":1},
{"name":"field3","value":"BBB","tieRef":2}]}
But I'm not sure this the correct transformation needed to make it easier for constructing the HTML table. Please suggest a better transformation of the JSON so I can loop through and construct the table
Does anyone know how to achieve this in an elegant way?
Key on tieRef and then on name worked really well for transforming the JSON. first do the below using d3
var data = [{"name":"field1","value":"Jim","tieRef":1},
{"name":"field2","value":120.11,"tieRef":1},
{"name":"field3","value":"AAA","tieRef":1},
{"name":"field1","value":"Stacy","tieRef":2},
{"name":"field2","value":34.10,"tieRef":2},
{"name":"field3","value":"BBB","tieRef":2}];
var transform = d3.nest()
.key(function(d) { return d.tieRef; })
.key(function(d) { return d.name; })
.object(data);
This will transform the JSON in to the below.
{"1":
{"field1":
[{"name":"field1","value":"Jim","tieRef":1}],
"field2":
[{"name":"field2","value":120.11,"tieRef":1}],
"field3":
[{"name":"field3","value":"AAA","tieRef":1}]
},
"2":
{"field1":
[{"name":"field1","value":"Stacy","tieRef":2}],
"field2":
[{"name":"field2","value":34.1,"tieRef":2}],
"field3":
[{"name":"field3","value":"BBB","tieRef":2}]
}
}
This is then iterated by the row number 1,2,.. and constructed the table or further transform the JSON

Collecting arrays from JSON object and element class names and comparing them

I have an external JSON feed that displays room bookings for multiple rooms. The problem is that it only shows the timeslots that are booked and does not show empty slots/appointments in the data object. Issue is the feed does not contain the empty timeslots that have not been booked yet.
So I came up with an idea to have a preformatted HTML 'template' page with some data already present - effectively to overlay the JSON data in the booked timeslots and leave the empty timeslots as just static HTML.
Idea was to name the <td> elements with a class name that denotes the room id and the timeslot in 24hr time. Then to construct an array based on all the <td> class names. Then filter my JSON object bookings times and retrieve back an array that contained the room id and booking start time (amongst other necessary data).
Next step is to loop through both arrays and if there is a match against the room id and booking start time across both arrays, then print the data into that cell (which can be accessed via its class name). Right now, I am having problems with getting the arrays to look the same.
The 'simplified' JSON file (just a selection of whole object):
var response={
"bookings": {
"group_id": 12306,
"name": "Public Meeting Rooms",
"url": "http:theurlfeed.from.libcal",
"timeslots": [{
"room_id": "36615",
"room_name": "Meeting Room 2A",
"booking_label": "Mahjong",
"booking_start": "2016-01-20T10:00:00+10:00",
"booking_end": "2016-01-20T11:00:00+10:00"
}, {
"room_id": "36615",
"room_name": "Meeting Room 2A",
"booking_label": "Mahjong",
"booking_start": "2016-01-20T11:00:00+10:00",
"booking_end": "2016-01-20T12:00:00+10:00"
}, {
"room_id": "36616",
"room_name": "Meeting Room 2B",
"booking_label": "IELTS",
"booking_start": "2016-01-20T10:00:00+10:00",
"booking_end": "2016-01-20T11:00:00+10:00"
}, {
"room_id": "36616",
"room_name": "Meeting Room 2B",
"booking_label": "recording",
"booking_start": "2016-01-20T12:00:00+10:00",
"booking_end": "2016-01-20T13:00:00+10:00"
}, {
"room_id": "36616",
"room_name": "Meeting Room 2B",
"booking_label": "Luke",
"booking_start": "2016-01-20T18:00:00+10:00",
"booking_end": "2016-01-20T19:00:00+10:00"
}],
"last_updated": "2016-01-20T12:40:36+10:00"
}
}
Here is the HTML (for the sake of simplification I haven't shown the complete structure):
<table border="1" id="rooms-table">
<thead><tr><th></th> <th>10am</th><th>11am</th><th>12pm</th><th>1pm</th><th>2pm</th><th>3pm</th><th>4pm</th><th>5pm</th><th>6pm</th><th>7pm</th></tr></thead>
<tbody id="main-table-body">
<tr>
<td>Meeting Room 2A</td>
<td class="36615 10:00"></td>
<td class="36615 11:00"></td>
<td class="36615 12:00"></td>
</tr>
<tr>
<td>Meeting Room 2B</td>
<td class="36616 10:00"></td>
<td class="36616 11:00"></td>
<td class="36616 12:00"></td>
</tr>
<tr>
</tbody>
</table>
And this is my JavaScript (contains pseudo code at the bottom for concepts I have not yet coded):
//Convert timestamp to readable format and remove date
var Timeslots = response.bookings.timeslots;
function getTime(timestamp) {
var time = new Date(timestamp);
return [ time.getHours(), time.getMinutes() ].map(function(time){
return ['', "0"][+(String(time).length < 2)] + String(time);
}).join(':');
}
for(var i in Timeslots) (function(Timeslots){
Timeslots.booking_start = getTime(Timeslots.booking_start);
Timeslots.booking_end = getTime(Timeslots.booking_end);
})(Timeslots[i]);
console.log(response);
var roomList = new Array;
var tdClassList;
//function to detect if timeslot is booked or not
//If booked, assigns the booking name and changes bg color of cell
$.each(response.bookings.timeslots, function(index, timeslot) {
var roomBooking = timeslot.room_id + ' ' + timeslot.booking_start;
roomList[roomBooking] = roomBooking;
tdClassList = $('td').map(function () {
return $(this).attr('class');
}).get();
});
console.log(tdClassList);
console.log(roomList);
// This code is incomplete
// It will need to loop through both arrays and compare values and then write some css and html if match is found across the arrays
/*if (roomList == tdClassName) {
$( "td" ).html(timeslot.booking_label)
$( "td" ).css( "background-color", "red" );
} else { $( "td" ).html("");
}*/
Here is a link to a working JS Fiddle showing all elements in play: https://jsfiddle.net/coolwebs/L0ybd0dm/1/
My issue right now is that the array that is being created from the JSON object is coming in as key value pairs.
Instead of returning:
["36615 10:00", "36615 11:00", "36615 12:00", "36615 30:00", ...]
It is returning:
[36615 10:00: "36615 10:00",36615 11:00: "36615 11:00", 36615 12:00: "36615 12:00", 36615 13:00: "36615 30:00", ...]
Um, what am I doing wrong?
This is far from perfect or complete but does simplify your process somewhat.
I don't see any need to create the cell array. Once you have parsed the incoming data, you can loop over the cells and do the matching right away.
I used a simple object to make the room/start comparison.
// example
var timeClasses ={"3456 02:00":true, "56854 11:00": true}
Then when you loop through the table it's a simple check to see if the property matching your cell classes exists
success: function(response) {
var data = response.bookings.timeslots;
var timeClasses = {};
var Timeslots = data.map(function(item) {
// parse the dates
item.booking_start = getTime(item.booking_start);
item.booking_end = getTime(item.booking_end);
// update hashmap
timeClasses[item.room_id + ' ' + item.booking_start] = true;
return item;
});
$('tbody tr').each(function() {
$(this).find('td:gt(0)').each(function() {
var className = $(this).attr('class');
if (timeClasses[className]) {
$(this).css('background', 'red')
}
});
});
}
This is really only intended to give you a starting point.
I don't really like the classes methodology ...especially with the space in them.
You will also need to revisit how you will visualize the full timeslot that a booking covers and will need some more logic to apply for the cells in middle of each booking
DEMO

How to parse dynamic json data?

I am using wikipedia API my json response looks like,
"{
"query": {
"normalized": [
{
"from": "bitcoin",
"to": "Bitcoin"
}
],
"pages": {
"28249265": {
"pageid": 28249265,
"ns": 0,
"title": "Bitcoin",
"extract": "<p><b>Bitcoin</b>isapeer-to-peerpaymentsystemintroducedasopensourcesoftwarein2009.Thedigitalcurrencycreatedandlikeacentralbank,
andthishasledtheUSTreasurytocallbitcoinadecentralizedcurrency....</p>"
}
}
}
}"
this response is coming inside XMLHTTPObject ( request.responseText )
I am using eval to convert above string into json object as below,
var jsonObject = eval('(' +req.responseText+ ')');
In the response, pages element will have dynamic number for the key-value pair as shown in above example ( "28249265" )
How can I get extract element from above json object if my pageId is different for different results.
Please note, parsing is not actual problem here,
If Parse it , I can acess extract as,
var data = jsonObject.query.pages.28249265.extract;
In above line 28249265 is dynamic, This will be something different for different query
assuming that u want to traverse all keys in "jsonObject.query.pages".
u can extract it like this:
var pages = jsonObject.query.pages;
for (k in pages) { // here k represents the page no i.e. 28249265
var data = pages[k].extract;
// what u wana do with data here
}
or u may first extract all page data in array.
var datas = [];
var pages = jsonObject.query.pages;
for (k in pages) {
datas.push(pages[k].extract);
}
// what u wana do with data array here
you can archive that using two methods
obj = JSON.parse(json)
OR
obj = $.parseJSON(json);
UPDATE
Try this this
var obj = JSON.parse("your json data string");
//console.log(obj)
jQuery.each(obj.query.pages,function(a,val){
// here you can get data dynamically
var data = val.extract;
alert(val.extract);
});
JSBIN Example
JSBIN

Categories

Resources