GEOG 489
Advanced Python Programming for GIS

Lesson 2 Assignment

PrintPrint

In this lesson's homework assignment you are going to implement your own GUI-based Python program with PyQt5. We won't provide a template for the GUI this time, so you will have to design it yourself from scratch and put it together in QT Designer. However, we will provide a list of required GUI elements that will allow the user to provide the needed input for the program. The program will use arcpy but it is intended to be a standalone program, so it's not supposed to be run as a script tool inside ArcGIS, and that's why it needs its own GUI. The program will realize a simple workflow for extracting features from a shapefile on disk based on selection by attribute and selection by location. If you took Geog485 along time ago, you will notice that this is similar to what you did there in lesson 3 and you will also already be familiar with the data we will be using. If you took Geog485 more recently and did the assignment with NHL hockey players, it's still a similar approach using multiple selection operations but with different data. Even if it's unfamiliar, don't worry, we are intentionally keeping the feature extraction task simple and providing some sample code that you can use for this so that you can focus on the GUI development aspects.

Data

Please download the zip file assignment2data.zip with the data you will need for this homework project. Extract the data to a new folder and check out the two shapefiles that are contained in the zip file, countries.shp and OSMpoints.shp, in ArcGIS Pro. In particular, have a look at the attribute tables of the two files:

  • countries. shp - This shapefile contains polygons for the countries of Central America and will be used for the selection by location part of the project, namely to extract only features that are inside one of the countries. The field you will mainly be working with is the 'NAME' field containing the names of the countries. To test your program, you will mainly use 'El Salvador' for the country you are interested in because the data from the other shapefile is limited to an area in and around El Salvador.
screenshot image of the country data set in ArcMap
Country data set 
  • OSMpoints.shp - This is a point shapefile with Points of Interests (POIs) exported from OpenStreetMap. The file is a bit messy, has quite a few attribute fields, and combines all kinds of POIs. In this assignment, we will be working with the 'shop' field that, if the feature is some kind of shop, specifies what kind of shop it is, e.g. supermarket, convenience, bakery. Our program will either extract all shops in a target country or only shops of one particular type.
screenshot image of the OSM point data set in ArcMap
OSM point data set

The feature extraction task

Your program will provide the GUI that allows the user

  • to select the two input files (country file and POI file),
  • to provide the name of the target country,
  • to specifiy the name of the output shapefile that will be produced with the extracted shop features,
  • and to indicate whether all shops or only shops of a particular type should be extracted (and if so, which type).

Then, when the user clicks a button to start the feature extraction, your code will have to select those point features from the POI file that are at the same time (a) located inside the target country and (b) are shops (meaning the 'shop' field is not null and not an empty string) if the user wants all shops. If the user indicated that s/he is only interested in shops of a particular type, only shops of that specified type should be selected (meaning the 'shop' field needs to contain exactly that type for a POI to be selected). After realizing these selections, the selected features satisfying both criteria should be written to a new shapefile with the user-provided output file name.

Hopefully it is clear that this feature extraction can be realized with a combination of the arcpy functions MakeFeatureLayer_management(...), SelectLayerByLocation_management(....), CopyFeatures_management(...) and Delete_management(...). If not, you may want to briefly (re)read the parts of Lesson 3 of Geog485 that talk about these functions or the appropriate sections of the arcpy help. The field names 'NAME' and 'shop' can be hard-coded in your script but only once in variables defined at the beginning that are then used in the rest of the code (so that your code is easily modifiable in-line with good programming practices). As we mentioned at the beginning, we want you to focus on GUI code, so we are, below, providing some basic sample code for performing the extraction task that you can adopt. Of course, you are free to challenge yourself and ignore this code and develop a solution for this extraction part yourself.

# This code uses the following variables:
# polygonFile: input polygon file (e.g. file with countries)
# polygonField: name of field of the input polygon file to query on (e.g. 'NAME')
# polygonValue: value to query polygonField for (e.g. 'El Salvador')
# pointFile: input point file (e.g. file with points of interest)
# pointField: name of field of the input point file to query on (e.g. 'shop')
# pointValue: value to query pointField for (e.g. 'supermarket'); if this variable has the value None, all features with something in pointField will be included
# outputFile: name of the output shapefile to produce

# select target polygon from polygon file
polygonQuery = '"{0}" = \'{1}\''.format(polygonField, polygonValue)          # query string
arcpy.MakeFeatureLayer_management(polygonFile,"polygonLayer", polygonQuery)  # produce layer based on query string

# select target points from point file
if pointValue:   # not None, so the query string needs to use pointValue
    pointQuery = '"{0}" = \'{1}\''.format(pointField, pointValue)
else:            # pointValue is None, so the query string aks for entries that are not NULL and not the empty string
    pointQuery = '"{0}" IS NOT NULL AND "{0}" <> \'\''.format(pointField) 
arcpy.MakeFeatureLayer_management(pointFile,"pointLayer", pointQuery)        # produce layer based on query string

# select only points of interest in point layer that are within the target polygon    
arcpy.SelectLayerByLocation_management("pointLayer", "WITHIN", "polygonLayer")

# write selection to output file
arcpy.CopyFeatures_management("pointLayer", outputFile)

# clean up layers    
arcpy.Delete_management("polygonLayer")
arcpy.Delete_management("pointLayer")

