Read csv data with D3.csv, each column in separate array - html

I'm new to working D3.js and html/js in general and I'm trying to figure out how to read in a csv file into separate arrays using d3.csv. I have a csv file that looks like this:
cause, prevalence, disability;
cancer, .3, .4;
aids, .5, .5;
malaria, .2, .1;
For now, I'm struggling with creating arrays for "cause", "prevalence", and "disability. Here is the code that I am using:
<html>
<script type="text/javascript" src="../d3/d3.js"></script>
<script type="text/javascript" src="../d3/d3.csv.js"></script>
<script type="text/javascript">
d3.csv('disability.csv', function(csv){
var cause=csv[0];
var prevalence=csv[1];
var disability=csv[2];
for (i=0;i<cause.length;i++)
{
document.write(cause[i] + "<br />");
}
})
</script>
</html>
The document.write portion is simply to test that I have read in the data.

It looks like you mean var cause = csv[0] to refer to the first variable/column, I'm guessing? Without seeing the csv file it's hard to know for sure.
If that's the case, the reason it's not working is javascript arrays unfortunately don't have easy ways of accessing a single variable/column.
csv[0] instead refers to the first row of your csv. In the case of d3's csv module, it'll be a dictionary with keys for each variable (column name) in the csv, e.g.:
console.log(csv[0]);
{ cause: 'A', prevalence: .1, disability: .5 }
So if you want to create separate arrays for each variable/column, you could do something like this:
var cause = [],
prevalence = [],
disability = [];
csv.map(function(d) {
cause.push(d.cause);
prevalence.push(d.prevalence);
disability.push(d.disability);
}
Then you'd be left with the three arrays it looks like you're trying to make. But in d3 you can probably actually just pass the entire csv object as the data to whatever you're creating and then use an accessor function [e.g. .attr('y', function(d) { return d.prevalence; })] to use a specific column/variable in a particular context.

Related

How to get clean json from wikipedia API

I want to get the result from a wikipedia page https://en.wikipedia.org/wiki/February_2 as JSON.
I tried using their API: https://en.wikipedia.org/w/api.php?action=parse&page=February_19&prop=text&formatversion=2&format=json
Though it is giving it as Json format. The content is HTML. I want only the content.
I need a way to get clean result.
If you want plain text without markup, you have first to parse the JSON object and then extract the text from the HTML code:
function htmlToText(html) {
let tempDiv = document.createElement("div");
tempDiv.innerHTML = html;
return tempDiv.textContent || tempDiv.innerText || "";
}
const url = 'https://en.wikipedia.org/w/api.php?action=parse&page=February_19&prop=text&format=json&formatversion=2&origin=*';
$.getJSON(url, function(data) {
const html = data['parse']['text'];
const plainText = htmlToText(html);
const array = [...plainText.matchAll(/^\d{4} *–.*/gm)].map(x=>x[0]);
console.log(array);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Update: I edited the code above according to the comment below. Now the function extracts all the list items putting them into an array.
I guess by clean you mean the source wikitext. In that case you can use the revisions module:
https://en.wikipedia.org/w/api.php?action=query&titles=February_2&prop=revisions&rvprop=content&formatversion=2&format=json
See API:Get the contents of a page and API:Revisions for more info.

How do I format my AngularJS data model?

Hi I am just beginning with angular and I am struggling to find the answer to what I'm sure is quite a simple thing to do.
I am currently getting the values of some input boxes and pushing them into my scope. This is creating one long 'array' eg:
['data-1','data-2','data-3']
I would like to format my data in the following way instead
$scope.data = [
{
'header1': 'data1-1',
'header1': 'data1-2',
'header1': 'data1-3'
},
{
'header1': 'data2-1',
'header1': 'data2-2',
'header1': 'data2-3'
}
]
This is my function as it currently is.
$scope.createRow = function(){
angular.forEach(angular.element("input"), function(value, key){
$scope.td.push($(value).val());
});
}
Any help or pointers would be greatly appreciated as I am just getting my head round the angular way
Doing this isn't hard... but before I give you a gun to shoot yourself in the foot, just to say that I think it would be beneficial to explain WHY you want structure in that other format you are mentioning. You seem to have lots of data repetition and that's always a red flag.
Now for the code, you just need to create object before pushing it to the array like:
$scope.createRow = function(){
angular.forEach(angular.element("input"), function(value, key){
var obj = {
"header1": val + "-1",
"header2": val + "-2"
};
$scope.td.push(obj);
});
}
EDIT:
OK, so you are trying to add new row to the table. First of all, you shouldn't be doing angular.forEach, but rather those input elements in HTML should bind to existing scope object, like:
// obviously use better names than Input1Value
// I am here just giving you example
$scope.bindData = {
Input1Value: null,
Input2Value: null
};
// in HTML you will do
// <input ng-model="bindData.Input1Value" />
// <input ng-model="bindData.Input2Value" />
Now that you've eliminated that nasty angular.forEach you need to have some kind of event handler, for example when user clicks the button you want to add this object to the array to which table is data bound. Just be sure to clone the $scope.bindData object when you add it to array.
$scope.createRow = function(){
var newRowData = $scope.cloneObject($scope.bindData);
$scope.td.push(newRowData);
}
// http://heyjavascript.com/4-creative-ways-to-clone-objects/
// https://stackoverflow.com/questions/728360/most-elegant-way-to-clone-a-javascript-object
$scope.cloneObject = function(objToClone) {
var newObj = (JSON.parse(JSON.stringify(objToClone)));
}
To close this answer off - keep in mind, if you ever find yourself directly referencing HTML DOM elements in Javascript with AngularJS - you are doing something wrong. It's a nasty habit to eliminate, especially if you are coming from jQuery background (and how doesn't?), where everything is $("#OhHiThere_ElementWithThisId).
Obviously the main thread on this topic on StackOverflow is this one:
“Thinking in AngularJS” if I have a jQuery background?
However I find that it's too theoretical, so Google around and you may find better overviews like:
jQuery vs. AngularJS: A Comparison and Migration Walkthrough

Initiate D3.js data map with new data

I'm going with the basic example in here except I need to be able to update the map based on new data (a json file.) I couldn't find a way to load the data directly inside Datamap object, so I'm loading it with D3.json and using the command to update the map. For some reason the popupTemplate function is receiving null data object and I don't know how to fix it.
What's the best way to do this?
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script src="http://datamaps.github.io/scripts/datamaps.world.min.js"></script>
<script src="http://datamaps.github.io/scripts/topojson.js"></script>
<div id="container" style="position: relative; width: 500px; height: 300px;"></div>
<script>
var data;
var map = new Datamap({
element: document.getElementById('container'),
fills: {
HIGH: '#afafaf',
LOW: '#123456',
MEDIUM: 'blue',
UNKNOWN: '#FFFFFF',
defaultFill: 'green'
},
geographyConfig: {
popupTemplate: function(geo, data) {
console.log(data)
return ['<div class="hoverinfo"><strong>',
'Number of things in ' + geo.properties.name,
': ' + data[geo.id].numberOfThings,
'</strong></div>'].join('');
}
}
});
map.legend();
d3.json("path/to/data.json", function(error, json) {
if (error) return console.warn(error);
data = json;
map.updateChoropleth(data);
});
</script>
This is my json file:
{
"IRL": {
"fillKey": "LOW",
"numberOfThings": "2002"
},
"USA": {
"fillKey": "MEDIUM",
"numberOfThings": "10381"
}
}
To make it easier to debug, I put on jsfiddle
I did not have problems loading the data directly inside Datamap. In any case, I also simulated a data update...the color gets updated but not the value (numberOfThings). In the example in the tutorial, it is not clear this can be done although it would make sense that one should be able to update values.
I am leaving you with the FIDDLE showing the results of my experiment.
A couple of notes:
I believe your popup was not showing because its return string needs
to be data.numberOfThings.
If I am not mistaken when I played with this before, if you don't have data for a country, then the popup is not updated and the same value as for the last country with data is displayed.
#Kiarash, there are two problems here:
You are using the Datamaps from the datamaps.github.io site, which I don't recommend since I can't guarantee reliability (uptime) or backwards compatibility. You are best off downloading it from the Github project page
data won't have a property with the country name, it should be accessed like data.numberOfThings.
Here is a working version of the code you supplied

JSON results into a variable and store in hidden input field

I wrote code below that is working perfectly for displaying the results of my sales tax calculation into a span tag. But, I am not understanding how to change the "total" value into a variable that I can work with.
<script type="text/javascript">
function doStateTax(){
var grandtotalX = $('#GRANDtotalprice').val();
var statetaxX = $('#ddl').val();
$.post('statetax.php',
{statetaxX:statetaxX, grandtotalX:grandtotalX},
function(data) {
data = $.parseJSON(data);
$('.products-placeholder').html(data.products);
$('.statetax-placeholder').html(data.statetax);
$('.total-placeholder').html(data.total);
// ...
});
return false;
};
</script>
Currently, $('.total-placeholder').html(data.total); is successfully placing the total number into here:
<span class="total-placeholder"></span>
but how would I make the (data.total) part become a variable? With help figuring this out, I can pass that variable into a hidden input field as a "value" and successfully give a proper total to Authorize.net
I tried this and id didn't work (see the testtotal part to see what I'm trying to accomplish)..
function(data) {
data = $.parseJSON(data);
$('.products-placeholder').html(data.products);
$('.statetax-placeholder').html(data.statetax);
$('.total-placeholder').html(data.total);
$testtotal = (data.total);
// ...
If you are using a hidden field inside a form, you could do:
//inside $.post -> success handler.
$('.total-placeholder').html(data.total);
$('input[name=yourHiddenFieldName]', yourForm).val(data.total);
This will now be submitted along with the usual submit. Or if you want to access the data elsewhere:
var dataValue = $('input[name=yourHiddenFieldName]', yourForm).val();
The "data" object you are calling can be used anywhere within the scope after you have a success call. Like this:
$.post('statetax.php',
{statetaxX:statetaxX, grandtotalX:grandtotalX},
function(data) {
data = $.parseJSON(data);
var total = data.total;
var tax = data.total * 0.19;
});
return false;
};
Whenever you get an object back always try to see with an alert() or console.log() what it is.
alert(data); // This would return <object> or <undefined> or <a_value> etc.
After that try to delve deeper (when not "undefined").
alert(data.total); // <a_value>?
If you want 'testotal' to be recognized outside the function scope, you need to define it outside the function, and then you can use it somewhere else:
var $testtotal;
function(data) {
data = $.parseJSON(data);
$('.products-placeholder').html(data.products);
$('.statetax-placeholder').html(data.statetax);
$('.total-placeholder').html(data.total);
$testtotal = (data.total);
EDIT:
The comments are becoming too long so i'll try and explain here:
variables defined in javascript cannot be accessed by PHP and vice versa, the only way PHP would know about your javascript variable is if you pass it that variable in an HTTP request (regular or ajax).
So if you want to pass the $testtotal variable to php you need to make an ajax request(or plain old HTTP request) and send the variable to the php script and then use $_GET/$_POST to retrieve it.
Hope that answers your question, if not then please edit your question so it'll be clearer.

Can't access XML data after first use using JQUERY html() or append()

I am setting up cycling quotes for a website, and I'm having trouble reloading the data when after it has already been used once.
I've set up a XML file with a bunch of data. The data includes a quote, an author, and the job title of the author (quote, author, title).
I then have a jQuery .ajax call and store it in the variable xmlData.
xmlData is then used to append or add html to specified id tags.
I am using setInterval() in order to move through the xml data.
The idea is to go through it in a loop like: 1 | 2 | 3| 1| 2 | 3 and so on. But when it comes back around, after the data has been appended to an ID, it doesn't show up anymore. It is as if the data was removed from the XML file.
Any help would be appreciated. Code is below, along with the website URL where I am working on the test.
<script language="javascript" type="text/javascript">
var xmlData;
var xmlFAILdata;
var nextE = 0;
var ttlE;
var quote;
var author;
var title;
$(function(){
$.ajax({
type: "GET",
url:"/wp-content/themes/privilegeofpersecution/endorsements.xml",
data: "",
dataType:"xml",
async: false,
success: function(xml){
//alert("XML SUCCESS!");
xmlData = xml;} ,
error: function(xmlFAIL){
alert("XML FAIL");
}
});
ttlE = $(xmlData).find('endorsement').length;
//Since .length return the number starting at 1 rather than 0 subtract 1 for accuracy
ttlE -= 1;
//On pageload, load in the first Endorsement into variables
quote = $(xmlData).find('endorsement').eq(0).children('quote');
author =$(xmlData).find('endorsement').eq(0).children('author');
title =$(xmlData).find('endorsement').eq(0).children('title');
//Append variables to id containers
$("#quote").html(quote);
$("#author").html(author);
$("#title").html(title);
//executes the function "next" which places the next endorsement
setInterval("next()", 5000);
});
function next(){
console.log('Next Function Started');
if(nextE >= ttlE){
nextE = 0;
}
else{
nextE++;
}
console.log('nextE = ' + nextE);
quote = $(xmlData).find('endorsement').eq(nextE).children('quote');
author =$(xmlData).find('endorsement').eq(nextE).children('author');
title =$(xmlData).find('endorsement').eq(nextE).children('title');
$("#quote").html(quote);
$("#author").html(author);
$("#title").html(title);
}
</script>
Here is the website: http://privilegeofpersecution.com/wp-content/themes/privilegeofpersecution/xmltest.html
I was able to fix the problem by adding .clone() to the variable assignment. This way I'm not just placing the XML object in the DOM and overwriting it. rather, I am copying the data from the XML each time I need it so that it stays in tact.
quote = $(xmlData).find('endorsement').eq(0).children('quote').clone();
author =$(xmlData).find('endorsement').eq(0).children('author').clone();
title =$(xmlData).find('endorsement').eq(0).children('title').clone();