Setting user defined workspace using raw_input

2381
7
10-08-2012 11:08 AM
noamrozenfeld
New Contributor III
Hi,
This should be easy enough, but i'm stuck on it for days:
I want to write a script (not using a parameter) that before performing the specific action (buffer, copy, or whatever)
will ask the user where is the workspace, and he (the user) will copy-paste it into a raw_input box
(meaning the script has to contain an option to add a backslash to each backslash).
Than, the env.workspace will be defined based on what was pasted into the raw_input box.

Thanks for any help!
Tags (2)
0 Kudos
7 Replies
by Anonymous User
Not applicable
You could do something like this:

ws = raw_input('Please Copy and Paste Worspace Environment\n')
arcpy.env.workspace = r'%s' % ws


This will allow you to use the user input as the workspace.  You may want to add some code to make sure the workspace exists though.
0 Kudos
noamrozenfeld
New Contributor III
Thanks for the super fast answer!
Works great!
Thanks!

Moving along the script, next, i would like for example to Clip some features.
Now, each of the clip parameters can differ at each run of the script (the source layer, the target layer and the output name)

How can I do this? (without definning them as parameters in a toolbox)
Should I use the raw_input again for each parameter?
if so, I can't use the arcpy.env.workspace = r'%s' %CSTFC for the source layer for example,

so how do i define the raw_input result as the in feature for the clip command?


Thanks for any help
0 Kudos
by Anonymous User
Not applicable
Thanks for the super fast answer!
Works great!
Thanks!

Moving along the script, next, i would like for example to Clip some features.
Now, each of the clip parameters can differ at each run of the script (the source layer, the target layer and the output name)

How can I do this? (without definning them as parameters in a toolbox)
Should I use the raw_input again for each parameter?
if so, I can't use the arcpy.env.workspace = r'%s' %CSTFC for the source layer for example,

so how do i define the raw_input result as the in feature for the clip command?


Thanks for any help


Using the raw_input() function is the "non-script tool" way of getting parameters as text when used in combination with the %s (which is a parameter substitution for string, I think?), so I suppose the answer to your question is yes.  You can use raw input for each parameter if you want to use this without having to use Arc at all.  If you wanted to run a clip process using only user input you can use raw input as much as you want instead of GetParameterAsText().  If you just want to clip all the features in the workspace that is provided and ask the user to also define the clip boundary you could do something like this:

import arcpy, os, sys, traceback
ws = raw_input('Please Copy and Paste Worspace Environment\n')
arcpy.env.workspace = r'%s' % ws
arcpy.env.overwriteOutput = True

# Local variables
folder = 'Clipped_features'

try:
    if arcpy.Exists(ws):
        arcpy.CreateFolder_management(ws, folder)
        clip_feat = raw_input('Copy and paste full path of clip boundary feature\n')
        fclist = arcpy.ListFeatureClasses()
        for fc in fclist:
            arcpy.Clip_analysis(fc, clip_feat, os.path.join(folder, fc))
            print 'Clipped: ' + fc

    else:
        print 'Workspace does not exist or is not supported'


I use the raw input function all the time for when I am too lazy to make script tools.  It can be a good work around if you do not want to use script tools.

If you wanted to add an SQL query for the clip boundary features you could add this to the above script.  I do this for queries sometimes too like this:

field = raw_input('type field name')
value = raw_input('type value')
cliplyr = clip_feat.split('.')[0]
query = "%s" = '%s'  % (field, value)
arcpy.MakeFeatureLayer_management (clip_feat, cliplyr, query)  # sub cliplyr in the clip tool if query is used


If I type City for the field and Chicago (assuming these are valid field names and unique values) for the value it will work just like any other query and read as:

"City" = 'Chicago'
0 Kudos
noamrozenfeld
New Contributor III
Wow! great answer! Thanks.

I would use your generosity farther more, if i may:
The script you've written takes all the layers in a workspace and clips them all.
If I would like to create a list, from which the user can pick the layers he would like to clip (and not all in the workspace),
how would i do that?


Thanks
0 Kudos
by Anonymous User
Not applicable
One way would be to use a wildcard or feature type.  The syntax for listing feature classes has optional parameters for using a wildcard, feature type, and/or a feature dataset.  You could make these optional parameters as well by asking the user if they want to use them with raw_input (y or n)  and using if statements to check for their answer.

arcpy.ListFeatureClasses ({wild_card}, {feature_type}, {feature_dataset})


However, this can be tricky for the user.  and may not be ideal for picking out individual layers.  Instead I would suggest two options that I can think of off the top of my head:

1. listing the full paths for user so they can copy and paste which ones they want to clip and use each fc they choose as input for clipping.

2. or setting up a menu that counts the number of feature classes and gives each one an index.  Then the user could just pick a number that indexes the fc from the menu.

Or if you change your mind about not using a script tool you could take a look at these two script tools I recently wrote (see attachment).  One does the whole workspace clip (BatchClip.py), and the other allows for the option to pick out individual feature classes (BatchClip2.py).  There are several other versions of batch clip tools floating around out there but I decided to make my own so that I could add an option SQL query and an optional buffer.

EDIT:  I just took another look at my BatchClip2.py script and noticed that the "if" semicolon check is unnecessary since 0 semicolons will still reference the index[0] of the first input of the in features.  That block can be taken out.
0 Kudos
ChristopherThompson
Occasional Contributor III
Here is one approach that works on a single workspace.  It creates a list of features in a user provided workspace, creates a dictionary from the list where the dictionary KEY is the list index, prints the key and values to the IDE screen (IDLE, PythonWin, etc.) so the user can see those, then prompts the user to input a list of the dictionary keys to perform the selection on.  The list that is created from from this (clip_list) can then be the input to your clipping routine.

Adding functionality to this to work on multiple workspaces would be simple enough - the user could input a comma delimited list of workspaces, and then the tool could iterate through those.  In theory anyway :cool:

To run, save the script to a file with a .py extension, then navigate to that and open it with the IDE of your choice, and run.  It works for me but possibly YMMV.

import arcpy,sys
from arcpy import env
ws = raw_input('Copy/paste the pathname of the folder containing feature classes to select from):  ')

env.workspace = ws
feats = arcpy.ListFeatureClasses()

# function prints text to the IDE window
def prn_screen(txt):
    sys.stdout.write(txt+'\n')
    sys.stdout.flush()

feat_dict = {} #creates an empty dictionary
# populates above dictionary from the list of features, where the key is
# essentially the index of the featureclass in the list
for x in range(len(feats)):
    feat_dict = feats

#simply prints the dictonary keys and associated values so the user can see these
for key,value in feat_dict.iteritems():
    display = str(key) + " : " + str(value)
    prn_screen(display)
    
# entering a number is easier than typing featureclass names, avoiding seplling errors :)
clip_keys = raw_input('Enter the number for each featureclass you want to clip, commas separating each entry: ')
idx_list = []
#converts the raw_input string to a list of numbers that match the dictionary keys
idx_list += map(int,clip_keys.split(','))
clip_list = []
for idx in idx_list:
    clip_list.append(feat_dict[idx])
0 Kudos
by Anonymous User
Not applicable
Wow Christopher! Very cool! Thanks for posting this! I have been looking for a good example of creating a dictionary like this.
0 Kudos