You are expected to place the code that performs this feature extraction task in its own function and its own .py file that is completely independent of the rest of the code in the same way as we did in the lesson's walkthrough with the functions defined in the core_functions.py module. This extraction function needs to have parameters for all input values needed to perform the feature extraction task and produce the output shapefile.

It is definitely not a bad idea to start with producing the feature extraction function/module first (adopting the code from above) and in the code that calls the function use hard-coded input variables for all input values for thoroughly testing that function. Then only start with designing and implementing the GUI, once the feature extraction function is working correctly. As mentioned above, the provided test data mainly contains POI features for El Salvador but you can also test it with one of the adjacent countries that contain some of the point features.

The GUI

As already explained, the main focus of this project will be on designing the GUI for this program, putting it together in QT Designer, and then creating the GUI for the main project code and wiring everything up so that the input values are taken from the corresponding input widgets in the GUI when the button to run the feature extraction is clicked, and so on. These steps can be approached in the same way as we did in the lesson's walkthrough and the project will also have a similar structure.

Designing the GUI will require some creativity and you are free to decide how the different GUI elements should be arranged in your GUI. However, you should make sure that the elements are laid out nicely and the overall GUI is visually appealing. Even though this is just a "toy" project to practice these things, you should try to make your GUI look as professional as possible, e.g. don't forget to give your main window a suitable title, use labels to explain what certain widgets are for, group related widgets together, make adequate use of file dialog boxes and message boxes, etc.

Below is a list of elements that your GUI needs to provide and other requirements we have for your GUI and code. Please don't take the order in which the elements are listed here as the order in which they are supposed to appear in your GUI.

  • The GUI should contain a button to start the feature extraction for the input values provided via the other widgets.
  • The GUI should contain an input widget for the name of the country shapefile. There should be a corresponding button to open an "Open file" dialog box to pick the country shapefile (similar to how this was done in the Locations From Web Services tool; see, for instance, the code of the selectShapefile() function in Section 2.7.3.5).
  • The GUI should contain an input widget for the name of the POI point shapefile. There should be a corresponding button to open an "Open file" dialog box to pick the point shapefile (similar to how this was done in the Locations From Web Services tool; see, for instance, the code of the selectShapefile() function in Section 2.7.3.5).
  • The GUI should contain an input widget for the name of the output shapefile. There should be a corresponding button to open a "Save file" dialog box to pick the output shapefile name (similar to how this was done in the Locations From Web Services tool; see, for instance, the code of the selectNewShapefile() function in Section 2.7.3.5).).
  • The GUI should contain an input widget for entering the name of the target country (you are not required to create a list of available country names for this; a widget that allows the user to type in the name is ok for this, or a hardcoded list providing it is drawn from a variable defined at the top of the code).
  • The GUI should contain an input widget that lets the user indicate whether all shops or only shops of a particular type should be extracted with a single mouse button click. (This should be a separate widget from the following one for choosing a specific shop type if the user picks the "shops of a particular type" option!)
  • The GUI should contain an input widget that allows the user to pick a shop type from a given list of predefined types. You can use the following set of predefined shop types for this: [ 'supermarket', 'convenience', 'clothes', 'bakery' ]. Selecting one of the predefined types should be done by clicking, not by letting the user type in the name of the shop type.
  • Your program should capture errors and use message boxes to inform the user about errors or when the feature extraction has been performed successfully (see again how this is handled in the walkthrough code).
  • The GUI independent code to perform the actual feature extraction (see previous section) should be located in its own module which is imported by the main module of your project.
  • The usual requirements regarding code quality and use of comments apply; please make sure that you use intuitive names for the widgets that you are referring to from the main project code.

Successful completion of the above requirements and the write-up discussed below is sufficient to earn 90% of the credit on this project. The remaining 10% is reserved for "over and above" efforts which could include, but are not limited to, the following (implementing just the first two items is not sufficient for the full 10 points):

  • Providing helpful tool tip information for all main GUI elements.
  • Adding input widgets for the field names to replace the hard-coded values 'NAME' and 'shop'
  • Incorporating additional widgets that increase the flexibility of the tool (e.g. you could add support for providing a buffer radius that is applied to the country before doing the selection by location, or an optional projection operation to be applied to the output file using one of several predefined spatial reference system names the user can choose from).
  • Populating the list of shop types to choose from automatically with all unique values appearing in the shop column of the selected POI input file whenever the name of the POI input file is changed.
  • Replacing the widget that allows the user to type in the name of the target country by a widget that lists the names of all country names in the country input file and allows the user to pick one (or even several) of them.

All files making up your project should be included in your submission for this assignment including the .ui file created with QT Designer. Please also include a screenshot showing the GUI of your program while the program is being executed. If as part of your "over and above" efforts you are making changes that result in the project not satisfying the original conditions from the list above anymore, please include both your original solution and the modified version in your submission as two separate folders.

Write-up

Produce a 400 word write-up of what you have learned during this exercise; reflect on and briefly discuss the decisions you made when you designed the GUI for this project. Please also briefly mention what you did for "over and above" points in the write-up.

Deliverables

Submit a single .zip file to the Programming Assignment drop box; the zip file should contain:

  • all the code and .ui files for your project
  • a screenshot showing the GUI of the running project
  • your 400 word write-up