Im creating a singleline series chart using dates and closing prices from yahoo. I have converted the dates into JS timestamps and put them in an array named timeStampArray and put the closing prices into an array named closePrices.
I can populate the chart with data like so:
data : [
[ 1361750400000, 442.80],
[ 1361491200000, 450.81]
],
I wish to use the data from my arrays and the API says to use an array with two values for x and y, like this
data: [[5, 2], [6, 3], [8, 2]]
therefore can I combine my two arrays so that they fit this format?
I can only find examples of how to combine my arrays into key-value pairs like this {'test1':'1', 'test2':'2'};
Also when I create the chart using hardcoded data it orders the dates in ascending order but I want it to keep the ordering that they are input, e.g 25th Feb before 22nd Feb as this is showing historical data.
Is there a way to correct this?
Heres the jsFiddle of my current code: http://jsfiddle.net/mXnZy/
update: ive tried
var timeClose = new Array();
for(var i=0; i<data.query.results.quote.length; i++)
{
timeClose.push( [timeStampArray[i], closePrices[i]] );
}
however this outputs [1361750400000, 442.80, 1361491200000, 450.81] which is wrong.
If you mean that you want them sorted in reverse order, you can use the 'reversed' property on the x axis:
http://api.highcharts.com/highstock#xAxis.reversed
If you mean that you want them listed in whatever order they're entered, without being sorted, it will be much more complicated.
You could provide ordinal x values, and provide the date as additional data. You could then use the axis label formatter to show the dates that you wish.
Related
I have a JSON file containing:
{"mapping": [
[
"london",
"51.18452",
"-0.150839",
"2016-04-19"
],
[
"london",
"52.6127",
"-2.02296",
"2016-04-21"
],
[
"london",
"53.334",
"-6.2761",
"2016-04-15"
]
}
Within my HTML I wish to have a range slider like this:
[]-----------------
oldest recent
In this scenario, the oldest JSON data should be shown, so
"london",
"53.334",
"-6.2761",
"2016-04-15"
And as the user slowly moves the range slider closer to the right end, more recent data should be shown..
----------------[]-
oldest recent
displaying..
"london",
"52.6127",
"-2.02296",
"2016-04-21"
I have many other values within the JSON file, I just used these three examples to show the format of the file. I am creating a heat map and whilst the slider moves along, the heat map should change to generate different points. Thanks for any help with this!
Turning the arrays into objects is optional, but it is much easier to reference properties like that, also it allowed us to convert the date string into a date object which has a number value to compare with.
const objectMapping = data.mapping.map(element => ({city:element[0], latitude:element[1], longitude:element[2], date:new Date(element[3])}));
Now that you have objects rather than an array, you can just say Array.sort on the date object where if b is higher than a, then b will come before a in the list
const sortedMapping = objectMapping.sort((a, b) => b.date - a.date);
Then sortedMapping[0] = oldest date
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.
I'm tying out dygraphs an it´s pretty fun.
For some reason though it does not accept a variable as labels for the array containing the data. I have formatted the string to exactly look like the "hardcoded" entry but it just won´t work.
Here are some snippets to let you know what i mean.
var select =('<?php echo implode('","', $select); ?>');
var label='"X"'+ ',"'+select+'"';
g = new Dygraph(
// containing div
document.getElementById("graphdiv"),allData,
{
labels: [label], // I tried it with and without the brackets, no difference
legend:'always',
title:'Abweichung der Messerte',
titleHeight:32,
ylabel:'<?php echo $art?>',
xlabel:'Zeit',
showRangeSelector: true,
digitsAfterDecimal: 5,
strokeWidth: 1.5,
drawPoints: true,
}
);
If i log label to the console it looks like this, depending on the selected numbers:
""X","10002","10003""
Still i get the folling error
"Mismatch between number of labels ("X","10002","10003") and number of columns in array (3)"
My array format for allData is [time,Value1,Value2] and works fine if i hardcode the labels.
Please tell me what i´m doing wrong :-)
greetings David
You need to pass an array of strings, not a comma-separated string of labels.
i.e.
['X', 'Y1', 'Y2']
and not
'X,Y1,Y2'
I'm working on a visualization utilizing the crossfilter.js library, and I'm a bit confused on how to create some dimensions from nested attributes within my dataset. For instance, each instance of the dataset has multiple dates associated with it, resulting in a data structure that looks like this:
[ { name: 'instance_name',
dates: ['2014-11-11', '2013-07-06', '2011-02-04'],
category: 'category 1' },
{ name: 'instance_name2',
dates: ['2012-01-01', '2013-03-07'],
category: 'category 2' } ]
I'd like to be able to create dimensions that will allow for filtering based on, say, the dates and the category and dimensions are a straightforward way to do this with crossfilter. However, I'm not sure how to parse the dates. I've tried first creating a date dimension using something like:
var cf = crossfilter(data);
var dateDim = cf.dimension(function(d) { return d.dates; });
and then tried to store just the dates as a variable using the .map() method like so:
var date = dateDim.top(Infinity).map(function(d) { return d.dates; });
The above does retrieve just the dates and stores them as a variable, however (a) this is just an array of dates each of which is a string, and (b) this doesn't get me any closer to linking the dateDim to other crossfilter dimensions I'd like to create for the visualization. Any help would be greatly appreciated. Thanks for reading.
My recommendation is be to flatten your structure before loading it in to Crossfilter. So your 1st record will become 3 records (1 for each date) and your 2nd record will become 2 records. You can then parse the dates and treat them as a dimension in Crossfilter without too much trouble. The downside is that counting because a problem, but that is manageable with custom grouping functions.
I'm using Highcharts (link to a specific demo -- click View Options to compare below code) to render some data for personal-use.
[Note: this is almost definitely a me-related error, so I don't mean to insinuate that Highcharts is at fault -- it's really a wonderful api!]
When setting the series.data field of the chart object, I encounter strange array sectioning.
For instance, this works fine:
series: [{
name: 'seriesName',
data: [22, 24, 15]
}]
And three data points are plotted with values 22, 24 and 15.
However,
series: [{
name: 'sillySeries',
data: chartData[0]
}]
renders 3 points with the values 2, 4 and 5 and the titles of the points are 2, 2 and 1 respectively... that is, it's splitting the array entries into a title and then a value for two-digit numbers.
console.log shows me that chartData looks like
22,24,15,2010-9,2010-10,2010-11
(3 values for 3 months)
Although the actual arrays are more like [22,24,15][2010-9,2010-10,2010-11]
My 2d-array chartData[][] has [column][row] indices for the data, and I figured that asking for chartData[0] would return an array.
Perhaps my question should be: How do I return a 1d array from a 2d array representation for setting properties/values in javascript objects? It seems like I'm probably overlooking something very obvious.
edit:
data: [24]
plots one point at 24, awesome.
data: '24'
splits up the data as title and then value, effectively plotting a point at 4 and not 24.
So the representation becomes a string when I try to pass an array to the data field. Any way I can do like string.toArray ?
edit 2:
chartData[col][row] is declared as an empty array
var chartData = [];
and subsequently filled up with values by iterating over an HTML table's rows and columns, where the innermost loop contents look like
chartData[cellIndex][rowIndex] = $(currentCell).text();
While chartData is probably an array, it sounds like chartData[0] is a string. When you use an array index on a string you get the character at that position, which is exactly what you are experiencing...
renders 3 points with the values 2, 4 and 5 and the titles of the points are 2, 2 and 1 respectively... that is, it's splitting the array entries into a title and then a value for two-digit numbers.
There are many ways to define arrays within arrays in javascript; here is one:
var chartData = [
[22,24,15]
,['2010-9','2010-10','2010-11']
];
parseInt() saved the day.
something like
for (i=0; i<chartData[0].length; ++i) {
columnOne.push(parseInt(chartData[0][i]);
}
gave me an array that I could then use to display the data with the data field in the object notation
data: columnOne
or more literally
chart1.series[0].data = columnOne;
Thank you James for pointing out
While chartData is probably an array, it sounds like chartData[0] is a string.
which lead to my discovery that the data in my array was actually all strings, which I kept this way because some fields are strings, some are dates (YYYY-MM-DD) and some are just ints.
Many thanks to you both =)
Well, this is not a real answer, but might help you.
Highcharts enables you to preprocess certain options. In your case, you could do something like :
options.series[0].data = new Array(1, 0, 4);
doc reference : http://www.highcharts.com/documentation/how-to-use#options
If this fails, comment above.