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.

5
  • 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
    Commented Jan 12, 2014 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
    Commented Jan 12, 2014 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 gis.stackexchange.com/questions/11019 for an example of what can be done when you merely identify the mouth of each river.
    – whuber
    Commented Jan 12, 2014 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
    Commented Jan 12, 2014 at 22:21
  • If the river lines are digitised in the direction of flow (or the reverse), then you won't necessarily need a DEM. You could create a graph data structure, and then compare the position of the nodes relative to each other. i.e. if a node is between a dam and the final leaf node, then it is downstream of the dam. This would be much more efficient than using a DEM, if that matters. Commented Aug 6 at 0:10

2 Answers 2

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.

6
  • You could use something similiar to this : 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 ) Commented Jan 23, 2014 at 12:45
  • 1
    Thanks so much @Zbynek for the thorough answer. I will try this out and see if it helps
    – sckott
    Commented Jan 23, 2014 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
    Commented Jan 23, 2014 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. Commented Jan 24, 2014 at 7: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
    Commented Jan 24, 2014 at 16:10
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 Pro toolbox that can generate these sorts of metrics, worth a look to give you some ideas.

3
  • 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
    Commented Jan 12, 2014 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! rpubs.com/edzer/6767
    – Spacedman
    Commented Jan 21, 2014 at 8:20
  • 1
    Found my effort: rpubs.com/geospacedman/runninguphill - again requires a DEM or spot-heights to compute flow direction.
    – Spacedman
    Commented Jan 21, 2014 at 8:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.