# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# + [markdown] pycharm={}
# # Some Basics of Python

# + [markdown] pycharm={}
# ## Variables

# + [markdown] pycharm={}
# Variable values are assigned with the equals sign (“=”), and variable types
# do not need to be defined. It is sufficient to simply make an assignment.
# For example, we can write

# + pycharm={}
a = 1

# + [markdown] pycharm={}
# and the variable `a` now holds an integer (`int`).  We can check if 
# any given variable is a particular type:

# + pycharm={}
isinstance(a, int)

# + [markdown] pycharm={}
# The type of a variable can be change by assigning something new.

# + pycharm={}
a = "Hello Florida!"

# + pycharm={}
isinstance(a, int)

# + [markdown] pycharm={}
# But generally, to avoid confusion, it is unwise to regularly overwrite
# variables with entirely different data of a different type.

# + [markdown] pycharm={}
# Since assignments are made with the equals sign, equality testing is done using two equals signs (“==”).  

# + pycharm={}
a == "Hello Florida!"

# + [markdown] pycharm={}
# ## Comments
#
# Comments can be inserted in Python code using the hash (#) symbol.
# On each line of code, everything after the first hash symbol is a comment.
# Comments can be on a line by themselves, or tucked in after other non-comment
# code.

# + pycharm={}
# this is a comment
x = 1  # this is also a comment
       # and this too is a comment.

# + [markdown] pycharm={}
# The exception to this rule is when the hash symbol appears inside a quoted string.
# In that case, it's part of the string, not a comment.

# + pycharm={}
text = "# This is not a comment because it's inside quotes."
# -

# Another way to effectively create a comment in Python is to 
# write a string and not assign it to a variable name.  Although
# it's not strictly a comment in that the Python interpreter will
# read and interpret it, doing this has no effect on the execution
# of other code.

"This is sort of a comment"

# + [markdown] pycharm={"metadata": false}
# ## Numbers
#
# Python obviously can handle numerical values for variables.
# It usually is not necessary to explicitly identify whether
# numbers are integers or floating point (decimal) numbers, 
# as Python can usually figure it out: when writing numbers
# explicitly in code, if you include the
# decimal point, it's a float, otherwise it's an integer.
#

# + pycharm={"metadata": false, "name": "#%%\n"}
a = 1  # integer

# + pycharm={"metadata": false, "name": "#%%\n"}
isinstance(a, int)

# + pycharm={"metadata": false, "name": "#%%\n"}
isinstance(a, float)

# + pycharm={"metadata": false, "name": "#%%\n"}
b = 1.0  # float

# + pycharm={"metadata": false, "name": "#%%\n"}
isinstance(b, int)

# + pycharm={"metadata": false, "name": "#%%\n"}
isinstance(b, float)
# -

# You can compare an `int` against a `float` to see if they are equal, which gives you the result you would expect.

a == b

# + [markdown] pycharm={"metadata": false}
# Python recognizes comma characters as meaningful, so
# you cannot put commas into numerical expressions in code:
#

# + pycharm={"metadata": false, "name": "#%%\n"}
1,000,000  # not one million

# + [markdown] pycharm={"metadata": false}
# Instead of commas, underscores can be inserted within
# numbers in code to make it more readable by humans, but
# retain the correct value by Python:
#

# + pycharm={"metadata": false, "name": "#%%\n"}
1_000_000  # one million
# -

# If you want to output a nicely formatted large number with commas for the thousands,
# you need to convert the number to a string. There is an extensive section on
# [string formatting](https://docs.python.org/3/library/string.html#format-string-syntax)
# provided in the Python documentation that outlines how to format numbers (and other
# Python objects) into virtually any format imaginable.  Here we'll assign the newly created string to a new variable.

million_dollars = "${:,.2f}".format(1_000_000)

million_dollars

# + [markdown] pycharm={}
# ## Strings
#
# Python can also work with strings, which can be enclosed in single quotes (``'...'``) or
# double quotes (``"..."``).  If the string needs to contain text which also includes
# quotes, they can be escaped using a backslash.

# + pycharm={}
'Florida'  # single quotes

# + pycharm={}
'Florida\'s Turnpike'  # use \' to escape the single quote...

