Monday, 2 November 2015

Building attribute table in 3-band raster using ArcGIS Desktop?


I have a 3-band (RGB) raster file from CORINE and the attribute table hasn't been built. When I try to execute the command BuildRasterAttributeTable I get an error that only single band rasters are allowed. What should I do to get the attribute with the land uses?


Error Message:



ERROR 000423 Only single band integer raster dataset is a valid input






arcgis javascript api - How to configure web map data layer that can accept csv data uploaded by user?


I made this map: http://tinyurl.com/a368268 on arcgis online. How do I get the same map but instead you can upload a new csv every time? Instead of having to first add it as data layer on arcgis online and then configure pop ups after doing that. I basically want what I made but be able to upload a new csv with new data but in the same format. The fields I'm using currently are:


ImageName,Latitude,Longitude,PicURL




arcgis javascript api - How do I use the Terrain with Labels basemap in the Map constructor


Seems like all the other basemaps can be used in the esri.Map() constructor, but this one doesn't have a corresponding entry in the list of acceptable values. I've tried just "terrain", and it didn't work.



Answer



You can combine the two layers as a single Basemap and pass them to the map constructor. Below is a full working example using the two layers you are interested in.


This came from a discussion we had over on github related to using non-mercator maps as basemaps for the Configurable Map Viewer (cmv) that is based on the ESRI JS API.


This does not fully address your additional requirement to save the basemap with the user settings but perhaps gives you an idea on how to proceed. There might be additional details in that discussion related to the BaseMap widget that would be helpful for you. One of the tricks there was to include no basemap at all (or a blank one) and allow the BaseMap widget to determine the starting basemap. Something like that might work for your requirement to save the basemap.








Simple Map












UPDATE:


While answering a question over at the cmv github repository, it occurred to me that there is another solution that may get you closer to what you desire. The available basemaps are just an object within the esri.config.defaults.map. You can add your own custom basemaps to that object and they are treated like the standard ESRI basemaps. The advantage of this approach is you can refer to the basemap id in the map constructor and thus that id can be saved in the user settings as you desired. Here's a full example:








Simple Map











arcpy - How to remove layers that are not in visible df extent


I am working on ArcMap 10.3 and I have a map with 50 layers in it.


I am trying to check if layers are in a data frame.


Unlike How to check if layers in a dataframe with Arcpy, I want to define the area to the current data frame.



My code is:


import arcpy,os,sys,string
import arcpy.mapping
from arcpy import env


env.workspace = r"C:\Project"
for mxdname in arcpy.ListFiles('*.mxd'):
print mxdname
mxd = arcpy.mapping.MapDocument(r"C:\Project\\" + mxdname)

df = arcpy.mapping.ListDataFrames(mxd, "Layers")[0]
data_frame = df
for lyr in arcpy.mapping.ListLayers(mxd,"",df):
if lyr in data_frame == False:
arcpy.mapping.RemoveLayer(df, lyr)
print lyr
mxd.save()
del mxd

and I get:



 >>> 
Project.mxd
>>>

but no layers have been removed.



Answer



The Extent object supports a 'disjoint' (i.e. does not intersect) method.


Try something like:


for mxdname in arcpy.ListFiles('*.mxd'):


print mxdname
mxd = arcpy.mapping.MapDocument(os.path.join(env.workspace, mxdname))
df = arcpy.mapping.ListDataFrames(mxd, "Layers")[0]
for lyr in arcpy.mapping.ListLayers(mxd, "" ,df):
if df.extent.disjoint(lyr.getExtent()):
arcpy.mapping.RemoveLayer(df, lyr)
print lyr

mxd.save()


del mxd

python - Seeking tool in QGIS similar to ArcGIS Combine?


I am wondering if there is a way/tool in QGIS (2.6) could produce similar output as ArcGIS "Combine" tool does. I am trying to integrate values from overlapping rasters, and then create a single raster with unique value for each unique combination of input values. If there is a tool in QGIS could be used to get that will be the best. If not, should I using a script to automate reading through each pixel values? I am afraid it will take a large amount of time to processing national-wide data.


