2013-01-17 154 views
10

有沒有人知道一種方法來打開contourLines多邊形的輸出,以便繪製爲填充的輪廓,如filled.contours。爲了查看所有可用的層次,是否有關於如何繪製多邊形的命令?下面是代碼的示例代碼段不起作用:如何將輪廓線變成填充的輪廓?

#typical plot 
filled.contour(volcano, color.palette = terrain.colors) 

#try 
cont <- contourLines(volcano) 
fun <- function(x) x$level 
LEVS <- sort(unique(unlist(lapply(cont, fun)))) 
COLS <- terrain.colors(length(LEVS)) 
contour(volcano) 
for(i in seq(cont)){ 
    COLNUM <- match(cont[[i]]$level, LEVS) 
    polygon(cont[[i]], col=COLS[COLNUM], border="NA") 
} 
contour(volcano, add=TRUE) 

enter image description here

+0

不能找到一個完整的解決方案,但使用'輪廓(火山,加= TRUE)'已經解決了你的部分問題或? –

+0

謝謝@thijsvandenbergh - 我希望得到實際的多邊形,以嘗試將這些投影到另一個網格上。 –

+0

,我沒有得到,但這可能是有幫助的:[link](http://stackoverflow.com/questions/12849623/in-r-how-does-one-place-multiple-filled-contour-plots-in-一個單一設備) –

回答

7

使用該raster封裝(它調用rgeossp)中的溶液。輸出爲SpatialPolygonsDataFrame,將覆蓋在網格的每個值:

library('raster') 
rr <- raster(t(volcano)) 
rc <- cut(rr, breaks= 10) 
pols <- rasterToPolygons(rc, dissolve=T) 
spplot(pols) 

Here's a discussion會告訴你如何簡化(「美化」)所產生的多邊形。

enter image description here

+0

很好地回答 - 人們可以看到,上面的評論中,輪廓確實在中心位置回落。釷'你的顏色選擇留下一個想知道:-) :-) –

+0

謝謝@諾阿 - 這是一個很好的方法。無論如何,意味着學習'raster'包的功能。乾杯。 –

4

感謝來自this網站一些靈感,我的工作了一個功能輪廓線轉換爲填充的輪廓。它設置爲處理柵格對象並返回一個SpatialPolygonsDataFrame。

raster2contourPolys <- function(r, levels = NULL) { 

    ## set-up levels 
    levels <- sort(levels) 
    plevels <- c(min(values(r), na.rm=TRUE), levels, max(values(r), na.rm=TRUE)) # pad with raster range 
    llevels <- paste(plevels[-length(plevels)], plevels[-1], sep=" - ") 
    llevels[1] <- paste("<", min(levels)) 
    llevels[length(llevels)] <- paste(">", max(levels)) 

    ## convert raster object to matrix so it can be fed into contourLines 
    xmin <- extent(r)@xmin 
    xmax <- extent(r)@xmax 
    ymin <- extent(r)@ymin 
    ymax <- extent(r)@ymax 
    rx <- seq(xmin, xmax, length.out=ncol(r)) 
    ry <- seq(ymin, ymax, length.out=nrow(r)) 
    rz <- t(as.matrix(r)) 
    rz <- rz[,ncol(rz):1] # reshape 

    ## get contour lines and convert to SpatialLinesDataFrame 
    cat("Converting to contour lines...\n") 
    cl <- contourLines(rx,ry,rz,levels=levels) 
    cl <- ContourLines2SLDF(cl) 

    ## extract coordinates to generate overall boundary polygon 
    xy <- coordinates(r)[which(!is.na(values(r))),] 
    i <- chull(xy) 
    b <- xy[c(i,i[1]),] 
    b <- SpatialPolygons(list(Polygons(list(Polygon(b, hole = FALSE)), "1"))) 

    ## add buffer around lines and cut boundary polygon 
    cat("Converting contour lines to polygons...\n") 
    bcl <- gBuffer(cl, width = 0.0001) # add small buffer so it cuts bounding poly 
    cp <- gDifference(b, bcl) 

    ## restructure and make polygon number the ID 
    polys <- list() 
    for(j in seq_along([email protected][[1]]@Polygons)) { 
    polys[[j]] <- Polygons(list([email protected][[1]]@Polygons[[j]]),j) 
    } 
    cp <- SpatialPolygons(polys) 
    cp <- SpatialPolygonsDataFrame(cp, data.frame(id=seq_along(cp))) 

    ## cut the raster by levels 
    rc <- cut(r, breaks=plevels) 

    ## loop through each polygon, create internal buffer, select points and define overlap with raster 
    cat("Adding attributes to polygons...\n") 
    l <- character(length(cp)) 
    for(j in seq_along(cp)) { 
    p <- cp[cp$id==j,] 
    bp <- gBuffer(p, width = -max(res(r))) # use a negative buffer to obtain internal points 
    if(!is.null(bp)) { 
     xy <- SpatialPoints(coordinates([email protected][[1]]@Polygons[[1]]))[1] 
     l[j] <- llevels[extract(rc,xy)] 
    } 
    else { 
     xy <- coordinates(gCentroid(p)) # buffer will not be calculated for smaller polygons, so grab centroid 
     l[j] <- llevels[extract(rc,xy)] 
    } 
    } 

    ## assign level to each polygon 
    cp$level <- factor(l, levels=llevels) 
    cp$min <- plevels[-length(plevels)][cp$level] 
    cp$max <- plevels[-1][cp$level] 
    cp <- cp[!is.na(cp$level),] # discard small polygons that did not capture a raster point 
    df <- unique([email protected][,c("level","min","max")]) # to be used after holes are defined 
    df <- df[order(df$min),] 
    row.names(df) <- df$level 
    llevels <- df$level 

    ## define depressions in higher levels (ie holes) 
    cat("Defining holes...\n") 
    spolys <- list() 
    p <- cp[cp$level==llevels[1],] # add deepest layer 
    p <- gUnaryUnion(p) 
    spolys[[1]] <- Polygons([email protected][[1]]@Polygons, ID=llevels[1]) 
    for(i in seq(length(llevels)-1)) { 
    p1 <- cp[cp$level==llevels[i+1],] # upper layer 
    p2 <- cp[cp$level==llevels[i],] # lower layer 
    x <- numeric(length(p2)) # grab one point from each of the deeper polygons 
    y <- numeric(length(p2)) 
    id <- numeric(length(p2)) 
    for(j in seq_along(p2)) { 
     xy <- coordinates([email protected][[j]]@Polygons[[1]])[1,] 
     x[j] <- xy[1]; y[j] <- xy[2] 
     id[j] <- as.numeric([email protected][[j]]@ID) 
    } 
    xy <- SpatialPointsDataFrame(cbind(x,y), data.frame(id=id)) 
    holes <- over(xy, p1)$id 
    holes <- xy$id[which(!is.na(holes))] 
    if(length(holes)>0) { 
     p2 <- p2[p2$id %in% holes,] # keep the polygons over the shallower polygon 
     p1 <- gUnaryUnion(p1) # simplify each group of polygons 
     p2 <- gUnaryUnion(p2) 
     p <- gDifference(p1, p2) # cut holes in p1  
    } else { p <- gUnaryUnion(p1) } 
    spolys[[i+1]] <- Polygons([email protected][[1]]@Polygons, ID=llevels[i+1]) # add level 
    } 
    cp <- SpatialPolygons(spolys, pO=seq_along(llevels), proj4string=CRS(proj4string(r))) # compile into final object 
    cp <- SpatialPolygonsDataFrame(cp, df) 
    cat("Done!") 
    cp 

} 

它可能存在一些低效率,但它在我使用海底測量數據進行的測試中運行良好。下面是使用了火山的數據爲例:

r <- raster(t(volcano)) 
l <- seq(100,200,by=10) 
cp <- raster2contourPolys(r, levels=l) 
cols <- terrain.colors(length(cp)) 
plot(cp, col=cols, border=cols, axes=TRUE, xaxs="i", yaxs="i") 
contour(r, levels=l, add=TRUE) 
box() 

enter image description here

+0

這並不壞,但並非所有多邊形都是空間排斥的 - 嘗試添加plot(cp [4,],add = T,col ='black')' - 這會導致分析和可視化問題陰謀順序,排除透明度等)。 gDifference'可能是你的朋友。 – geotheory

2

大廈保羅經常的出色工作,這裏是應該確保專屬的多邊形(即不重疊)的一個版本。

我已經爲仙塵添加了新參數fd,以解決我發現的使用UTM類型座標的問題。基本上,據我所知,算法的工作原理是通過從輪廓線中取樣側面點來確定內部的哪一側是多邊形。如果採樣點與線路的距離結束,則會產生問題。在另一輪廓之後。所以,如果你得到的多邊形看起來錯誤嘗試設置fd將值10 ^±N個,直到它看起來非常錯誤的或有關的權利..

raster2contourPolys <- function(r, levels = NULL, fd = 1) { 
    ## set-up levels 
    levels <- sort(levels) 
    plevels <- c(min(values(r)-1, na.rm=TRUE), levels, max(values(r)+1, na.rm=TRUE)) # pad with raster range 
    llevels <- paste(plevels[-length(plevels)], plevels[-1], sep=" - ") 
    llevels[1] <- paste("<", min(levels)) 
    llevels[length(llevels)] <- paste(">", max(levels)) 

    ## convert raster object to matrix so it can be fed into contourLines 
    xmin <- extent(r)@xmin 
    xmax <- extent(r)@xmax 
    ymin <- extent(r)@ymin 
    ymax <- extent(r)@ymax 
    rx <- seq(xmin, xmax, length.out=ncol(r)) 
    ry <- seq(ymin, ymax, length.out=nrow(r)) 
    rz <- t(as.matrix(r)) 
    rz <- rz[,ncol(rz):1] # reshape 

    ## get contour lines and convert to SpatialLinesDataFrame 
    cat("Converting to contour lines...\n") 
    cl0 <- contourLines(rx, ry, rz, levels = levels) 
    cl <- ContourLines2SLDF(cl0) 

    ## extract coordinates to generate overall boundary polygon 
    xy <- coordinates(r)[which(!is.na(values(r))),] 
    i <- chull(xy) 
    b <- xy[c(i,i[1]),] 
    b <- SpatialPolygons(list(Polygons(list(Polygon(b, hole = FALSE)), "1"))) 

    ## add buffer around lines and cut boundary polygon 
    cat("Converting contour lines to polygons...\n") 
    bcl <- gBuffer(cl, width = fd*diff(bbox(r)[1,])/3600000) # add small buffer so it cuts bounding poly 
    cp <- gDifference(b, bcl) 

    ## restructure and make polygon number the ID 
    polys <- list() 
    for(j in seq_along([email protected][[1]]@Polygons)) { 
    polys[[j]] <- Polygons(list([email protected][[1]]@Polygons[[j]]),j) 
    } 
    cp <- SpatialPolygons(polys) 
    cp <- SpatialPolygonsDataFrame(cp, data.frame(id=seq_along(cp))) 

    # group by elev (replicate ids) 
    # ids = sapply(slot(cl, "lines"), slot, "ID") 
    # lens = sapply(1:length(cl), function(i) length(cl[i,]@lines[[1]]@Lines)) 

    ## cut the raster by levels 
    rc <- cut(r, breaks=plevels) 

    ## loop through each polygon, create internal buffer, select points and define overlap with raster 
    cat("Adding attributes to polygons...\n") 
    l <- character(length(cp)) 
    for(j in seq_along(cp)) { 
    p <- cp[cp$id==j,] 
    bp <- gBuffer(p, width = -max(res(r))) # use a negative buffer to obtain internal points 
    if(!is.null(bp)) { 
     xy <- SpatialPoints(coordinates([email protected][[1]]@Polygons[[1]]))[1] 
     l[j] <- llevels[raster::extract(rc,xy)] 
    } 
    else { 
     xy <- coordinates(gCentroid(p)) # buffer will not be calculated for smaller polygons, so grab centroid 
     l[j] <- llevels[raster::extract(rc,xy)] 
    } 
    } 

    ## assign level to each polygon 
    cp$level <- factor(l, levels=llevels) 
    cp$min <- plevels[-length(plevels)][cp$level] 
    cp$max <- plevels[-1][cp$level] 
    cp <- cp[!is.na(cp$level),] # discard small polygons that did not capture a raster point 
    df <- unique([email protected][,c("level","min","max")]) # to be used after holes are defined 
    df <- df[order(df$min),] 
    row.names(df) <- df$level 
    llevels <- df$level 

    ## define depressions in higher levels (ie holes) 
    cat("Defining holes...\n") 
    spolys <- list() 
    p <- cp[cp$level==llevels[1],] # add deepest layer 
    p <- gUnaryUnion(p) 
    spolys[[1]] <- Polygons([email protected][[1]]@Polygons, ID=llevels[1]) 
    for(i in seq(length(llevels)-1)) { 
    p1 <- cp[cp$level==llevels[i+1],] # upper layer 
    p2 <- cp[cp$level==llevels[i],] # lower layer 
    x <- numeric(length(p2)) # grab one point from each of the deeper polygons 
    y <- numeric(length(p2)) 
    id <- numeric(length(p2)) 
    for(j in seq_along(p2)) { 
     xy <- coordinates([email protected][[j]]@Polygons[[1]])[1,] 
     x[j] <- xy[1]; y[j] <- xy[2] 
     id[j] <- as.numeric([email protected][[j]]@ID) 
    } 
    xy <- SpatialPointsDataFrame(cbind(x,y), data.frame(id=id)) 
    holes <- over(xy, p1)$id 
    holes <- xy$id[which(!is.na(holes))] 
    if(length(holes)>0) { 
     p2 <- p2[p2$id %in% holes,] # keep the polygons over the shallower polygon 
     p1 <- gUnaryUnion(p1) # simplify each group of polygons 
     p2 <- gUnaryUnion(p2) 
     p <- gDifference(p1, p2) # cut holes in p1  
    } else { p <- gUnaryUnion(p1) } 
    spolys[[i+1]] <- Polygons([email protected][[1]]@Polygons, ID=llevels[i+1]) # add level 
    } 
    cp <- SpatialPolygons(spolys, pO=seq_along(llevels), proj4string=CRS(proj4string(r))) # compile into final object 

    ## make polygons exclusive (i.e. no overlapping) 
    cpx = gDifference(cp[1,], cp[2,], id=cp[1,]@polygons[[1]]@ID) 
    for(i in 2:(length(cp)-1)) cpx = spRbind(cpx, gDifference(cp[i,], cp[i+1,], id=cp[i,]@polygons[[1]]@ID)) 
    cp = spRbind(cpx, cp[length(cp),]) 

    ## it's a wrap 
    cp <- SpatialPolygonsDataFrame(cp, df) 
    cat("Done!") 
    cp 
}