library(XML) useStyle = TRUE if(!exists("temperature") || class(temperature) != "data.frame") { # This version has intentional errors. load(url("http://eeyore.ucdavis.edu/stat32/Data/Temperature.rda")) temperature$level = cut(temperature$temp, 4) } # Generate some colors to use to represent the different levels of temperature temperatureColors = rev(rainbow(length(levels(temperature$level)))) f = # # loop over the cities and process each of the specified # months # # function(showImages = FALSE, style = "me", months = levels(temperature$month)) { invisible( by(temperature, temperature$city, function(city) { name = strsplit(city[1, "city"], ",")[[1]][1] tt$addNode("Folder", close = FALSE) tt$addNode("name", name) by(city, city$month, function(row) { tt$addNode("Placemark", attrs = c(id = row[1, "city"]), close = FALSE) mnth = as.character(row[1, "month"]) label = if(length(months) > 1) paste(row[1, "temp"], mnth) else row[1, "temp"] tt$addNode("name", label) if(showImages) { tt$addTag("IconStyle", close = FALSE) tt$addTag("Icon", close = FALSE) tt$addTag("href", imageName(city[1, "city"])) tt$closeNode() tt$closeNode() } else { tt$addNode("styleUrl", paste("#", style, sep = "")) } tt$addNode("TimeStamp", close = FALSE) tt$addNode("when", paste("1997", sprintf("%02d", match(mnth, month.name)), sep = "-")) #tt$closeNode() tt$closeNode() if(length(months) > 1) { # we don't need the table now that we have desc = list(name, "", c("", paste("", sep = ""), ""), c("", paste("", sep = ""), ""), "
", months, "
", city$temp, "
", c("")) desc = paste(sapply(desc, paste, collapse = ""), collapse = "\n") tt$addNode("description", close = FALSE) tt$addCData(desc) tt$closeNode() # description } else { desc = paste("Temperature for", city, row["temp"], "in", mnth) tt$addNode("description", desc) } tt$addNode("Point", close = FALSE) tt$addNode("coordinates", paste(- as.numeric(row["longitude"]), row["latitude"], sep = ", ")) tt$closeNode() # Point tt$closeNode() # Placemark # should be one closeTag(2) }) # Ground Overlay to show the time series curve of temperature across the 4 months. tt$addNode("GroundOverlay", close = FALSE) tt$addNode("name", city[1, "city"]) tt$addNode("Icon", close = FALSE) tt$addNode("color", "#88FFFFFF") tt$addTag("href", imageName(city[1, "city"])) tt$closeNode() tt$addNode("LatLonBox", close = FALSE) off = c(.5, .5)*3 loc = as.numeric(city[1, c("longitude", "latitude")]) box = c(north = loc[2] + off[2], south = loc[2] - off[2], east = -loc[1] + off[1], west = -loc[1] - off[1]) sapply(names(box), function(i) tt$addNode(i, box[i])) tt$closeNode() # LatLonBox tt$closeNode() # GroundOverlay tt$closeNode() # Folder }) ) } imageName = function(city, full = FALSE, mini = FALSE, ext = "png") { id = gsub("[ ,]", "_", city) if(is.logical(full)) { if(full) id = paste("file://", getwd(), id, sep = .Platform$file.sep) } else id = paste(full, id, sep = .Platform$file.sep) if(mini) id = paste(id, "mini", sep = "_") id = paste(id, ext, sep = ".") id } makeHist = function(z, device = png, ylim = range(z$temp), full = FALSE, mini = FALSE, cols = temperatureColors) { # cols = rainbow(length(levels(z$level))) id = imageName(z[1, "city"], full, mini = mini) if(!is.null(device)) { device(id, width = 300, height = 300, bg = "transparent") on.exit(dev.off()) } plot(z$temp, xlab = "", ylab = "", axes = FALSE, ylim = ylim, col = cols[z$level]) segments(1:3, z$temp[1:3], 2:4, z$temp[2:4], col = cols[z$level], lwd = if(mini) 2 else 30) axis(2) id } createHist = function(data = temperature, f = makeHist, full = "/tmp", mini = FALSE) { invisible(by(data, factor(data$city), f, ylim = range(data$temp), full = full, mini = mini)) } createLegend = function(values, filename = "/tmp/legend.png", colors = temperatureColors) { library(lattice) library(grid) key.width = 8 levels = values$level if(length(filename) && nchar(filename) > 0) { trellis.device(png, filename = filename, bg = "transparent") on.exit(dev.off()) } trellis.par.set(axis.text = list(col = "white", cex=1.2, font=2)) # print(simpleKey(levels(levels?dra), rectangles = list(TRUE, col = rainbow(4))) breaks = c(min(values$temp), by(values$temp, values$level, max)) k = list(at = breaks, labels = as.character(breaks), col= colors, width= key.width ) draw.colorkey(key = k, draw = TRUE, viewport(height = unit(.9, "npc"))) } # Create the KML document tt = xmlTree("kml", namespaces = c("http://earth.google.com/kml/2.1")) tt$addTag("Document", close = FALSE) # Put a little HTML description of what we are displaying. tt$addTag("description", 'Illustrates the temperatures of 50 different cities at 4 different times of the year.\nGenerated from R by Duncan Temple Lang') # A top-level, global style to which we can refer within Placemarks, etc. if(useStyle) { tt$addTag("Style", attrs = list(id = "me"), close = FALSE) tt$addTag("IconStyle", close = FALSE) tt$addTag("scale", .35) tt$addTag("color", "#FFFF0000") tt$closeNode() tt$addTag("LabelStyle", close = FALSE) tt$addTag("scale", 1) # note the alpha-blue-green-red order tt$addTag("color", "#FFFFFF00") tt$closeNode() tt$closeNode() } f() # Create the screen overlay that will display the legend in the lower left corner. # The legend should have no margins in R. tt$addNode("ScreenOverlay", close = FALSE) tt$addNode("name", "Temperature legend") tt$addNode("Icon", "legend.png") tt$addNode("screenXY", attrs = c("x" = 2, "y" = 2, xunits = "pixels", yunits = "pixels")) tt$addNode("overlayXY", attrs = c("x" = 0, "y" = 0)) tt$addNode("size", attrs = c("x" = 300, "y" = 300, xunits = "pixels", yunits = "pixels")) tt$closeNode() # ScreenOverlay tt$closeNode() # KML root node saveXML(tt, "/tmp/doc.kml") system("open /tmp/doc.kml") system("zip /tmp/CityTemperatures.kmz /tmp/doc.kml /tmp/*.png")