Here is the link to document for the "Combine" tool: http://desktop.arcgis.com/en/arcmap/10.3/tools/spatial-analyst-toolbox/combine.htm



Answer



Not tried it myself, but the GRASS algorithm r.stats will give total areas for each combination of cell values in multiple rasters. It seems to available (in 2.16 at least) via Processing.


The output isn't a raster though, it's a table, and it doesn't assign a new category number to each unique combination.


It will save you the trouble working out how to count how many cells have each combination, though. It also allows binning (e.g. aggregating over ranges of values like 0-9, 10-19, 20-29 etc.)


If it's an exact duplicate of the Arc functionality it would certainly be possible using Python and Numpy


Sunday, 1 November 2015

Calculating average stream slope at each location along stream using ArcGIS Desktop?


I'm trying to calculate the time of concentration for every point along a stream network. To calculate the time of concentration, I need the upstream channel length and channel slope.


I've been able to calculate the upstream channel length at each pixel using the Hydrology/Flow Length (upstream) tool (See image - red corresponds to longer cumulative channel length):


Upstream channel length


However, I have not been able to estimate the overall channel slope at each pixel (i.e. the slope between the pixel in question to the furthest-upstream headwater pixel). I know you can do this for individual basins (i.e. for one pixel), but my study area is very large (longest channel is 500+ km), so I dont want to generate a "watershed" for every single stream pixel, as this will be too time consuming.


