Can another column name than "value" be used in Highmaps? - javascript

I have a JSON file with multiple columns, and would like to keep the display of any of those as a map relatively open, based on the choice of the user. Now, I can't see any examples of using other column names for display in Highmaps than "value". Is it so? Or is there any way to name within the Javascript code the column that should be used by Highmaps for the display of the data?
That is, the column names are (for example) these:
LC_Ctry_Limit,LC_Capita_Limit,LC_Ctry_Footprint,LC_Capita_Footprint,LC_Score
Now, in order to be able to display the data from LC_Score, I'd need to rename the column (hard coded into the JSON-file) into "value". Thus:
LC_Ctry_Limit,LC_Capita_Limit,LC_Ctry_Footprint,LC_Capita_Footprint,value
But what is, if the user wants to display instead another column? Do I need to create five different JSON files, for each column, and name it "value" then? That seems rather inflexible to me.
My Highmaps-code looks like this, based on loading first a GeoJSON and then a JSON file, and I guess there, it should be something about a column-name-specifier:
series : [
{
data : data,
mapData: geojson,
joinBy: ['Country_40','Country'],
name: 'LC_Score',
borderWidth: 0.2,
COLUMN-TO-BE-USED: lorem
}]
Thanks for any hints!

You could set values of value property before setting the data in chart's options/configuration. This selection can be based on value passed into function that will return prepared array for configuration.
Example: http://jsfiddle.net/bmv0y8dn/
var columnToBeUsed = 'lorem';
$('#container').highcharts('Map', {
series: [{
data: (function (columnToBeUsed) {
var len = data.length,
tab = [];
for (var i = 0; i < len; i++) {
data[i].value = data[i][columnToBeUsed];
}
return data;
})(columnToBeUsed),
...
Series data can be changed dynamically using Series.setData, so you could change value's value and call setData() with new data for dynamic data change.

Related

D3 making new, smaller CSV file

I'm stuck with a quite simple problem and need help.
I have a big CSV file with 50 columns which i absolutely can't modifie.
Now i want to make a chart where i only need 5-6 columns out of it.
My idea was now to make a new "data2" which contains only these 5-6 columns (with key and evertything) and work with this data2.
But i'm not able to create this data2.
To filter which columns i need i wanted to work with regex. Something like this:
d3.keys(data[0]).filter(function(d) { return d.match(/.../); })
But how do i create the new data2 then? I'm sure i need to work with d3.map but even with the api i'm not able to understand how it works correctly.
Can someone help me out?
Firstly, your question's title is misleading: you're not asking about making a smaller CSV file, since the file itself is not changed. You're asking about changing the data array created by D3 when that CSV was parsed.
That brings us to the second point: you don't need to do that. Since you already lost some time/resources loading the CSV and parsing that CSV, the best idea is just keeping it the way it is, and using only those 5 columns you want. If you try to filter some columns out (which means deleting some properties from each object in the array) you will only add more unnecessary tasks for the browser to execute. A way better idea is changing the CSV itself.
However, if you really want to do this, you can use the array property that d3.csv creates when it loads an CSV, called columns, and a for...in loop to delete some properties from each object.
For instance, here...
var myColumns = data.columns.splice(0, 4);
... I'm getting the first 4 columns in the CSV. Then, I use this array to delete, in each object, the properties regarding all other columns:
var filteredData = data.map(function(d) {
for (var key in d) {
if (myColumns.indexOf(key) === -1) delete d[key];
}
return d;
})
Here is a demo. I'm using a <pre> element because I cannot use a real CSV in the Stack snippet. My "CSV" has 12 columns, but my filtered array keeps only the first 4:
var data = d3.csvParse(d3.select("#csv").text());
var myColumns = data.columns.splice(0, 4);
var filteredData = data.map(function(d) {
for (var key in d) {
if (myColumns.indexOf(key) === -1) delete d[key];
}
return d;
})
console.log(filteredData)
pre {
display: none;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<pre id="csv">foo,bar,baz,foofoo,foobar,foobaz,barfoo,barbar,barbaz,bazfoo,bazbar,bazbaz
1,2,5,4,3,5,6,5,7,3,4,3
3,4,2,8,7,6,5,6,4,3,5,4
8,7,9,6,5,6,4,3,4,2,9,8</pre>

How to organise/nest data for d3.js chart output

I'm looking for some advice on how to effectively use large amounts of data with d3.js. Lets say for instance, I have this data set taken from a raw .csv file (converted from excel);
EA
,Jan_2016,Feb_2016,Mar_2016
Netherlands,11.7999,15.0526,13.2411
Belgium,25.7713,24.1374
France,27.6033,23.6186,20.2142
EB
,Jan_2016,Feb_2016,Mar_2016
Netherlands,1.9024,2.9456,4.0728
Belgium,-,6.5699,7.8894
France,5.3284,4.8213,1.471
EC
,Jan_2016,Feb_2016,Mar_2016
Netherlands,3.1499,3.1139,3.3284
Belgium,3.0781,4.8349,5.1596
France,16.3458,12.6975,11.6196
Using csv I guess the best way to represent this data would be something like;
Org,Country,Month,Score
EA,Netherlands,Jan,11.7999
EA,Belgium,Jan,27.6033
EA,France,Jan,20.2142
EA,Netherlands,Feb,15.0526
EA,Belgium,Feb,25.9374
EA,France,Feb,23.6186
EA,Netherlands,Mar,13.2411
EA,Belgium,Mar,24.1374
EA,France,Mar,20.2142
This seems very long winded to me, and would use up a lot of time. I was wondering if there was an easier way to do this?
From what I can think of, I assume that JSON may be the more logical choice?
And for context of what kind of chart this data would go into, I would be looking to create a pie chart which can update the data depending on the country/month selected and comparing the three organisations scores each time.
(plnk to visualise)
http://plnkr.co/edit/P3loEGu4jMRpsvTOgCMM?p=preview
Thanks for any advice, I'm a bit lost here.
I would say the intermediary step you propose is a good one for keeping everything organized in memory. You don't have to go through a csv file though, you can just load your original csv file and turn it into an array of objects. Here is a parser:
d3.text("data.csv", function(error, dataTxt) { //import data file as text first
var dataCsv=d3.csv.parseRows(dataTxt); //parseRows gives a 2D array
var group=""; // the current group header ("organization")
var times=[]; //the current month headers
var data=[]; //the final data object, will be filled up progressively
for (var i=0;i<dataCsv.length;i++) {
if (dataCsv[i].length==1 ) { //group name
if ( dataCsv[i][0] == "")
i++; //remove empty line
group = dataCsv[i][0]; //get group name
i++;
times = dataCsv[i];//get list of time headings for this group
times.shift(); // (shift out first empty element)
} else {
country=dataCsv[i].shift(); //regular row: get country name
dataCsv[i].forEach(function(x,j){ //enumerate values
data.push({ //create new data item
Org: group,
Country: country,
Month: times[j],
Score: x
})
})
}
}
This gives the following data array:
data= [{"Org":"EA","Country":"Netherlands","Month":"Jan_2016","Score":"11.7999"},
{"Org":"EA","Country":"Netherlands","Month":"Feb_2016","Score":"15.0526"}, ...]
This is IMO the most versatile structure you can have. Not the best for memory usage though.
A simple way to nest this is the following:
d3.nest()
.key(function(d) { return d.Month+"-"+d.Country; })
.map(data);
It will give a map with key-values such as:
"Jan_2016-Netherlands":[{"Org":"EA","Country":"Netherlands","Month":"Jan_2016","Score":"11.7999"},{"Org":"EB","Country":"Netherlands","Month":"Jan_2016","Score":"1.9024"},{"Org":"EC","Country":"Netherlands","Month":"Jan_2016","Score":"3.1499"}]
Use entries instead of mapto have an array instead of a map, and use a rollup function if you want to simplify the data by keeping only the array of scores. At this point it is rather straightforward to plug it into any d3 drawing tool.
PS: a Plunker with the running code of this script. Everything is shown in the console.

Dynamically add code to JS

I've been asked to create Graphs dynamically according to a certain csv content.
I'm currently using the Chart.js library, which requires you to add elements to the "label" property in order to properly build the graph.
label : ["name1", "name2"]
What I am not able to do here, is dynamically add the elements contained in an array "Names" into the parameter.
var names = "asia", "africa";
What I am try to accomplish is that, according to the number of entries inside the array "names", those many names are gonna appear on the graph.
Any ideas? thanks in advance!
[EDIT]
function createChart(upData, lData, allData){
var ctx = document.getElementById("myChart").getContext("2d");
document.getElementById("myChart").style.width = "<?wsx5 document.write(parameters.widthsize.value);?>px";
document.getElementById("myChart").style.height = "<?wsx5 document.write(parameters.heightsize.value);?>px";
var data = {
labels: [
],
This is about what I got now, the relevant part of course. upData is an array that contains the names I need, and those elements need to be added dynamically to the label section
I actually found out what the problem was.
Apparently the code in order for the labels field to work is without brackets:
function createChart(upData, lData, allData){
var ctx = document.getElementById("myChart").getContext("2d");
document.getElementById("myChart").style.width = "<?wsx5 document.write(parameters.widthsize.value);?>px";
document.getElementById("myChart").style.height = "<?wsx5 document.write(parameters.heightsize.value);?>px";
var data = {
labels: arrayname , }

loading csv into nvd3 to make discrete bar chart

I have the following CSV file:
Fun,Stupid,Yes,No
50,-20,100,70
I'd like to load it into nvd3 to make a discrete bar chart. I know it's easy but it's taking me way to long to manipulate the data.
I've tried the following:
d3.csv("/path/to/file", function(data){
console.log(data);
});
and I get the following object which isn't working with nvd3:
[{Fun:50, Stupid: -20, Yes: 100, No: 70}]
Thanks.
nvd3 is expecting a fairly specific data form so you need to get your data into that form. The form that it is expecting is:
[
{
key: "totals",
values: []
}
];
Where the empty array is filled with the objects from d3.csv and note that nv is expecting the name of the array of your objects to be called values.
So the first step is to create an empty object like this:
var exampleData = [
{
key: "totals",
values: []
}
];
Then fill it with your data:
data.forEach(function (d){
d.value = +d.value
exampleData[0].values.push(d)
})
This all needs to be inside your d3.csv call.
To use this format you need to have your csv file organised into columns with your names in one column and your values in another like:
label, value
Fun, 50
Stupid, -20
And here's a link to a working example

ComboBox.store.loadData can't load single-item array

I am using ExtJS 3.4 .
I have a structure with data for combobox like this:
var a = [[1,"text1"],[2,"text2"]]
I load it like this:
ComboBox.store.loadData(a);
But when I have only 1 item in the array
var a = [[1,"text1"]]
then it doesn't load at all. I've read that:
an Array : Arrays will be converted to a Ext.data.ArrayStore
internally, automatically generating field names to work with all data
components. 1-dimensional array : (e.g., ['Foo','Bar']) A
1-dimensional array will automatically be expanded (each array item
will be used for both the combo valueField and displayField)
2-dimensional array : (e.g., [['f','Foo'],['b','Bar']]) For a
multi-dimensional array, the value in index 0 of each item will be
assumed to be the combo valueField, while the value at index 1 is
assumed to be the combo displayField.
But that doesn't explain how do I load an array with one element. Or whatever, it shouldn't be necessary an array, the point is to load only one item. I've tried loading this:
Code:
[{id:1,text:"text1"}]
[[{id:1,text:"text1"}]]
{id:1,text:"text1"}
Even creating a custom ArrayStore:
Code:
var store = new Ext.data.ArrayStore({
autoDestroy: true,
storeId: 'Store1',
idProperty:"id",
fields: ["id","text"]);
ComboBox.store = store;
ComobBox.store.loadData([{id:1,text:"text1"}]);
But everything loads incorrectly . Either the combobox is empty, or it displays id instead of text.
I can see that if I lazily init the combo:
Code:
{"xtype":"combo","width":250,"fieldLabel":"my combo","value":31029,"forceSelection":true,"hiddenName":"ComboHiddenName","minChars":1,"triggerAction":"all","store":[[31029,"gdfs"]]}
then the array with one item will load successfully. At which properties of ComboBox.store should I look to configure them properly for a single-item array to be loaded correctly using loadData method?
ComboBox.store.loadData(var a); would not work for any data. It would raise exception Unexpected token var. Instead one should use ComboBox.store.loadData(a); without var
ComboBox.valueField = "id";
ComboBox.displayField = "text";
ComboBox.store = new Ext.data.ArrayStore({autoDestroy: true, fields: ["id", "text"]});

Categories

Resources