# + pycharm={}
"Florida's Turnpike"  # ...or use double quotes instead
# -

# Note that Python is case sensitive with respect to handling strings.
# So, these two strings are not equal:

'Florida' == 'florida'

# If you want to make a case *insensitive* comparison, you need
# to first transform a string into all lowercase letters:

statename = 'Florida'
statename.lower() == 'florida'

# + [markdown] pycharm={}
# In addition to using the backslash to escape quote marks in a string,
# it can also be used to escape other special characters, including
# ``'\n'`` for newlines, ``'\t'`` for tabs, and ``'\\'`` for literal
# backslashes.  If you don't want to escape anything a instead treat any
# backslash as a single backslash, you can use *raw strings* by adding 
# an ``r`` before the first quote:

# + pycharm={}
print('C:\Python\transportation-tutorials')  # here \t means *tab*

# + pycharm={}
print(r'C:\Python\transportation-tutorials')  # note the r before the quote

# + [markdown] pycharm={}
# As you might note from the example, this is a subtle but important problem that often
# catches users by surprise when entering pathnames on Windows.  It is tricky because 
# most regular letters following a backslash are not escape sequences and code
# may work fine, until problems mysteriously emerge when a filename is changed
# to begin with one of `a`, `b`, `f`, `n`, `r`, `t`, `u`, or `v`.  To help out,
# in addition to permitting raw string input, Python also allows Windows paths to
# be written using forward slashes instead of the default backslashes.

# + [markdown] pycharm={}
# String literals can span multiple lines.  One way is using triple-quotes:
# ``"""..."""`` or ``'''...'''``.  End of lines are automatically
# included in the string, but it's possible to prevent this by adding a ``\`` at
# the end of the line.  The following example:

# + pycharm={}
print("""\
   Usage: florida-man [OPTIONS]
        -h            Display this usage message
        -t degrees    Set temperature in °F
        -a            Include alligators
""")

# + [markdown] pycharm={}
# Two or more *string literals* (i.e. the ones enclosed between quotes) next
# to each other are automatically concatenated. :

# + pycharm={}
'Flo' 'rida'

# + [markdown] pycharm={}
# Strings (literal or otherwise) can be concatenated (glued together) with the ``+`` operator:

# + pycharm={}
s1 = 'Cape '
s2 = 'Canaveral'
s1 + s2

# + [markdown] pycharm={}
# ## Lists
#
# There are a variety of *compound* data types, used to group together other
# values.  One of these is the *list*, which can be written as a list of
# comma-separated values (items) between square brackets.  

# + pycharm={}
cities = ['Miami', 'Orlando', 'Tampa', 'Jacksonville']

# + [markdown] pycharm={}
# Lists are ordered, and can be indexed starting at zero for the first item.

# + pycharm={}
cities[0]

# + [markdown] pycharm={}
# They can also be sliced, passing a `start:stop` syntax instead of a single 
# number to the indexer:

# + pycharm={}
cities[0:2]

# + [markdown] pycharm={}
# Note that the `stop` value indicates the first value past the end of the slice,
# not the last value in the slice.

# + [markdown] pycharm={}
# You can append items to a list like this:

# + pycharm={}
cities.append('Tallahassee')
# -

cities

# The items in a list are not restricted to be all the same data type, 
# so Python won't prevent you from doing something like this:

cities.append(123)

cities

# But for your sanity, you may not want to do that.  The `pop` method
# can help here, by removing and returning the last item in the list.

cities.pop()

cities

# + [markdown] pycharm={}
# You can also change values within a list:

# + pycharm={}
cities[2] = 'Tampa–St. Petersburg'
cities

# + [markdown] pycharm={}
# ## Tuples
#
# A tuple is like a list, except it is *immutable* (i.e. you cannot change any part of it
# after it exists).  Tuples are created using round parenthesis instead of square brackets.

# + pycharm={}
counties = ('Miami-Dade', 'Orange', 'Hillsborough', 'Duval')
# -

counties.append(123)

# + pycharm={}
counties[0] = 'Miami'
# -

