Pages

banner ads

Friday, April 26, 2013

mapping people flying between cities

A couple of weeks ago, I was interested in how the Facebook Friendship Map was created using R. Here is my learning experience. After reading a few blogs about the Facebook chart and mapping in general. I was able to create very similar chart. It is super interesting.

Here is my rendering of a sample data set with number of flights between cities for a day. My sample data has a concentration of flights for USA. Curves with blue color tells us that there is more flights than curves with grey colors. One can make out visually the boundary of the continents. It is not nearly as nice as the original. But I am happy that I got this far! A few more tweaks might make it much better.



Following is the rough process to get there.
1. Getting familiar with the Orientation of the R map is very important. Longitude [-180, 180] and Latitude [-100, 100] basically are x, y ranges for the space. Here is a few points, lines and curves to illustrated the layout the map.

library(maps)
library(geosphere)
#mapping test

map("world", col="#f2f2f2", fill=TRUE, bg="white", lwd=0.01) #, xlim=xlim, ylim=ylim)

segments(0,0,100,100, col='red', lwd=2)
lines(c(0,-100 ),c(0,-100), col='blue',lwd=2)
points(180,0,col='red',lwd=2)
points(-180,0,col='red',lwd=2)
points(1:10*-10, 1:10*10, col='red',lwd=2)
inter <- gcIntermediate(c(-100,40), c(140,-37.331979), n=50, addStartEnd=TRUE, breakAtDateLine=T)
inter1 <- gcIntermediate(c(100,40), c(140,-37.331979), n=50, addStartEnd=TRUE, breakAtDateLine=T)
lines(inter1,col='red')


2.  The curvature is another key concept which needs careful design. I draw a curve from China to Australia on above chart. gcIntermediate() function is great in drawing arc over two points on the map. However, there are a few things deserve mentioning. First of all, breakAtDateLine=T is needed so that we don't end up with a lot of horizontal lines cross the map which connects dateline. Secondly, the arc is pretty high sometimes which visually is not pretty. I think a bit work could be done to make the arc lower. I will save the work to be next blog.

3. Finally, in order to create a nice chart with an arc between many pairs of points, one needs a few tricks to manage the rendering of color and layout.Background color and arc color could be easily changed. Example code is included here.


trip=read.csv("od_cnt.csv",header=T)
trip=read.csv('odpairs.csv',header=T)
fsub <- trip
maxcnt <- max(fsub$count_itiniery)
fsub <- fsub[order(fsub$count_itiniery),]

pal <- colorRampPalette(c("#f2f2f2", "red"))
pal <- colorRampPalette(c('grey',"blue", "white"))
colors <- pal(100)


pdf("test4.pdf",height=100,width=120)
map("world", col="black", fill=F, bg="black", lwd=1) #,xlim=xlim, ylim=ylim)



for (i in 1:length(fsub$count_itiniery)) {
#for (i in 1:100) {
  inter <- gcIntermediate(c(fsub[i,]$orig_long, fsub[i,]$orig_lat), c(fsub[i,]$dest_long, fsub[i,]$dest_lat), n=100, addStartEnd=TRUE,breakAtDateLine=T)
  #inter <-greatCircle(c(fsub[i,]$orig_long, fsub[i,]$orig_lat), c(fsub[i,]$dest_long, fsub[i,]$dest_lat), n=100, sp=F)
  #inter <- clean.Inter(c(fsub[i,]$orig_long, fsub[i,]$orig_lat), c(fsub[i,]$dest_long, fsub[i,]$dest_lat),n=100, addStartEnd=TRUE)
  colindex <- round( (fsub[i,]$count_itiniery / maxcnt) * length(colors) )
  lenwd<- (fsub[i,]$count_itiniery / maxcnt)
  if (length(inter)>2) {
  # lines(inter, col=colors[colindex], lwd=lenwd)
  lines(inter, col=colors[colindex], lwd=lenwd)
  }
  else {
    lines(inter[[1]],col=colors[colindex],lwd=lenwd)
    lines(inter[[2]],col=colors[colindex],lwd=lenwd)
  }
}
dev.off()

No comments:

Post a Comment