One of the most useful tools in decision making, especially for feedback to the ongoing project approach, is being able to see a lot of different visualizations of the most current information set you have. I've been looking at rgl for producing 3D plots, and was wondering how it would fit with typical 3d drill data. Up until now this has been possible with specialist proprietary software (or using expensive consultants), but this approach is not optimal in terms of cost, responsiveness or turnaround time.
So I very quickly generated some synthetic drill data, and used plot3d from the rgl library to try and produce a grade map of the sort that would be useful for target indication. It took almost no time at all:
Something I found handy was the ability to tinker with the color, size scaling, and alpha by adding basic parameters to curve or shift the scaling factors.
Playing around with these massively helped visualization (for me anyway) by allowing observation of subtly different summaries of the data.
If you have an OpenGL supporting browser, you can download a spinnable version here. Remember to unzip it.
So as a rudimentary tool for visualization, it's been great, and took no time. As a follow up to this, I think that I could pretty quickly do the following (and will publish here when I do):
- Add a Shiny Wrapper to make it interactive
- Add some interpolative and sampling functions to mimic the continuous block model generation of commercial packages
- Add other information to map in faults, economic cut-offs etc.
Here's the commented code for the map (and data generation) for those who are interested:
######################################################### ## PRELIMINARIES ## ######################################################### ## load required packages require(rgl) # 3d package require(RColorBrewer) # color package for ramp creation ######################################################### ## MAKE TEST DATA ## ######################################################### ## make some data that looks like mining data for drilling of a surface ore body ## this represents 144 holes drilled at 25m intervals on a 300 m square grid ## each hole is 50 m long (sampled at 2m intervals) ## each hols in drilled on a bearing of 30%, and at 55% from surface ## obviously in the real world you'd have real data which is why these repeat ## the ore grade is set to 0 as a placeholder dg<-data.frame(expand.grid(seq(0,300,25),seq(0,300,25),seq(0,-50,-2)),0,30,55) colnames(dg)<-c("X","Y","Z","grade","bearing","downholedeg") ######################################################### ## FUNCTIONS TO PREPARE IN ADVANCE ## ######################################################### genGrade<-function(vec,g){ ## This function generates grade data, clustering higher values ## in the middle of the series (what you'd expect in a mine), ## and adding some random noise ## Also allows shift on x, y & z with input g ## basically it's just making dirty x^y curves and centering them vec<-vec-((max(vec)-min(vec))/2)-min(vec) vec<-abs(vec)+g vec<-1/vec^g vec<-vec*runif(length(vec),1,2) vec<-vec/max(vec) vec<-vec+runif(length(vec),-0.1,0.5) return(vec) } scaleColors <- function(colors, vec) { ## This function scales a set of colors to any numeric vector ## basically creating a discrete scale ## and mapping to rgb colors for plot3d to understand scaletoUnit <- (vec - min(vec))/diff(range(vec)) x <- colorRamp(colors)(scaletoUnit) rgb(x[,1], x[,2], x[,3], maxColorValue = 255) } scaleAlpha <- function(vec,maxa=1,mina=0,pwr=1) { ## This function creates a discrete scale which maps to alpha values ## typically 0 to 1, although it allows for a superset or subset ## and has a raise to power factor to increase or decrease the hi/lo differential scaletoUnit <- (vec - min(vec))/diff(range(vec)) x<-min(mina,maxa)+(scaletoUnit*abs(maxa-mina)) x<-x^pwr return(x) } scaleSize <- function(vec,base=0,factor=1,pwr=1) { ## This function creates a discrete scale for size ## Again the power factor allows you to de/emphasize the tail scaletoUnit <- (vec - min(vec))/diff(range(vec)) x<-base+(scaletoUnit*factor)^pwr return(x) } absCoords<-function(xrel,yrel,zdepth,hangle,zangle,xabs=0,yabs=0){ ## This converts the x(rel),y(rel),z(depth) numbers to useful "real" co-ordinates realz<-zdepth*sin(zangle) realx<-(-realz*sin(zangle)*cos(hangle))+xrel+xabs realy<-(-realz*sin(zangle)*sin(hangle))+yrel+yabs return(data.frame(X=realx,Y=realy,Z=realz)) } ######################################################### ## FUNCTION TO MAKE THE PLOT DATA FOR THE GRAPH ## ######################################################### ## First in the right shape dg$grade<-genGrade(dg$X,2)*genGrade(dg$Y,3)*genGrade(dg$Z,4) ## Then scale it to 0-20 maximum (this is arbitrary, still creating data) dg$grade<-abs(dg$grade)*(20/max(dg$grade)) ## Then call the function to make the co-ordinates abolute dg[,1:3]<-absCoords(xrel=dg$X,yrel=dg$Y,zdepth=dg$Z, hangle=(2*pi*dg$bearing/360),zangle=(2*pi*dg$downholedeg/360), xabs=208,yabs=1102) ######################################################### ## NOW CALL THE PLOTS ## ######################################################### plot(dg$grade) # This is a simple 2d plots so I can eyball the distributions myDrillBlock<-plot3d (x = dg$X, y = dg$Y, z = dg$Z, col = scaleColors(c("yellow","red"),dg$grade), size=scaleSize(dg$grade,base=2.4,factor=2.5,pwr=1.5), alpha=scaleAlpha(dg$grade,pwr=0.8), xlab="Distance N from reference point (m)", ylab="Distance E from reference point (m)", zlab="Vertical depth from surface (m)", type="s") ######################################################### ## AND HERE YOU CAN CALL OUT TO A LOCAL URL ## ######################################################### ## This is a complete html OpenGL file format ## If you want to persist or share the graph ## you can save as "Web Page Complete" and share it ## with anyone who has a Chrome browser browseURL( paste( "file://", writeWebGL(dir=file.path(tempdir(), "myDrillBlock"), width=700), sep="") )
No comments:
Post a Comment