d3.js - Query regarding interpolate values - d3.js

I am working on a visulaization http://bost.ocks.org/mike/nations/:
I have a query as to the interpolation function. Initially the mousemove is called which calls the displayYear, where the interapolate data is called.
function mousemove() {
displayYear(yearScale.invert(d3.mouse(this)[0]));
}
}
// Tweens the entire chart by first tweening the year, and then the data.
// For the interpolated data, the dots and label are redrawn.
function tweenYear() {
var year = d3.interpolateNumber(thisyear, 2009);
return function(t) { displayYear(year(t)); };
}
// Updates the display to show the specified year.
function displayYear(year) {
//alert(year);
thisyear=year;
dot.data(interpolateData(year), key).call(position).sort(order);
label.text(Math.round(year));
}
// Interpolates the dataset for the given (fractional) year.
function interpolateData(year) {
return nations.map(function(d) {
return {
name: d.name,
region: d.region,
checkins: interpolateValues(d.checkins, year),
teamsize: interpolateValues(d.teamsize, year),
Checkintimes: interpolateValues(d.Checkintimes, year)
};
// Finds (and possibly interpolates) the value for the specified year.
function interpolateValues(values, year) {
var i = bisect.left(values, year, 0, values.length - 1),
a = values[i];
if (i > 0) {
var b = values[i - 1],
t = (year - a[0]) / (b[0] - a[0]);
return a[1] * (1 - t) + b[1] * t;
}
return a[1];
}
what does this function do? i tried debugging and found that it compares 2 years and does a calculation and then returns the values. can anyone elaborate this?
The json file contains
[
{
"name":"India",
"region":"South Asia",
"income":[[2000,225],[2001,225],[2002,226],[2003,227],[2004,229],[2005,230],[2006,231],[2007,244],[2008,254],[2009,253]],
"population":[[2000,41542812],[2001,41623424],[2002,41866106],[2003,42186202],[2004,41521432],[2005,41827315],[2006,42127071],[2007,42420476],[2008,42707546],[2009,42707546]],
"lifeExpectancy":[[2000,43.56],[2001,43.86],[2002,44.22],[2003,64.61],[2004,56.05],[2005,56.52],[2006,66.02],[2007,68.54],[2008,67.06],[2009,73.58]]
}
]

What this code is meant for is the case where a year (or more) of data is missing, which doesn't seem to be the case in the example data that you've posted. First, it finds the closest data point to the given year using bisect.left and then computes an extrapolation between the previous data point and the current data point for the requested year.
Note in particular that year - a[0] in your case will always be 0, as all the years are present (this computes the difference between the requested and found year). Hence, the whole term will be 0 and the return value corresponds to a[1].
If the year that's requested is not present, t denotes the factor that describes the change between the previous year b and the current year a. This change factor is used to extrapolate past a to get the value for the requested year.

Related

Custom time interval in bar chart has no gaps between bars

I created my own d3-time interval and added it to the switching time intervals example (ported to this jsfiddle).
But I'm unhappy with the result. The gaps between two bars are not shown.
I'd like the bars looking with a gap as all the other intervals. I suspect my implementation of the custom interval is wrong, but I cannot figure out what the problem is.
I used this implementation in another project and there the opposite happened: The gaps are maximal large and the bars very small.
var threeMonthsInterval = d3.timeInterval(
function (date) {
date.setDate(1);
date.setHours(0, 0, 0, 0);
var currentMounth = date.getMonth()
if (currentMounth <= 2) {
// 'Q1';
date.setMonth(0)
} else if (currentMounth > 2 && currentMounth <= 5) {
// 'Q2';
date.setMonth(3)
} else if (currentMounth > 5 && currentMounth <= 8) {
// 'Q3';
date.setMonth(6)
} else {
// 'Q4';
date.setMonth(9)
}
},
function (date, step) {
date.setMonth(date.getMonth() * 3 + step);
},
function (start, end) {
return (end.getMonth() - start.getMonth()) / 3 + (end.getFullYear() - start.getFullYear()) * 3;
},
function (date) {
return date.getMonth() * 3;
}
);
The one that counts the number between two dates
function (start, end) {
return (end.getMonth() - start.getMonth()) / 3 + (end.getFullYear() - start.getFullYear()) * 3;
},
is the one that tells dc.js how many bars to plan for, and therefore how wide they should be.
I haven't tested your code, so there could be other problems, but there are four quarters in a year, so that last number should be 4.

dc.js and crossfilter second level aggregation to average count per hour

I am trying to slightly extend the problem described in this question:
dc.js and crossfilter reduce average counts per day of week
I would like to chart average counts per hour of the day. I have followed the solution above, counting the values by day in the custom reduce with the only change being to dimension by hour of day. This seems to work well and can be seen in the following fiddle:
http://jsfiddle.net/dolomite/6eeahs6z/73/
The top bar chart shows the average counts by hour, the lower chart the total counts by hour. So hour 22 has a total count of 47 and average count of 4.2727... There are 11 days in the data so this is correct.
However, when I click on the weekday row chart and filter for Sunday I get a total count for hour 22 of 4 and an average of 0.3636... The denominator in calculating the average values is still including all weekdays in the data, irrespective of the weekday I filter by. So while the total count has filtered to just show 4 for Sunday it is being divided by the total number of days in the data, whereas the requirement is just to divide by the number of whichever day/s have been selected in the filter.
I know the solution lies in modifying the custom reduce but I am stuck! Any pointers on where I am going wrong would be gratefully received.
hourAvgGroup = hourDim.group().reduce(
function (p, v) { // add
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) + 1 : 1);
p.avg = average_map(p.map);
return p;
},
function (p, v) { // remove
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) - 1 : 0);
p.avg = average_map(p.map);
return p;
},
function () { // init
return { map: d3.map(), avg: 0 };
}
)
function average_map(m) {
var sum = 0;
m.forEach(function(k, v) {
sum += v;
});
return m.size() ? sum / m.size() : 0;
}
m.size() counts up the number of keys in the map. The problem is that even if a day has 0 records assigned to it, the key is still there, so m.size() counts it in the denominator. The solution is to remove the key when the count gets to 0. There are probably more efficient ways to do this, but the simplest solution is to add one line to your remove function in the custom reducer so that the function looks like this:
function (p, v) { // remove
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) - 1 : 0);
// If the day has 0 records, remove the key
if(p.map.has(day) && p.map.get(day) == 0) p.map.remove(day);
p.avg = average_map(p.map);
return p;
},
By the way, I would also recommend not including the actual average and average calculation in your group. Calculate it in the dc.js chart valueAccessor instead. The reducer is run once for every record added or removed. The valueAccessor is only run once per filter operation.

