3

I have a set of fish species occurrences (lat/long) as points and set of rivers as lines. The fish species can of course only occur in the rivers (and not on land).

I would like to determine whether these points fall up or downstream of a point on the river (like a dam for example).

The way I think may work is to convert the river to a polygon with a small buffer around the polygon to include points that weren't exactly in the river (but should be). Then break up the new polygon to that below the dam, and that above.

Then do a spatial overlay, e.g., over(points, line_downstream) and over(points, line_upstream) to get that set of points down and upstream of the dam.

Is this the correct approach. If so, any tips on the code for this? I have tried converting lines to polygons and creating a buffer, but no success yet.

p.s. I did notice a similar question done in ArcGIS - I need to do this in R.

sckott
  • 153
  • 1
  • 6
  • 1
    Don't you have a DEM of your study area? Because water tends to flow downhill, any point with a lower elevation than your reference point (dam or whatever) would be downstream. That leads to a very efficient simple solution. – whuber Jan 12 '14 at 16:58
  • Good idea. I could get DEM's, but I'm trying to do it with points for occurrences and lines for rivers. – sckott Jan 12 '14 at 18:04
  • 2
    In principle you cannot succeed without additional information like that afforded by a DEM: given an arbitrary polyline representing part of a river system, it is not possible to determine which way the water flows. Sometimes it's obvious to the eye, but remember that the visual pattern of a large watershed is not a whole lot different from that of a river delta. You don't need much more information, though: see http://gis.stackexchange.com/questions/11019 for an example of what can be done when you merely identify the mouth of each river. – whuber Jan 12 '14 at 18:45
  • Good point. I hadn't thought about needing to know the direction of flow. I'll look into that, and DEMs – sckott Jan 12 '14 at 22:21

2 Answers2

3

You can use function snapPointsToLines from the package maptools. It will not only snap the fish location to the nearest river, but also give you the id of the nearest river.

snappedFish <- snapPointsToLines(fish, rivers)
snappedFish$nearest_line_id

Than, you can calculate stationing of point on that line

# function to decide, if point is on the line segment
pointOnLine <- function(point,line_start,line_end){ # each of parameters is pair x;z
  if(identical(point,line_start) | identical(point,line_end)){return(TRUE)}
  if(point[1]>max(c(line_start[1],line_end[1])) | point[1]<min(c(line_start[1],line_end[1])) | point[2]>max(c(line_start[2],line_end[2])) | point[2]<min(c(line_start[2],line_end[2]))){
    return(FALSE)
  }
  if(line_start[2]==line_end[2]){
    slope<-0
  } else if(line_start[1]==line_end[1]){
    return(T)
  } else {
    slope <- (line_start[2]-line_end[2])/(line_start[1]-line_end[1])
  }
  intercept <- -slope*line_start[1] + line_start[2]
  onLine <- round(point[2],digits=0)==round((slope*point[1]+intercept),digits=0)
  return(onLine)
}

#### here is just a pseudocode, you will have to iterate through all fish locations
pointCrds <- coordinates(fishLocation)
# get the river a fish location is on
coords <- coordinates(nearestRiver)[[1]][[1]]

position <- 0
# calculate stationing from the start
d <- 0
for(j in 2:nrow(coords)){
  onLine <- pointOnLine(point=pointCrds,line_start=coords[j-1,],line_end=coords[j,])
  if(onLine){
    d0 <- sqrt((pointCrds[1]-coords[j-1,1])^2 + (pointCrds[2]-coords[j-1,2])^2)
    position <- round(d+d0)
    break
  }
  d <- d + sqrt((coords[j,1]-coords[j-1,1])^2 + (coords[j,2]-coords[j-1,2])^2)
}

#d is the distance of fish location from the start on given river

The second task is to decide, whether that nearest river is upstream or downstream, which is more difficult and the approach would depend on the structure of your data.

Zbynek
  • 443
  • 3
  • 10
  • You could use something similiar to this : http://blog.cleverelephant.ca/2010/07/network-walking-in-postgis.html , to solve correct order of linestring from start point ( river exit to ocean or dam ) – simpleuser001 Jan 23 '14 at 12:45
  • 1
    Thanks so much @Zbynek for the thorough answer. I will try this out and see if it helps – sckott Jan 23 '14 at 17:04
  • It appears this solution assumes the river coordinates are stored in a consistent order (from their 'start') in every reach of the river. Ensuring that is the case actually is the hardest part of this question! – whuber Jan 23 '14 at 18:25
  • I assume that @whuber means network topology cleaning. Yes, it is hard to fix network perfectly, getting it good enough is easier. – simpleuser001 Jan 24 '14 at 07:46
  • @simplexio You're on the right track, but this is more than an issue of topology: the topology can be perfectly consistent while having all directions reversed. In such cases this solution will work without failure or any warning messages but it will produce incorrect results. – whuber Jan 24 '14 at 16:10
  • Indeed, didn't notice that example handled only one direction (i usually handle both directions ) – simpleuser001 Jan 27 '14 at 08:21
1

I've never used R so not sure what it is capable of with regards to hydrological tools, but it can be done in one of two ways:

  1. Snap your sites to the network then do a network search from your test point (e.g. dam). Any points intersecting the network as you search upstream must be upstream of the dam. The rest of your sites are either in entirely different catchments or are downstream of your dam but could potentially be up another tributary.
  2. The second approach is to generate a catchment boundary from a DEM for your dam. Then it is a simple point in polygon test to determine if the point is upstream of your dam. Again the rest of your sites are either in entirely different catchments or are downstream of your dam but could potentially be up another tributary.

RivEX is an ArcGIS 10.2 AddIn that can generate these sorts of metrics, worth a look to give you some ideas.

Hornbydd
  • 43,380
  • 5
  • 41
  • 81
  • Thanks for the tips. I'll see if there's any way to do a network search in R. Yep, you're right on DEM's. I will look for those. – sckott Jan 12 '14 at 22:24
  • For that you want the igraph package and to create a directed graph representing your stream network. That's tricky, since you are creating topology from a set of topologically unrelated SpatialLine segments. The osmar package can create graph networks from OpenStreetMap data but I think that already has the topology in it. I also have a feeling I've done this a while ago... Or actually Edzer has! http://rpubs.com/edzer/6767 – Spacedman Jan 21 '14 at 08:20
  • 1
    Found my effort: http://rpubs.com/geospacedman/runninguphill - again requires a DEM or spot-heights to compute flow direction. – Spacedman Jan 21 '14 at 08:28