Monday, May 27, 2024

Python Scripting - Functions, Methods, Modules

Moving forward into our second week of GIS Programming, there was a lot to memorize related to basic Python programming terminology and functionality. Our first foray into Python utilized functions, methods and modules. Additionally we gain experience working with lists and loops.

The Lab assignment for Module 2 commenced with a basic assignment of a string variable comprising our full name. A string, or string literal, is a set of characters enclosed by either single or double quotation marks. Strings have an Index Positioning System that uses a range of values enclosed in brackets. Each character in a string, including spaces, is assigned an index number. Since Python is a Zero-Based Language, the first character in a string or list sequence represents index zero [0]. This is  fundamental in understanding indexing numerology.

Following the creation of a variable for our name, the next step was splitting the string into separate elements via the split ( ) method. Functions operate independently, whereas a method is a function that is coupled to an object. An object can be a number, a string or a list. With Dot Notation, the object and method precede the argument / parameters, which are enclosed within parenthesis. A more simpler explanation is that what follows the dot belongs to what precedes it, or the method belongs to the object.

Using the split ( ) method on the string containing our full name generates a list. The list is indexed similarly to the characters in a string, where the first name is index [0], the middle name is index [1] and the last name is index [2]. Alternatively, we can work backward with indexes where the final entry in a sequence is -1. Following that sequence, the middle name is index [-2].

The second step in the Lab assignment was the review of a prewritten script for a dice game. There were two errors to correct, and identifying these were pretty straight forward. The difficulty I had was  understanding the logic of the actual dice game. I posted about it on the class discussion board and finally figured it out with help.

The for loop repeats a specified portion of code, typically on a sequence such as a string or list, but not based on a condition. The loop iterates through a block of code on each element in the sequence. The loop concludes once it reaches the sequence end.

The script uses a for loop run on a list of eight players. The dice number generates a random integer from zero to a range that is calculated as twice the number of characters in the string of the player name. So for Tom, his name is 3 characters in length, so the variable x*2 gives him a dice range of 0 to 6. If he rolls 4 of more, he wins, as the condition for winning is dice > x. The elif (else if) statement is based upon the condition dice == x, so if he rolls a 3 he ties. The else condition applies if he rolls 2 or less, where he loses.

Results from a Python script for a random dice game
Successful run of corrected Dice Game script showing all three possible results

The final name on the list is Marceline, which is nine characters in length. Her dice range is between 0 and 18. So if she rolls 9 she ties and anything above is a win and below a loss. The logic is now clear, but practically, what kind of dice game is based upon the length of a players name? 😑

The remainder of the Lab assignment further covered if statements, else statements and while loops. Incorporating these functions, we were tasked with compiling a program of "lucky numbers" that started by populating a list of 20 randomly generated numbers between zero and ten. Then an "unlucky number" was selected by user-input, which in turn was iterated through the program to determine if it was on the list, and if so, how many times. If the unlucky number was, compiled code would remove any instance of that from the lucky number list. Results were printed.

Unlucky Number is in Lucky Numbers list
Lucky Number script showing the condition where the unlucky number is removed.

The while loop requires an exit condition, an argument that evaluates to True (Boolean). The exit condition utilizes a sentry variable or loop variable, which is compared to some other value. An exit condition must eventually be reached during the iteration of the while loop, otherwise the endless cycle may result in an infinite loop.

As part of our lab exercise, a simple while loop iterated to a specified number of times. The block of code for the iteration generated a random number using the randint (random integer) method found within the random module and populated a blank list. A module is like an extension imported into Python that expands its capabilities, typically with specialized functions. Python scripts, by definition, are modules.

Branching is where code partitions along one path or another. Typically used with an if structure and its variants, the script can branch into a section of code or bypass it depending upon the set conditions. Within the while loop structure in the Lab, we coupled an if statement with a break statement under the condition that once the iteration was equivalent to a predetermined index number, it exited.

Results of Lucky Numbers Python Program
The lucky number script case where the unlucky number input was not within the lucky number list

