americanpanorama / panorama-foreignborn

Foreign-Born Population 1850-2010
8 stars 2 forks source link

Are the proportional circles calculated using area or radius? #1

Open almccon opened 8 years ago

almccon commented 8 years ago

On twitter someone asks if we're calculating our circle sizes correctly: https://twitter.com/mxfh/status/676939990169952256

Compare Mexico and Central America in 2000: http://dsl.richmond.edu/panorama/foreignborn/#decade=2000

screen shot 2015-12-15 at 6 08 18 pm

Mexico is 9,177,487, and Central America is 2.026,150.

If they were scaled linearly by radius, Mexico's circle would be 4.52 times wider.

However, on the map the circle is only 3 times wider (~300px vs ~100px).

screen shot 2015-12-15 at 6 07 17 pm screen shot 2015-12-15 at 6 07 41 pm

So I think we're doing it right. The radius is calculated on this line: https://github.com/americanpanorama/panorama-foreignborn/blob/master/app/components/DisjointedWorldLayout.jsx#L501, but it's using a function defined here https://github.com/americanpanorama/panorama-foreignborn/blob/master/app/stores/scales.js#L19-L21 which shows that we're using a sqrt function. So I think we're good.

mxfh commented 8 years ago

https://github.com/americanpanorama/panorama-foreignborn/blob/04f413aa8b59e2ce31cd69eb3d0296a796898ebe/app/stores/scales.js#L19 looks indeed alright, but the legend does something else:

image

mxfh commented 8 years ago

d3.scales.sqrt() does not behave well with ranges and domains length >2

var radius = d3.scale.sqrt()
  .domain([500000, 1000000, 1500000, 2000000])
  .range([12, 24, 36, 48]);

should be more like

var radius = d3.scale.sqrt()
  .domain([0, 2000000])
  .range([0, 48]);

and labels/breaks added via ticks, see http://bl.ocks.org/mxfh/6285470954cf4d207fd0

mxfh commented 8 years ago

This scale behaves not continuously as a square root function, the input domain between 500k and 2m is mapped linearly to the output range:

var testScale = d3.scale.sqrt().range([]).domain([500000, 1000000, 1500000, 2000000]).range([12, 24, 36, 48]);

testScale(0) // -16.970562748477143
testScale(172000) // 0.02111068445544717
testScale(500000) // 12 start of linear part
testScale(1000000) // 24
testScale(1500000) // 36
testScale(2000000) // 48 end of linear part
testScale(2500000) // 58.57221223283089
testScale(5000000) // 100.05215136300797
testScale(9000000) // 148.4357878494041
sconnelley commented 8 years ago

When specifying >2 values in the domain, the scale becomes a polypower scale as in "multiple piecewise power scales that divide a continuous domain and range". More documentation over here. Irregardless, I think I agree that the domain and range would be better set to a length of 2.

rnelson2 commented 8 years ago

changed to the following so it's both accurate and has the breakpoints to render four circles in the legend.

var radius = d3.scale.sqrt() .domain([500000, 1000000, 1500000, 2000000]) .range([12, 26.91, 38.35, 48]);

mxfh commented 8 years ago

Polypowered wizardy.

mxfh commented 8 years ago

How are these breaks calculated? I get different values when applying the unit area ratios to a factor of 48.

https://docs.google.com/spreadsheets/d/1rSxd3rfVgnQVxnDNdbTW2GBqNMbIc5OIBL9PbGpTrbk/edit#gid=0

resulting in

d3.scale.sqrt()
  .domain([0, 500000, 1000000, 1500000, 2000000])
  .range([0, 24, 33.9 , 41.6, 48]); 

comparing the scales: http://codepen.io/mxfh/full/pggXoW/

grey: old implementation red: current, blue: proposed new version, overlayed with simple non polypower version (orange)

image

for reference with sqrt x-axis (makes sqrt-curve a straight line starting from origin, if it is one): image

almccon commented 8 years ago

Here's @rnelson2's change, now pushed to the public repo: efec7e986b314922e414a4afff4d67f7e74dc2a7

almccon commented 8 years ago

Sorry @mxfh, I won't have time to think more deeply about those charts until January.

emilyhobson commented 8 years ago

To @almccon for consideration