# ## Dictionaries
#
# Tuples and lists are *sequences*: a bunch of objects in some order.  
# Dictionaries, on the other hand, are *mappings*: a bunch of objects
# with labels.  Like a physical dictionary, if you know the label
# (for a regular dictionary, the word) then you can very quickly find
# the object (for a regular dictionary, the definition) without having 
# to read through very many other labels on the way.
#
# When writing a dictionary directly in Python code, we use curly 
# brackets, and give the contents of the dictionary as key:label pairs.

jurisdictions = {
    'Miami': 'Dade County', 
    'Orlando': 'Orange County',
    'Ft. Lauderdale': 'Broward County',
}

# We can add new items by assignment with index-like syntax like this:

jurisdictions['Jacksonville'] = 'Duval'

# And access members similarly:

print(jurisdictions['Miami'])

# An attempt to access a key that does not exist in the dictionary 
# raises an error:

print(jurisdictions['Tallahassee'])

# Although the values that are stored in a dictionary can be anything, the
# *keys* need to be both unique and immutable.  Assigning a new value to the
# same key deletes the old value:

jurisdictions['Miami'] = 'Miami-Dade County'

# ## Sets
#
# A set is an unordered bunch of unique objects.  Although the implemention is a bit
# different, you can generally think of a set as a dictionary that only has the keys
# and doesn't have any values attached to those keys.

national_parks = {'Everglades', 'Biscayne', 'Dry Tortugas'}

# The primary reason to use a set instead of a tuple is to speed up the process
# of checking if some value is contained in the set or not.

'Everglades' in national_parks

# + [markdown] pycharm={}
# ## Syntax
#
# Python has no mandatory statement termination characters.
# You can end a statement by ending the line of code. 
# You can also have a semicolon at the end of a statement,
# which allows you to write two statements on a single line,
# although this is generally frowned upon for most Python code.
#
# Blocks of Python code are denoted by indentation. 
# Multiple lines of code in a row with identical indentation form a 
# block of code that is executed in sequence.  Note that indenting
# can be done with spaces, or with tabs, but mixing these in one
# file is very strongly discouraged.
# Statements that expect an increase in indentation level on the following
# line end in a colon (:).  

# + [markdown] pycharm={}
# ## Flow Control
#
# Common flow control keywords are `if`, `for`, and `while`.
#
# An `if` statement can be used alone, or along with `elif` (short for else if) 
# and/or `else` statements.

# + pycharm={}
x = 'Miami Beach'

if x in cities:
    print("found", x, "City")
elif x in counties:
    print("found", x, "County")
else:
    print("didn't find", x)

# + [markdown] pycharm={}
# The `for` statement will iterate over items in a sequence (list, tuple, or similar).

# + pycharm={}
for x in counties:
    print(x, 'County')

# + [markdown] pycharm={}
# The `while` statement loops until the conditional evaluates as False.

# + pycharm={}
x = 1
while x < 5:
    print(x)
    x += 1

# + [markdown] pycharm={}
# You can exit a `for` or `while` block early with a `break` statement.

# + pycharm={}
x = 1
while x < 5:
    print(x)
    x += 1
    if x > 3:
        break

# + [markdown] pycharm={}
# ## Importing Packages

# + [markdown] pycharm={}
# Only the most basic functionality is exposed in Python by default. 
# Almost all functions and object classes will need to be imported from
# a library, either one that is built-in to Python (but still needs to be
# imported) or one installed alongside Python (by conda or pip, usually).
# Libraries are loaded with the `import` keyword. You can also use 
# `from [libname] import [funcname]` to access library components, and 
# you can use the `as` keyword to provide a unique or different name
# for the thing you are importing. For example:

# + pycharm={}
import os
import numpy as np
from transportation_tutorials import data as td
# -

# You can then use functions and modules that are found in these packages
# using "dot" notation.  For example, the `numpy` package includes a `zeros`
# function, that creates an array full of zeros, which we can call like this:

np.zeros(5)

# + [markdown] pycharm={}
# In a Jupyter notebook, we can also access function documentation by using a
# special question mark syntax, which will print out the built-in documentation
# for any function, if it is available (most standard analytical packages including
# numpy, scipy, and pandas have extensive documentation for nearly every function).

# +
# np.zeros?

StarcoderdataJupyterScriptsDedupFiltered