How to find if the second hand of a clock lies in the larger area or smaller one [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I have been given the time in the format: hh:mm:ss
I have to find if for a given time, the second hand lies in the larger or smaller area formed by the hour and minute hands?
I know that the hour hand moves at the rate of 0.5 degrees per minute,
the minute hand moves at the rate of of 6 degrees per minute and the second hand completes 360 degrees per minute.
But I am unable to find out in which area the second hand lies. So how can I do this?
Second hand within angle between hour and minute hands:
10:15:00
04:40:30
Second hand in reflex angle:
12:01:30
The problem intrigued me so I went ahead and wrote a test project in C#. As far as I can tell it works, you will have to test it to make sure though.
This is the code:
string strTime = "10:15:00";
DateTime dt = DateTime.ParseExact(strTime, "HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
int nHourDegrees = (360 / 12) * dt.Hour;
int nMinuteDegrees = (360 / 60) * dt.Minute;
int nSecondDegrees = (360 / 60) * dt.Second;
if (nHourDegrees > nMinuteDegrees)
{
int nArea1 = nHourDegrees - nMinuteDegrees;
int nArea2 = 360 - nArea1;
bool bArea1IsBigger = (nArea1 >= nArea2);
if (nSecondDegrees <= nHourDegrees && nSecondDegrees >= nMinuteDegrees)
{
//Second hand lies in area1
if (bArea1IsBigger)
{
Console.WriteLine("Second hand is in the larger area");
}
else
{
Console.WriteLine("Second hand is in the smaller area");
}
}
else
{
if (bArea1IsBigger)
{
Console.WriteLine("Second hand is in the smaller area");
}
else
{
Console.WriteLine("Second hand is in the larger area");
}
}
}
else if (nMinuteDegrees > nHourDegrees)
{
int nArea1 = nMinuteDegrees - nHourDegrees;
int nArea2 = 360 - nArea1;
bool bArea1IsBigger = (nArea1 >= nArea2);
if (nSecondDegrees <= nMinuteDegrees && nSecondDegrees >= nHourDegrees)
{
//Second hand lies in area1
if (bArea1IsBigger)
{
Console.WriteLine("Second hand is in the larger area");
}
else
{
Console.WriteLine("Second hand is in the smaller area");
}
}
else
{
if (bArea1IsBigger)
{
Console.WriteLine("Second hand is in the smaller area");
}
else
{
Console.WriteLine("Second hand is in the larger area");
}
}
}
else
{
if (nSecondDegrees == nHourDegrees)
{
Console.WriteLine("Second hand is on both of the other hands");
}
else
{
Console.WriteLine("Second hand is in the ONLY area");
}
}
The idea is that we find the areas between the Hour and Minute hands. Then check to see if the second hand is inside this area. We also compare this area to the other one and then we can easily deduce if the second hand is in the smaller or larger of the two.
Note: Some improvements can be made to the code:
It can be significantly shorter - I haven't done this because it was mainly a test/proof of how this can be done
If the hours overrun (i.e. 24 hour clock not 12) an alteration will have to be made. i.e. minus 12
If the times go to 12/60/60 and not back to 0, this will have to be done manually
Constants can be added in to remove the need for magic numbers
Similar to the above but common calculations like 360 / 12 can be moved to constants
It can be broken out into separate methods to improve readability
Can be moved into a helper method i.e. bool IsInLargerArea(string timeString)
Need to add the case for when the areas are the same size, at the moment I just assume Area1 to be bigger if they are equal i.e. >= (greater than or equal to)
Add checks to make sure there are only 3 parts to the straTimes array
And possibly some more things that I have not thought of
I would go with method which look like this. You have to identify, if the smaller area goes through 0 degree or not and then based on that you can say the solution.
int minDegree;
int maxDegree;
bool over360;
if (Math.abs(hourHandDegree - minuteHandDegree) < 180){
minDegree = Math.min(hourHandDegree, minuteHandDegree);
maxDegree = Math.max(hourHandDegree, minuteHandDegree);
over360 = false;
} else {
minDegree = Math.min(hourHandDegree, minuteHandDegree);
maxDegree = Math.max(hourHandDegree, minuteHandDegree);
over360 = true;
}
if (over360){
if ((secondHandDegree < minDegree) && (secondHandDegree > maxDegree)){
return true;
} else {
return false;
}
} else {
if ((secondHandDegree > minDegree) && (secondHandDegree < maxDegree)){
return true;
} else {
return false;
}
}
This solution is concise, easy to understand, and allows 12-hour or 24-hour input.
It is easier to visualize when you use radians.
The following is in R, but hopefully easy enough to read. Note %% is modulo operator.
which_region <- function(s){
# number of seconds elapsed in day (i.e., since midnight)
sec <- as.numeric(as.POSIXct(s, tz = "GMT", format = "%H:%M:%S")) %% (12*60*60)
# angle of each hand, clockwise from vertical, in radians
hour_ang <- 2*pi * (sec / (12*60*60)) # hour makes a circuit every 12*60*60 sec
min_ang <- 2*pi * ((sec / 60^2) %% 1) # min makes a circuit every 60*60 sec
sec_ang <- 2*pi * ((sec / 60) %% 1) # sec makes a circuit every 60 sec
hour_to_min_ang <- (2*pi + min_ang - hour_ang) %% (2*pi)
min_to_hr_ang <- (2*pi + hour_ang - min_ang) %% (2*pi)
if(hour_to_min_ang < min_to_hr_ang){
return(ifelse(sec_ang > hour_ang & sec_ang < min_ang,
"Smaller Area","Larger Area") )
} else if(min_to_hr_ang < hour_to_min_ang){
return(ifelse(sec_ang > min_ang & sec_ang < hour_ang,
"Smaller Area","Larger Area") )
} else return("Equal")
}
which_region("06:00:00") # Equal
which_region("01:10:00") # Larger Area
which_region("01:20:15") # Smaller Area
which_region("05:10:20") # Smaller Area
which_region("12:00:00") # Equal
which_region("21:55:50") # Smaller Area
which_region("10:55:15 PM") # Larger Area

Highstock custom min max approximation works properly only at some ranges

I am feeding highstock chart with datas from mysql. There are variables stored every minute so if you want to look at data past 3 months they are grouped. Highstock's default approximation functions give low,high,averare,sum values only. I min and max values are most important for me so I made my own approximation function which is:
approximation: function (arr) {
// first time or point precalculated
if ( !gInfo || gInfo.nextPoint) {
// first time return first value (arr[0])
var point = gInfo ? gInfo.nextPoint : arr[0];
// save current data to the next iteration
gInfo = {prev : arr, nextPoint : null};
return point;
} else {
var prev = gInfo.prev,
// concat current group with the previous one
data = prev.concat(arr),
// get min, max and their positions
min = Math.min.apply(null, data),
max = Math.max.apply(null, data),
minIdx = data.indexOf(min),
maxIdx = data.indexOf(max),
// order min and max
aprox = minIdx < maxIdx ? [min, max] : [max, min];
// save next aproximation and return current
gInfo.nextPoint = aprox[1];
return aprox[0];
}
},
Actually I didn't make it but I found it here in the forum.
The problem is it gives me right results only at some ranges as shown in the pictures below:
First picture at max range - not ok:
Max range - you can't see every min value
As I am changing range to smaller I can see every min value:
This is how it should looke like at max range
It is also happening when I zoom in so datas are grouped in two min intervals and I am just scrolling to the left or to the right.
At first I thought that it has something to do with the way groups are made by changing groupPixelWidth: to any value did not help.
Having min or max is really important for me and this is something I can solve in highstock.
There seems to an error in approximation function.
In 3rd line:
if ( !gInfo || gInfo.nextPoint) {
if should evaluate to false if !gInfo is false (it is after first time) AND gInfo.nextPoint returns false, but it will return false not only if it is null (as set in function), but also when it is zero. Changing if condition to:
if (!gInfo || gInfo.nextPoint !== null) {
Example with error (before the fix): http://jsfiddle.net/p2qvx24a/1/
Example with fix: http://jsfiddle.net/p2qvx24a/

Getting wrong answer when trying to get k subsets from Array in ActionScript

I'm working on a Texas Holdem game and i need to generate all possible k subsets from an Array of cards (represented as numbers in this example). This is how it looks so far:
public function getKSubsetsFromArray(arr:Array, k:int):Array {
var data:Array = new Array();
var result:Array = new Array();
combinations(arr, data, 0, arr.length - 1, 0, k, result, 0);
return result;
}
public function combinations(arr:Array, data:Array, start:int, end:int, index:int, r:int, resultArray:Array, resultIndex:int):int {
if (index == r) {
trace(resultIndex, data);
resultArray[resultIndex] = data;
return ++resultIndex;
}
for (var i:int = start; i<=end && end-i+1 >= r-index; i++) {
data[index] = arr[i];
resultIndex = combinations(arr, data, i + 1, end, index + 1, r, resultArray, resultIndex);
}
return resultIndex;
}
I am new to Actionscript, my idea is to have a function that takes an array of number and a parameter k, and returns an Array of arrays each of size k. However once i test the functions I get an array containing only the last combination nCk times. For example:
var testArray:Array = new Array(1, 2, 3, 4, 5);
trace(getKSubsetsFromArray(testArray, 3));
Returns:
0 1,2,3
1 1,2,4
2 1,2,5
3 1,3,4
4 1,3,5
5 1,4,5
6 2,3,4
7 2,3,5
8 2,4,5
9 3,4,5
The function output is
3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5
Of course it should print an array containing all the combinations listed before but it only prints the last one the right amount of times.
Thank your for your help.
The reason for the error is that when you are making array of arrays you are actually using the reference of the same array (data) so when the last combination is executed the contains of data array become 3,4,5 and each of index of resultArray points to data array so it prints out same values.
Solution :-
if (index == r) {
trace(resultIndex, data);
var result = new Array();
copy(result,data)
resultArray[resultIndex] = result;
return ++resultIndex;
}
Note :-
The above is pseudo code as i am not familiar with actionscript but you can implement copy function that copies values of data into result in actionscript syntax.

Resources