Another aspect of while loops is that the counter variable must both be defined and an integer. The use of variables is intuitive in Python, so the type is implicit in the value assigned. x = 0 is an integer whereas x = 1.02 is a float and x = "text" is a string. The while loop iterates with integers (or slices) and if not, a TypeError occurs. Also without the counter variable being predefined, attempting to run the while loop results in a NameError, where the counter variable is not defined.

Flow Chart for the Lucky Number Script in Python
Flow Chart for the Lucky Number Python Script

Completing the Lab for module 2 was challenging, requiring a lot of code testing and patience. I found using IDLE to compile the code with the separate script window was more efficient than ArcGIS Notebook and the use of cells. The IDLE interface uses syntax highlighting, my main requirement thus far, and running a saved script is as simple as pushing the F5 button.


Wednesday, May 22, 2024

GIS Programming - an Introduction to Python

A week removed from completing Computer Cartography (GIS4006), my next class in the UWF Online GIS Certification Program is GIS Programming (GIS4102), which covers Python. Python is an open-sourced programming language used for geoprocessing tools in ArcGIS Pro. Python is also object-orientated, which is a programming model that organizes software around data (objects) as opposed to functions and logic.

Python is the is the scripting language of choice for geoprocessing in ArcGIS. A scripting language references the automation of certain functionality within another program. The scripting programming task connects separate, existing components in an effort to perform a new associated task. Python can take manual tasks in GIS and automate them.

Python is an interpreted language and does not need to be compiled. That means it does not need compilation to binary code before it is run. Python can run an entire script (module) or just a snippet of code. The flexibility allows smaller sections of code or even a single line to be tested or checked for proper syntax.

There are multiple Python Editors that make working with Python easier by using a menu-driven interface and tools for organizing and testing scripts. IDLE (Integrated DeveLopment Environment) comes preinstalled with Python and is the default interactive interpreter for working with Python scripts. Another Python Editor is Jupyter Notebook. ArcGIS Notebooks are derived from Jupyter Notebook that allow a user to work with Python directly from within ArcGIS Pro. This Python editor uses narrative text and visualizations, and produce results from analysis in a geographic context.

An example of a flowchart for a Python script

Also introduced in the first module for GIS Programming are flowcharts for programs. A flowchart outlines an algorithm with the use of symbols and shapes. General rules for flowcharts use ovals for the start and end of a program. Rectangles are used for a task process or executing assignment statements.. Diamonds are used for decisions and parallelograms for I/O statements, when statements are printed or information is obtained from the keyboard. Arrows connect the various shapes indicate the direction of the program.

Flowcharts visualize the behavior of a program. An exercise for Lab this week was to create a flowchart illustrating converting 3 radios to degrees and printing the result. This was based upon the formula of degrees = radians * 180/pi.
The resulting python script from the flowchart was:

#This program calculates degrees from radians
radians = 3
pi = 3.14159
degrees = radians * (180/pi)
print (degrees)

Lastly this week we were tasked to derive the meaning of "The Zen of Python" poem embedded within the Python source code. These are 19 aphorisms alluding to general guidelines used by Python developers. An aphorism is defined as short clever observation intended to express a general truth.

I attempted to make sense out of "The Zen of Python" by making correlations to what was in our textbook "Python Scripting for ARCGIS Pro" but was not satisfied with my interpretation. I ended up researching it and found the article "What's the Zen of Python" on the Real Python web site. The author breaks down the poem into sections with examples of what the aphorisms try to convey. Coupling that analysis with some of my own observations from working with PHP scripts for AARoads, I surmised:

The guidelines allude to the simplicity of Python (syntax) and the ease of learning the programming language. Code should be clear and easily understood. More complex code can be subdivided into more manageable components. Avoid overly nesting code with multiple indentations, but not by using overly long and compacted code placed on a single line. Separate longer code into smaller parts that are easier to parse. Patience can offset premature intuition that saves time and frustration. Functionally should not be added until deemed necessary.