Thursday, March 21, 2013

Code for the spaghetti plot active viewer



I have occasionally posted active viewers of spaghetti plots - most recently the Marcott proxies. There has been interest in how it's done, so I am posting here a fairly generic code. A combination of R and Javascript is required, although I've been able to make the Javascript work from data, so it doesn't have to be specially written for each plot. The work is done in R.


So I'll post the R code and make the Javascript available in a zip file. In R, the spaghetti plot is made, and then a minimal plot with transparent background is made of each component curve, in black. These are png files. The Javascript organises the superposition of them.

Everything you need should be on this zip file. You need to run your data through the makejs() R routine, then display the active.html file.
Update 11.47am 21/3 GMT I fixed something in the zip file

The R program

The key element of the R program is the function makejs(). This takes arguments similar to what you would supply to a spaghetti plot routine. The first, xy, is a list of 2-column coordinate matrices, one for each curve. Then xlim, ylim are the x and y ranges, eg c(0,9). These are all required, as is a vector of labels for each curve, to go in the clickable table.

Then there are inputs with defaults. met is a vector of metadata to be displayed with each visible curve, one string of HTML for each. Default is "", which means no display. Fil is a vector with first component a directory, and second a filename prefix. The directory and prefix will be attached to graphics files, and the directory is passed to the Javascript.

In the program as shown, I then assemble the inputs for the Marcott proxies and run the function. Outputs are the spaghetti plot, black line plots and a file called prox.js, which carries information to the Javascript.

HTML and Javascript

It's best at this stage to run with all files in the same directory, with the images in a subdirectory. The html is called active.html, and you can run it locally. Just click in the file explorer. Files you should have there are:
active.html, prox.js
reddot.gif, X.png, X101.png et seq, and Xkey.png (the table).
X is your file prefix (input to makejs()); images should be in your designated graphics dir.

The Marcott stuff uses prox.sav as data - also on the zip.

The R program code


# This program was written by Nick Stokes, www.moyhu.blogspot.com Mar 21 2013, to process input for a complex plot, and to output the graphics and js files for an active plotter. Describes at: www.moyhu.blogspot.com
# Made available under the terms of the GNU GPL

#The key routine is makesjs(), which can be used generally.
#I am using it here for the Marcott et al proxies, described
#https://moyhu.blogspot.com.au/2013/03/an-active-viewer-for-marcott-et-al.html

makejs=function(xy,xlim,ylim,lab,met="",Fil=c("./","proxy")){
N=length(xy); fil=paste(Fil, collapse="")
# Working out the layout for the key
ii=round(sqrt(N/2));jj=N%/%ii+1;
iw=round(max(nchar(lab))*7.5);nw=iw*ii;nh=jj*18;
# Assembling data for javascript
b=sprintf('Yxdir=["%s","%s"]; YxT=[%s,%s,%s,%s,%s];',
Fil[1],fil,N,jj,ii,iw,18)
b=c(b,paste("Yxmet=['",paste(met,collapse="','"),"'];",sep=""))
write(b,file="prox.js")

# The spaghetti plot
cls=rainbow(N,v=0.99,end=0.9)
png(sprintf("%s.png",fil),width=wid)
plot(xlim,ylim,type="n",xlab="Years BP",ylab="proxy anomaly deg C")
for(i in 1:N){
lines(xy[[i]],col=cls[i])
}
dev.off()
# The black line plots
for(i in 1:N){
png(sprintf("%s%s.png",fil,100+i),width=wid)
par(bg="#ffffff00") # The transparent background
plot(xlim,ylim,type="n",axes=F,xlab="",ylab="")
lines(xy[[i]],lwd=2)
dev.off()
}
cls=rainbow(N,v=0.7,end=0.9) # darken the colors
# Now make the key - labels lab[]
png(sprintf("%skey.png",fil),width=nw,height=nh)
par(mai=c(0,0,0,0))
plot(c(0,nw),c(0,nh),type="n",xlim=c(0,nw),ylim=c(0,nh),xlab="",ylab="",axes=F,xaxs="i",yaxs="i")
for(i in 1:ii-1)for(j in 1:jj-1){
k=i*jj+j;
if(k<N) text(i*iw,nh-j*18-9,lab=lab[k+1], col=cls[k+1],pos=4);
}
dev.off()
} # End function makejs

## End of generic code. The rest is the Marcott example

# Make anomalies about tm period
anomalize=function(tm,xy){
for(i in 1:length(xy)){
p=xy[[i]]
y=approx(p[,1],p[,2],xout=tm)
xy[[i]][,2]=p[,2]-mean(y$y)
}
xy
}

load("prox.sav") # loading data from Marcott et el SM
wid=800
graphics.off()
cls=rainbow(73,v=1,end=0.9)
xlim=c(-50,11300); ylim=c(-5,5);
prox=anomalize(4500:5500,prox)
# Input xlim,ylim,xy,proxst
# xy is list(N) of nx2 matrices, one for each proxy (variable n)
# proxst is a Nx2 string - labels and metadata
lab=c("GeoB5844-2","ODP-1019D","SO136-GC11","JR51GC-35","ME005A-43JC","MD95-2043","M39-008","MD95-2011","ODP 984","GeoB 7702-3","Moose Lake","ODP 658C","MD95-2011;HM79-4","IOW225517","IOW225514","M25/4-KL11","ODP 1084B","AD91-17","74KL","74KL","NIOP-905","NIOP-905","MD01-2421; KR02-06","GeoB 3910","Dome C","GeoB 7139-2","Dome F","18287-3","GeoB 1023-5","GeoB 5901-2","KY07-04-01","Hanging Lake","GeoB 3313-1","Lake 850","Lake Nujulla","PL07-39PC","MD02-2529","MD98-2165","MD79-257","BJ8 13GGC","BJ8 70GGC","MD95-2015","Homestead Scarp","Mount Honey","GeoB 10038-4","TN05-17","MD97-2120","MD97-2121","17940","Vostok","D13822","M35003-4","OCE326-GGC26","OCE326-GGC30", "CH07-98-GGC19","GIK23258-2","GeoB 6518-1","Flarken Lake", "Tsuolbmajavri Lake","MD01-2390","EDML","MD98-2176","MD98-2181","A7" ,"RAPID-12-1K","NP04-KH3, -KH4","Agassiz & Renland","GeoB6518-1","MD03-2707","GeoB 3129","GeoB 4905","MD01-2378","MD02-2575");
lab=paste(1:73,lab)
# Make metadata strings
met=lab
s=c(" Proxy #","<br>Type: ","<br>Calibration: ","<br>Lat=",", Lon=",", Alt=",
"<br>Resolution = ","<br>Season: ","<br>Ref: ")
s=paste('<span style="color:blue">',s,'</span>',sep="")
for(i in 1:73){
p=meta[i,]
met[i]=sprintf("%s%s %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
s[1],p[1],p[2],s[2],p[3],s[3],p[4],s[4],p[5],s[5],p[6],s[6],p[7],s[7],p[8],s[8],p[9],s[9],p[10])
}
# Now run makejs()
makejs(prox,xlim,ylim,lab=lab,met=met,Fil=c("png/","prox"));

No comments:

Post a Comment