I have also tried calculating the flow length with a slope raster as the "input weight raster," (and then dividing the result by the flow length raster (with no weight raster) to get the average slope along the stream, but this is far overestimating the overall stream slope.


Essentially, I need to find a way to make a map of the headwater elevation corresponding to any pixel in the stream network. Then I can subtract the elevation at each pixel and divide by the upstream channel length to get the overall stream slope.


(I'm using ArcGIS 10.1, Basic License)




Here is the error message I'm getting when I use the python script presented below (after running for 1 hour and getting through half of the points):



error message



Answer



As @Hornbydd pointed it is network searching problem. I suggest the following workflow:



  1. find source points of the streams

  2. sort them in descending order by flow length


In the picture below 139 green points are sources labelled by their sequential order and elevation, e.g. remotest point (1/435).


Screen shot


There are 2 possible paths from here:




  • Trace and dissolve streams downstream from each source node, to calculate what I call ‘long rivers’

  • Spatially join (intersect) stream points that represent your streams (one to many) to long rivers

  • Select points with minimum long river ID and add to points table relevant elevation.


This is pretty much or close to what @Hornbydd is suggesting.


Alternatively run flow accumulation multiple times for each point (139 in my example), using its sequential number as weight raster.


Use cell statistics to compute minimum. This will give source point ID etc


UPDATE:


I’ll elaborate on raster approach because network searching is boring.




  1. Use Stream to Feature (do not simplify lines) to convert stream raster to polylines. If in doubt re sources location, use stream order tool. First point of stream orders 1 is source.

  2. Convert starts of (selected) polylines to points.

  3. Extract multi-values to points from Flow Length and DEM rasters.


Sort points using Flow Length field in descending order, output to SHAPEFILE, call this layer “SOURCES” in current mxd. It’s table should look like this:


Screen shot


Add flow direction raster to mxd and call it “FDIR”


Set environment extent equal FDIR extent, raster analysis cell size to one in FDIR.


Modify output folder and output grid name in below script and run it from mxd.



import arcpy, os, traceback, sys
from arcpy import env
from arcpy.sa import *

env.overwriteOutput = True
outFolder=r"D:\SCRATCH\GRIDS"
outGrid=r"fromELEV"
env.workspace = outFolder
try:
def showPyMessage():

arcpy.AddMessage(str(time.ctime()) + " - " + message)

mxd = arcpy.mapping.MapDocument("CURRENT")
SOURCES=arcpy.mapping.ListLayers(mxd,"SOURCES")[0]
FDIR=arcpy.mapping.ListLayers(mxd,"FDIR")[0]
SOURCES.definitionQuery=""

aTable=arcpy.da.TableToNumPyArray(SOURCES,("ID","DEM"))
victim ='VICTIM'
fd=arcpy.Raster(FDIR.name)

one=Con(fd>0,0)

for ID,Z in aTable:
arcpy.AddMessage('Processing source no %s' %ID)
dq='"ID"=%s' %ID
SOURCES.definitionQuery=dq
arcpy.PointToRaster_conversion(SOURCES, "DEM", victim)
facc = FlowAccumulation(FDIR, victim, "FLOAT")
two=Con(one==0,facc,one)
one=two

# REMOVE LINE BELOW AFTER TESTING
if ID==10:break

SOURCES.definitionQuery=""
two=Con(one!=0,one)
two.save(outGrid)
arcpy.Delete_management(victim)

except:
message = "\n*** PYTHON ERRORS *** "; showPyMessage()

message = "Python Traceback Info: " + traceback.format_tb(sys.exc_info()[2])[0]; showPyMessage()
message = "Python Error Info: " + str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"; showPyMessage()

OUTPUT: Note sources labelled by ID,flow length and elevation. After processing last source it will take some time for script to finish! I guess it is ArcGIS removing all temporary rasters created during the run.


enter image description here


UPDATE 2 hopefully last


My bad, try this out. It is much faster:


import arcpy, os, traceback, sys
from arcpy import env
from arcpy.sa import *


env.overwriteOutput = True
outFolder=r"D:\SCRATCH\GRIDS"
outGrid=r"fromELEV"
env.workspace = outFolder
NODATA=-9999.0
try:
def showPyMessage():
arcpy.AddMessage(str(time.ctime()) + " - " + message)


mxd = arcpy.mapping.MapDocument("CURRENT")
SOURCES=arcpy.mapping.ListLayers(mxd,"SOURCES")[0]
FDIR=arcpy.mapping.ListLayers(mxd,"FDIR")[0]
fd=arcpy.Raster(FDIR.name)
one=Con(fd>0,NODATA)
dirArray = arcpy.RasterToNumPyArray(fd,"","","",NODATA)
nRows,nCols=dirArray.shape
blankArray=arcpy.RasterToNumPyArray(one,"","","",NODATA)
del one
ext=arcpy.Describe(FDIR).extent

origin=ext.lowerLeft
yMax,xMin=ext.YMax,ext.XMin
cSize=fd.meanCellHeight
## directions to find neighbour
fDirs=(1,2,4,8,16,32,64,128)
dCol=(1, 1, 0, -1, -1,-1, 0,1)
dRow=(0, -1, -1, -1, 0, 1, 1,1)
## flipped
dRow=(0, 1, 1, 1, 0, -1, -1,-1)
aDict={}

for i,v in enumerate(fDirs):
aDict[v]=(dCol[i],dRow[i])

with arcpy.da.SearchCursor(SOURCES,("Shape@","ID","DEM")) as cursor:
for shp,ID, Z in cursor:
arcpy.AddMessage('Processing source no %s' %ID)
p=shp.firstPoint
nR=int((yMax-p.Y)/cSize)
nC=int((p.X-xMin)/cSize)
while True:

blankArray[nR,nC]=Z
direction=dirArray[nR,nC]
if direction==NODATA:break
dX,dY=aDict[direction];nC+=dX
if nC not in range(nCols): break
nR+=dY
if nR not in range(nRows): break
S=blankArray[nR,nC]
if S!=NODATA: break


myRaster = arcpy.NumPyArrayToRaster(blankArray,origin,cSize,cSize)
oneGrid=Con(myRaster<>NODATA,myRaster)
oneGrid.save(outGrid)
del dirArray,blankArray

except:
message = "\n*** PYTHON ERRORS *** "; showPyMessage()
message = "Python Traceback Info: " + traceback.format_tb(sys.exc_info()[2])[0]; showPyMessage()
message = "Python Error Info: " + str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"; showPyMessage()

qgis - How to create a buffer around a point that takes terrain elevation in account?


In QGIS, I am creating a few different buffer around points to simulate walking distances. For example, 10 minutes walk about 800m at 5km/h. Using population density, I then clip a population layer which gives me the population that is within a 10 min walk from those points. I am working on a hilly city where elevation does matter.


How can I adjust the buffer with elevation?





arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...