0

I have extracted a list of 160+ IP addresses from participants to a survey that I would like to plot on a world map. Wondering if there is an R package for that. I also have the IPs in a CSV column.

user3412574
  • 11
  • 1
  • 3
  • 1
    Using an external service is fine for geolocation of a handful of addresses. I've got a pkg - https://gitlab.dds.ec/public/projects/bob.rudis/iptools - that uses the maxmind C API in an Rcpp-based package to do the geo-conversion. But, there's usually little efficacy in plotting IP addresses on a map in general and even more so from a surveymonkey (et al) CSV log. Someone could have filled the form in while on a business trip or using Tor, so why plot where they were (or may have been) at the time of the survey from the IP logs? Finally, bar charts by country, or CC+subregion wld be better IMO – hrbrmstr Aug 14 '14 at 19:14

3 Answers3

3

Here's a way using www.freegeoip.net to geocode the IP addresses, and ggplot to make the map.

# some IP addresses - you have this already...
ips <- c(Louvre           ="213.139.122.103",
         British.Museum   ="195.224.71.221",
         Museo.del.Prado  ="213.27.146.137",
         Grand.Egyptian   ="163.121.93.15",
         Hermitage.Museum ="213.152.151.197",
         MBNA             ="200.218.240.120",
         Sydney.Museum    ="54.252.89.136",
         MOMA             ="63.117.124.131")

# you start here...
library(XML)
library(httr)
library(ggplot2)
get.geocode <- function(ip) {  # returns lat/long given an ip address
  url   <- "http://www.freegeoip.net"
  xml   <- content(GET(url,path=paste("xml",ip,sep="/")),type="text/xml")
  xpath <- c(lat="//Latitude",long="//Longitude")
  sapply(xpath,function(xp) as.numeric(xmlValue(xml[xp][[1]])))
}
locs <- data.frame(t(sapply(ips,get.geocode)))
library(ggplot2)
ggplot(locs, aes(x=long,y=lat))+ 
  borders("world", color="grey50", fill="grey90")+
  geom_point(color="red", size=3)+
  labs(x="",y="")+
  theme_bw() + theme(axis.text=element_blank(),axis.ticks=element_blank())+
  coord_fixed()

A note of caution. The RDSTK package is a wrapper for the Data Science Toolkit API. While I love the idea, I've found that DSK is a bit quirky. Among other things it does not necessarily find every legitimate IP address. For instance, when I run the other answer with the dataset above, it only finds 4 of the 8 IPs. Also, their "bulk" API, which uses POST to grab multiple results at once, does not necessarily work the same way as it's GET interface (which grabs one result per http request). See this post.

If this was for a client, I would use one of the commercial web services (MaxMind for instance) to geocode the IP addresses and work from that. With only 160 IPs it would cost you almost nothing.

Also, borders(...) uses the worldHires dataset in the mapdata package, which as you can see, is not great. I'd be inclined to download a better dataset, for instance the world map on GADM.

Community
  • 1
  • 1
jlhoward
  • 58,004
  • 7
  • 97
  • 140
  • amazing. It's a bit cumbersome to put brackets and commas around all the ips, but it works – user3412574 Aug 14 '14 at 01:48
  • Not sure what you mean. There's no need to put brackets or commas around the ips. – jlhoward Aug 14 '14 at 02:08
  • what I meant is that it only seems to work in this format: ips <- c("76.119.124.150", "95.221.113.183", "66.59.43.125", "97.85.63.55", "80.47.42.230", "178.125.207.129", "74.236.208.211", "66.213.122.190", "87.183.45.242", "37.190.49.39", "171.33.251.112", "108.208.235.0"). Whereas this doesn't ips <- c( 76.119.124.150 95.221.113.183 66.59.43.125 97.85.63.55 etc..) – user3412574 Aug 14 '14 at 23:21
  • That's true but where are the ips coming from? If you read them into R from a text file using `read.table(...)` or `read.csv(...)` they will import a character (or factor more likely). In either case the code should work. – jlhoward Aug 15 '14 at 00:05
1

Here's one way to do it:

# grab example data
library(XML)
tab <- readHTMLTable("http://www.ip-adress.com/proxy_list/", which = 1)[-1, c(1, 3)]
names(tab) <- c("ip.address", "country")
tab$ip.address <- sub(":.*", "", tab$ip.address)

# ip to location
library(RDSTK)
loc <- ip2coordinates(ip = paste(tab$ip.address, collapse=", "))
df <- merge(x = tab, y = loc, by = "ip.address", all.x = TRUE)
na.omit(df) # print matches

# plot
library(rworldmap)
par(mar = rep(0, 4)) 
plot(getMap())
with(df, points(x = longitude, y = latitude, col = "red", pch = 19))

enter image description here

You may have to install the packages XML, RDSTK and rworldmap.

lukeA
  • 53,097
  • 5
  • 97
  • 100
0

You would need to break up the work into several processes.

  1. Map IP to lat-long coordinates. Refer Geocode an IP address? or look for APIs that provide this.

  2. Pass your IP to API using httr::get or Rcurl. Returning format will be in JSON or XML (most of the cases), and you would need RJSONIO or XML libraries to parse to lat long

  3. Worldmap You can use maps, rworldmap packages (or ggmap...) to create a map. Then project your lat-long using any method of your choice (as point..)

The question you asked is more complex than you think, and you would perhaps want to ask separate questions or search for answers in each of the steps above.

Community
  • 1
  • 1
won782
  • 696
  • 1
  • 4
  • 13