D3.js multiple area chart not working - javascript

I am following this tutorial for creating multiple area charts with D3.js and I want to customize it to my data.
His data is:
Year, Variable1, Variable2, etc
My data is
YYYYMMDD, variable1, variable2, etc
I changed this part of the code to convert the date column to a Date object:
function createChart(data){
var countries = [];
var charts = [];
var maxDataPoint = 0;
/* Loop through first row and get each country
and push it into an array to use later */
for (var prop in data[0]) {
if (data[0].hasOwnProperty(prop)) {
if (prop != 'Day') {
countries.push(prop);
}
}
};
var countriesCount = countries.length;
var startYear = (data[0].Day).substr(0,4);
var endYear = (data[data.length - 1].Day).substr(0,4);
var chartHeight = height * (1 / countriesCount);
/* Let's make sure these are all numbers,
we don't want javaScript thinking it's text
Let's also figure out the maximum data point
We'll use this later to set the Y-Axis scale
*/
data.forEach(function(d) {
for (var prop in d) {
if (d.hasOwnProperty(prop)) {
d[prop] = parseFloat(d[prop]);
if (d[prop] > maxDataPoint) {
maxDataPoint = d[prop];
}
}
}
// D3 needs a date object, let's convert it just one time
var y = (d.Day).substr(0,4),
m = (d.Day).substr(4,2) - 1,
d = (d.Day).substr(6,2);
d.Day = new Date(y,m,d);
});
This is a sample of my data and there is around 400 rows
Day NYTimes Guardian The Peninsula Gulf Times
20101201 1 8 2 0
20101203 3 9 2 0
20101205 6 10 4 1
20101207 2 9 5 1
20101209 1 3 7 0
20101211 12 8 6 0
20101213 3 4 3 0
No graph is shown, I just get a blank page and no errors on the console, take a look here. What is wrong?

Somewhere in the code, the Day value is getting converted from a string ("20101201") to an integer (20101201). You are then getting a no method substr error when trying use .substr() on a integer.
Try converting the var y to a string using .toString() by replacing line:
var y = (d.Day).substr(0,4)
With
var y = (d.Day).toString().substr(0,4)
Or consider using the d3's built in time parsing functions

Related

Calculating bands for Graphic EQ

I'm trying to make a Graphic EQ using web audio and the goal is build a function that
calculates an array of fixed center frequency's using a band count (a.k.a number) as input.
In other words it generates an array for fixed center frequencies.
example:
function calcBands(bands) {
// Since there are different graphic EQ's they usually around 6 - 31 bands
// but professionally it's normally 31 bands
// band parameter needs to be a number between 6 and 31
//insert code here:
const freqs = new Array(bands);
return freqs;
}
function buildFilters(bands) {
let centers = calcBands(bands);
let filters = [];
for (let i = 0; i < bands; i++) {
let filter = context.createBiquadFilter();
filter.type = "peaking";
filter.frequency.value = centers[i];
filter.Q.value = Math.SQRT1_2;
if (i > 0) {
filters[i - 1].connect(filter);
}
filters.push(filter);
}
return filters;
}
The thing is I tried doing some research and I found out that there are ISO standards and other things, but I just can't do the maths of it.
All I can understand from this is that:
This is calculated using octave bands either 1 or 1/3, etc in base 2
Graphic EQ's usually have 6 to 31 bands
Middle C (a.k.a A4) equals to 440Hz
Nyquist Frequency is sampleRate / 2
Can anyone please help me?
Feel free to correct me if I'm wrong
references:
https://www.cross-spectrum.com/audio/articles/center_frequencies.html
https://sound.stackexchange.com/questions/14101/what-is-the-frequency-step-formula-for-10-and-31-band-eqs
http://www.tonmeister.ca/main/textbook/intro_to_sound_recordingch13.html

I want to solve the "system:time_start" error when trying to output GLDAS monthly precipitation to CSV using Google Earth Engine

I am using GoogleEarthEngine to look at precipitation data for the Mekong River basin. The GLDAS data are set every three hours per day. My goal is to extract the GLDAS data from 2000 to 2020 by adding up the data by month.
I want to extract the total monthly precipitation in GLDAS using the Google Earth Engine, but I cannot extract the CSV due to the error
Image.date: Image '120' has a 'system:time_start' property which is not a number: 2010-01-01T00:00:00
I think I can extract the CSV by converting "system:time_start", how should I change it?
var studyArea = ee.Geometry.Rectangle(102, 8.5, 107, 15);
Map.centerObject(mekong, 9);
// 解析対象年
var years = ee.List.sequence(2000, 2019);
var months = ee.List.sequence(1, 12);
var early = ('2010-01-01');
var late = ('2011-01-01');
// MOD11A1の取り出し
var image = ee.ImageCollection('NASA/GLDAS/V021/NOAH/G025/T3H')
.filterDate(early, late).filterBounds(mekong);
//print(image);
// mmに変換してmodLSTcに保存
var gldas_precipitation = image.select('Rainf_f_tavg');
var gldas_precipitation_mm = gldas_precipitation.map(function(img)
{return img.multiply(10080.0).copyProperties(img, ['system:time_start'])});
// 変数gldas_precipitation_mm_monthの中に月単位のメジアンデータを保存 ////////////////////////////////////////////
var gldas_precipitation_mm_month = ee.ImageCollection.fromImages(
years.map(function(y) {
return months.map(function(m) {
var monthly = gldas_precipitation_mm.filter(ee.Filter.calendarRange(y, y, 'year'))
.filter(ee.Filter.calendarRange(m, m, 'month'))
.sum()
.rename('precipitation_mm_month');
return monthly.set('year', y).set('system:time_start', ee.Date.fromYMD(y, 1, 1))
.set('month', y).set('system:time_start', ee.Date.fromYMD(y, m, 1));
});
}).flatten());
var gldas_precipitation_mm_month = gldas_precipitation_mm_month.filterBounds(mekong);
// TSLのポリゴン ///////////////////////////////////////////////////////////////////////////////////
var empty = ee.Image().byte();
// Paint all the polygon edges with the same number and width, display
var outline = empty.paint({
featureCollection: mekong,
color: 1,
width: 2
});
Map.addLayer(outline, {palette: 'FF0000'}, 'TSL');
//output_csv_precipitation
//Create variables and extract data
var scale = gldas_precipitation_mm_month.mean().projection().nominalScale().multiply(0.05); print(scale);
var gldas = gldas_precipitation_mm_month.filter(ee.Filter.listContains('system:band_names', gldas_precipitation_mm.mean().bandNames().get(0)));
var ft = ee.FeatureCollection(ee.List([]));
//Function to extract values from image collection based on point file and export as a table
var fill = function(img, ini) {
var inift = ee.FeatureCollection(ini);
var ft2 = img.reduceRegions(mekong, ee.Reducer.mean(), scale);
var date = img.date().format("YYYY/MM/dd");
var ft3 = ft2.map(function(f){return f.set('month', date)});
return inift.merge(ft3);
};
// Iterates over the ImageCollection
var profile = ee.FeatureCollection(gldas_precipitation_mm_month.iterate(fill, ft));
print(profile,'profile');
The value of the property system:time_start must be a number (even though it would make sense for it to be a Date, the system design didn't end up that way). You must change calls like
.set('system:time_start', ee.Date.fromYMD(y, m, 1))
to
.set('system:time_start', ee.Date.fromYMD(y, m, 1).millis())
While looking, I see other possible problems here:
return monthly.set('year', y).set('system:time_start', ee.Date.fromYMD(y, 1, 1))
.set('month', y).set('system:time_start', ee.Date.fromYMD(y, m, 1));
This is setting the month property value to the y variable (not m), and it's setting system:time_start twice (so only the second value will be used). Probably this is not what you meant. I have not looked at what you're intending to do with the collection, so you'll have to figure that part out yourself.

how to pass big data to google scatter chart

I am relatively new to JavaScript and Django and I am struggling with passing big data to my google chart.
I have a chart representing velocities for a given date and distance. In my django views I create list of distances, dates and according velocities. I also generate there a list with sorted values occuring in velocity list and a list with colors according to velocity's value.
I want to have a chart with velocity map with applied colortable like this :
http://i.imgur.com/9Tyv8Rn.jpg
So I used scatter chart with velocity series. The chart is dynamic, it's diffrent for every item selected by a user.
JS to generate rows and columns :
// Define data table rows:
var rows = [];
var rows_list = [];
var vl_max = vel_list.length;
for (i=0; i < vl_max; i+=1) {
var date_tmp = new Date(date_list[i].split(',')[0],date_list[i].split(',')[1]-1,date_list[i].split(',')[2]);
var date = [date_tmp];
var vel_tmp = vel_list[i];
var vtemp_max = vel_tmp.length;
var tooltip_dsname = dsname_list[i];
var tooltip_track = track_list[i];
for (j=0; j < vtemp_max; j+=1) {
var cell = [{v : date_tmp}];
for (k=0; k < vr_max; k+=1) {
var vel_full = vel_tmp[j];
var vel = vel_full.toFixed(1);
if (vel == vel_range[k]) {
// tooltip:
var dist = dist_list[j]/1000;
var yyyy = date_tmp.getFullYear().toString();
var mm = (date_tmp.getMonth()+1).toString(); // getMonth() is zero-based
var dd = date_tmp.getDate().toString();
var tooltip_date = yyyy + "-" + (mm[1]?mm:"0"+mm[0]) + "-" + (dd[1]?dd:"0"+dd[0]);
var tooltip = "<b>dataset: </b>"+tooltip_dsname+"<br><b>date: </b>"+tooltip_date+"<br><b>track: </b>"+tooltip_track+"<br><b>distance: </b>"+dist+" k"+mapunit+"<br><b> velocity: </b>"+vel_full.toFixed(2)+" m/d";
var color = color_list[k]
var style = "point { shape-type: square; fill-color: "+color+";}"
} else {
var dist = NaN;
var tooltip = "empty" ;
var style = "empty" ;
}
cell.push({v: dist},{v: tooltip},{v:style});
}
rows_list.push({c: cell});
}
};
Here is JSfiddle for chart generation with smaller data :
http://jsfiddle.net/joannao89/t26ooyrt/2/
The problem that I have is while the chart is working for smaller data, once I want to load it for a long distance and a wide date range, the browser keeps on popping us this line : "A website is slowing down your browser, what would you like to do ? {stop} {wait}"
I know that this is probably the problem of too large amount of rows, my website generates also 3 other charts like this, with the same data but in another X-Y axis combination (for example time on X-axis, velocity on Y-axis and distance as series) and it works perfectly fine. That's why I would like to pass the data to the chart in some faster way, but I have no clue how.
I already tried to use setTimeout, but it doesn't change a lot. I also tried doing a little less coding on JS side and more in django views, but it also didn't help.
So any suggestions about how to solve this will be very appreciated!

MySQL table output in JavaScript

We have this local timesheet and we want to add these two rows together and output its duration (ex: 09:16 am and 5:35 pm and we want the output as 8 hrs 51 min. But we want it in a loop.
We want to display this in a chart.js in y axis for each person. This is what we tried so far and it is not working.
data = JSON.parse(data);
var timein = [];
var timeout = [];
for(var i in data) {
total_duration = (data[i].timein + data[i].timeout);
}
console.log(total_duration);

How to set the dynamic or static tick size in a Rickshaw.js plot?

I am creating a Rickshaw.js-powered graph much like in this example: http://code.shutterstock.com/rickshaw/tutorial/example_07.html based on my own data that is returned via an AJAX call. The data is either measured in bytes (typical values range in a few gigabytes or hundreds of MBs) or seconds (anywhere between 10s and 50 minutes). I tried using a Rickshaw.Fixtures.Number.formatBase1024KMGTP formatter for the bytes and wrote my own for the seconds, which does its part well. The problem is that I need to position the tick lines in a smart way - preferably dynamically, but even static settings (e.g. place a tick every 1024*1024*1024=1 GB or every 60 s) would be fine.
I tried setting the tickSize to 1024^3 like so:
var y_axis = new Rickshaw.Graph.Axis.Y({
graph: graph,
tickSize: 1073741824 // 1 GB
});
y_axis.render();
but I ended up seeing no ticks at all. What am I doing wrong and what would be the right way?
Basically, you need to adapt the tickOffsets() function of the Axis.X, Axis.Y and Axis.Time classes in Rickshaw.
tickSize will not help you with that as - like #Old Pro stated correctly - it indicates the size of the bold tick lines in pixels. It has nothing to do with spacing.
For Time-based Axes
My solution essentially consists of replacing the standard tickOffsets() function in those files
this.tickOffsets = function() {
var domain = this.graph.x.domain();
var unit = this.fixedTimeUnit || this.appropriateTimeUnit();
var count = Math.ceil((domain[1] - domain[0]) / unit.seconds);
var runningTick = domain[0];
var offsets = [];
for (var i = 0; i < count; i++) {
var tickValue = time.ceil(runningTick, unit);
runningTick = tickValue + unit.seconds / 2;
offsets.push( { value: tickValue, unit: unit } );
}
return offsets;
};
by a custom routine. This is gonna do the trick:
this.tickOffsets = function() {
var domain = this.graph.x.domain();
var unit = this.fixedTimeUnit || this.appropriateTimeUnit();
var tickSpacing = args.tickSpacing || unit.seconds;
var count = Math.ceil((domain[1] - domain[0]) / tickSpacing);
var runningTick = domain[0];
var offsets = [];
for (var i = 0; i < count; i++) {
var tickValue = time.ceil(runningTick, unit);
runningTick = tickValue + tickSpacing;
offsets.push( { value: tickValue, unit: unit } );
}
return offsets;
};
With that in place, you can write something like
var time = new Rickshaw.Fixtures.Time();
var timeUnit = time.unit('year');
var x_axis = new Rickshaw.Graph.Axis.ExtendedTime(
{
graph: graph,
tickSpacing: 60*60*24*365*13, // 13 years
timeUnit: timeUnit
} );
to have ticks spaced out evenly at every 13 years.
For Value-based Axes
For value-based Axes, you would need to extend the render() function to include a facility that "manually" sets the ticks for the axis. I did it like this:
this.render = function() {
if (this.graph.height !== this._renderHeight) this.setSize({ auto: true });
var axis = d3.svg.axis().scale(this.graph.y).orient(this.orientation);
if (this.tickSpacing) {
var tickValues = [];
var min = Math.ceil(axis.scale().domain()[0]/this.tickSpacing);
var max = Math.floor(axis.scale().domain()[1]/this.tickSpacing);
for (i = min * this.tickSpacing; i < max; i += 1) {
console.log(i);
tickValues.push(i * this.tickSpacing);
}
axis.tickValues(tickValues);
}
axis.tickFormat( args.tickFormat || function(y) { return y } );
if (this.orientation == 'left') {
var berth = this.height * berthRate;
var transform = 'translate(' + this.width + ', ' + berth + ')';
}
if (this.element) {
this.vis.selectAll('*').remove();
}
this.vis
.append("svg:g")
.attr("class", ["y_ticks", this.ticksTreatment].join(" "))
.attr("transform", transform)
.call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));
var gridSize = (this.orientation == 'right' ? 1 : -1) * this.graph.width;
this.graph.vis
.append("svg:g")
.attr("class", "y_grid")
.call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize));
this._renderHeight = this.graph.height;
};
The important part here are the statements in the if (this.tickSpacing) clause. They compute ticks given by the tickSpacing variable in the config array, and assign them to the axis in the axis.tickValues(tickValues) statement. Note that this.tickValues is assigned in the this.tickSpacing = args.tickSpacing statement in the initialize() function, not stated above.
Try it yourself
Have a look at this jsfiddle, where the complete code is available. This will certainly give you some pointers. If you want, you can create your own jsfiddle with your values and tell me if you need anything else.
tickSize is the size of the ticks in pixels. Not what you want to be setting to a huge number.
Set ticks to the number of ticks you want on the graph and Rickshaw (actually d3) will do some magic to give you pretty values of ticks that generate about that number of ticks on the graph.
If you want further control you're going to have to dig into d3, where you will be able to explicitly set the tick values using axis.tickValues(). I'd probably copy the existing Rickshaw.Graph.Axis.Y code and create my own Y axis class that includes access to tickValues or the ability to use my own scale. It's a little unclean in that Rickshaw creates the Y scale in the graph.render() function, so you can't easily override the Y scale, but the Y scale Rickshaw creates does have the range set from the graph data, which is information you will want when creating your own tick values.

Categories

Resources