diff --git a/.gitignore b/.gitignore index 41068f6..3ec89e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# TeachBooks +.teachbooks/ + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/book/.DS_Store b/book/.DS_Store new file mode 100644 index 0000000..1f17029 Binary files /dev/null and b/book/.DS_Store differ diff --git a/book/01/In_a_Nutshell/01.ipynb b/book/01/In_a_Nutshell/01.ipynb deleted file mode 100644 index e725a45..0000000 --- a/book/01/In_a_Nutshell/01.ipynb +++ /dev/null @@ -1,907 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 1. Variables, operators and functions." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Excuting a cell in python" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The print() function in Python is used to output or display text or other information on the screen. It can be used to display a string of text, the value of a variable, or the result of a calculation. The text or information that you want to display is passed as an argument inside the parenthesis of the print() function.\n", - "\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Print () command" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To execute a cell in Python, you can use the run command in Jupyter Notebook or press the \"Run\" button in the toolbar. You can also use the keyboard shortcut **Shift + Enter** to execute the cell. \n", - "\n", - "Lets start by excecuting our first code by printing the words 'Hello world'. Press **Shift+Enter** to run the cell below. You should see the output \"Hello, World!\" displayed below the cell. Notice that we have to write the sentence inside the quotation marks to indicate that the data is of string type. \n", - "\n", - "Alternatively, You can also execute the code by clicking on the Run button in the toolbar or by using the run command in the Jupyter Notebook." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Hello, world!\n" - ] - } - ], - "source": [ - "print ('Hello, world!')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, try to fill in your name and print the following sentence in the next cell: \n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "My name is _____\n" - ] - } - ], - "source": [ - "print ('My name is _____')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Basic input and out definitions in python" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Value\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In Python, a **value** is any data that can be stored in a variable. It can be a number (such as an integer or a float), a string (a sequence of characters), a Boolean (True or False), or other types of data. For example" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "x = 5 # x is a variable that holds an integer value of 5\n", - "y = \"Hello World\" # y is a variable that holds a string value of \"Hello World\"\n", - "z = True # z is a variable that holds a Boolean value of True" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Variable " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A **variable** is a container that holds a value, which is like a label or a name given to the value that is stored inside it. You can use variables to store values and then use them later in your code. You can also change the value of a variable at any time. For example:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "x = 5 # x is a variable that holds an integer value of 5\n", - "x = x + 2 # x now holds the value of 7" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### String" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A string is a sequence of characters, enclosed in quotation marks. You can use strings to store text, such as words and sentences. You can also use them to display messages to the user or to create strings that hold specific data, like a name or an address. Strings are a very important data type in python and you will use it very frequently. For example:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'Hello World'" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "\"Hello World\"" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### List" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A list in Python is a collection of values stored in a single object, similar to arrays in other programming languages. Lists can contain elements of any type, including numbers, strings, and other objects. \n", - "\n", - "To create a list in Python, you can use square bracket [ ] notation and include the values you want to store in the list, separated by commas.\n", - "\n", - "For a beginner, it's important to remember the following when creating lists in Python:\n", - "\n", - "* Lists start with a square bracket [ ]\n", - "* Values in the list are separated by commas\n", - "* Lists can contain elements of any type, including numbers, strings, and other objects." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[1, 2, 3.14, 'Hello', True]\n" - ] - } - ], - "source": [ - "# create a list\n", - "my_list = [1, 2, 3.14, \"Hello\", True]\n", - "\n", - "# print the list\n", - "print(my_list)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Indexing in Python is a way to access specific elements in a list or array. Think of a list as a row of boxes, where each box contains a value. The index is the number assigned to each box [ ] and it allows us to locate a specific value or object. Lists in Python are zero-indexed, meaning that the first element in the list is stored at index 0, the second element is stored at index 1, and so on. For example, we an print any element in out created list by specifying the index releated:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1\n", - "Hello\n", - "3.14\n" - ] - } - ], - "source": [ - "# access elements by index\n", - "print(my_list[0]) # prints the integer 1\n", - "print(my_list[3]) # prints the string \"Hello\"\n", - "print (my_list[2]) # prints the float 3.14" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## type () of data in python " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In Python, you can use the built-in type() function to determine the type of an object. For example:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "\n" - ] - } - ], - "source": [ - "x = 5\n", - "print(type(x)) # Output: \n", - "\n", - "y = \"hello\"\n", - "print(type(y)) # Output: \n", - "\n", - "z = [1, 2, 3]\n", - "print(type(z)) # Output: " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can also check an object's type very simply by:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "int" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x2 = 5\n", - "type(x2) # Output: int" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "str" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y2 = 'hello'\n", - "type(y2) # Output: str" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "list" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "z2 = [1, 2, 3]\n", - "type(z2) # Output: list" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Arithmetic Operators\n", - "\n", - "| Math sign | Python sign | name |\n", - "| :-: | :-: |:-:|\n", - "| + | + | addition |\n", - "| - | - | subtraction |\n", - "| * | * | multiplication |\n", - "| / | / | division |\n", - "| ^ | ** | exponentiation |\n", - "| mod | % | modulus |\n", - "| | // | floor division |" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Arithmetic operators: These operators perform mathematical operations, such as addition, subtraction, multiplication, and division. Examples:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "7\n", - "3\n", - "10\n", - "2.5\n", - "25\n" - ] - } - ], - "source": [ - "x = 5\n", - "y = 2\n", - "\n", - "print(x + y) # Output: 7 \n", - "print(x - y) # Output: 3\n", - "print(x * y) # Output: 10\n", - "print(x / y) # Output: 2.5\n", - "print(x**y) # output: 25\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Error codes in python" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "When you run a Python script or code in a cell, the code is executed line by line, starting from the first line and moving down the code.\n", - "\n", - "If an error occurs, Python will stop executing the code at the line where the error occurs and will display an error message. The first line of the error will indicating the line number where the error occurred. This is often the most informative as it tells you where in your code the problem is. The last line in the error message will tell you what the problem in this line is." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The code results in a TypeError because you are trying to add a variable of type integer (a) to a variable of type string (b). In python, you can only add two variables of the same type. You can't add an int to a string.\n", - "If you want to concatenate the string and the int you can convert the int to string before adding them together. " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Here is an example:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0hello\n" - ] - } - ], - "source": [ - "a = 0\n", - "b = \"hello\"\n", - "c = str(a) + b\n", - "\n", - "print (c)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Or you can use the format() method to insert the value of a into the string b." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "hello 5\n" - ] - } - ], - "source": [ - "a = 5\n", - "b = \"hello {}\"\n", - "c = b.format(a)\n", - "\n", - "print (c)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Or you can use f-strings (formatted string literals) that are available from python 3.6 and above. You can show a nummerical output with any string you want using f-strings. The code you need to type for f-strings: **f ' text {output} '**. The output has to be inside the curly brackets --> { } " - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "hello 5\n" - ] - } - ], - "source": [ - "a = 5\n", - "b = \"hello\"\n", - "c = f\"{b} {a}\"\n", - "\n", - "print (c)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Comparison Operators
In Python, you often want to compare a value with another. For that, you use comparison operators.\n", - "\n", - "| Math sign | Python sign | Meaning |\n", - "| :-: | :-: | :-: |\n", - "| $=$ | $==$ | Equal to |\n", - "| $>$ | $>$ | Greater than |\n", - "| $<$ | $<$ | Less than |\n", - "| $\\geqslant$ | $>=$ | Greater than or equal to |\n", - "| $\\leqslant$ | $<=$ | Less than or equal to |\n", - "| $\\neq$ | $!=$ | Not equal to |" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Comparison operators: These operators compare two values and return a Boolean value (True or False). Examples:" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "False\n", - "True\n", - "True\n", - "False\n", - "True\n", - "False\n" - ] - } - ], - "source": [ - "x = 5\n", - "y = 2\n", - "print(x == y) # Output: False\n", - "print(x != y) # Output: True\n", - "print(x > y) # Output: True\n", - "print(x < y) # Output: False\n", - "print(x >= y) # Output: True\n", - "print(x <= y) # Output: False\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Control flow statements in Python" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are several control flow statements in Python that are used to control the flow of execution of a program. The most important ones are:" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**if** statement: The if statement is used to check a certain condition, and if the condition is true, the code within the if block will be executed. If the condition is false, the code within the if block will be skipped. For example:" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "x is positive\n" - ] - } - ], - "source": [ - "x = 5\n", - "if x > 0:\n", - " print(\"x is positive\")\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**if-else** statement: The if-else statement is an extension of the if statement, which allows you to specify a block of code to be executed if the condition is true, and a different block of code to be executed if the condition is false. Example:" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "x is non-positive\n" - ] - } - ], - "source": [ - "x = -2\n", - "if x > 0:\n", - " print(\"x is positive\")\n", - "else:\n", - " print(\"x is non-positive\")\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**if-elif-else** statement: The if-elif-else statement is an extension of the if-else statement, which allows you to check multiple conditions and execute different code blocks based on the first condition that is true. This is how you use them: " - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "x is zero\n", - "x2 is negative\n" - ] - } - ], - "source": [ - "x = 0\n", - "if x > 0:\n", - " print(\"x is positive\")\n", - "elif x == 0:\n", - " print(\"x is zero\")\n", - "else:\n", - " print(\"x is negative\")\n", - " \n", - "\n", - "x2 = -2\n", - "if x2 > 0:\n", - " print(\"x2 is positive\")\n", - "elif x2 == 0:\n", - " print(\"x2 is zero\")\n", - "else:\n", - " print(\"x2 is negative\")\n", - "\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Indexing" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Indexing is a method in Python to access individual elements in a list by their position. This is a fundamental feature of Python's list data structure, allowing you to retrieve specific elements from the list. Elements are stored in a sequential manner and can be accessed using their index (integer value indicating their position)." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Functions " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In Python, a function is a block of code that can be reused multiple times throughout a program. Functions are useful for organizing and structuring code, and for breaking down complex tasks into smaller, more manageable pieces. " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Below are some examples of common built-in Python functions and what they do:\n", - "\n", - "\n", - "* ``print()`` Prints input to screen\n", - "* ``type()`` Returns the type of the input\n", - "* ``abs()`` Returns the absolute value of the input\n", - "* ``min()`` Returns the minimum value of the input. \n", - " (input could be a list, tuple, etc.)\n", - "* ``max()`` Same as above, but returns the maximum value\n", - "* ``sum()`` Returns the sum of the input \n", - " (input could be a list, tuple, etc.)\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Here is a step-by-step guide on how to create any function in Python:\n", - "\n", - "**Step 1:** Define the function using the def keyword, followed by the function name, and a set of parentheses.\n", - "\n", - "**Step 2:** Define the code block that will be executed when the function is called. This code block should be indented underneath the function definition. For example:" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "def greet():\n", - " print(\"Hello, World!\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Step 3:** (Optional) Add parameters to the function, which are values that can be passed into the function when it is called. These parameters are defined within the parentheses of the function definition. For example:" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "def greet(name):\n", - " print(\"Hello, \" + name + \"!\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Step 4:** (Optional) Add a return statement to the function, which is used to return a value or an expression from the function. For example:" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "def add(x, y):\n", - " return x + y" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Step 5:** Call the function by using the function name, followed by a set of parentheses. For example:" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Hello, John Weller!\n" - ] - } - ], - "source": [ - "greet(\"John Weller\")\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Thus, to create and use the function we write it all in one cell as follows:" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Hello, John!\n", - "Hello, Mary Jane!\n" - ] - } - ], - "source": [ - "def greet(name):\n", - " print(\"Hello, \" + name + \"!\")\n", - "\n", - "greet(\"John\")\n", - "greet(\"Mary Jane\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In this example, the function **greet()** is defined with one parameter **name**, the function is called twice, first with \"John\" as an **argument**, then with \"Mary\" as an **argument**, the function will print out a greeting message each time it's called --> the **input** of the created function is the argument and the **output** is the greeting message.\n", - "\n", - "Functions are essential to programming, they allow you to organize, structure and reuse your code in an efficient and readable way." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/book/02/Theory/01.ipynb b/book/02/Theory/01.ipynb deleted file mode 100644 index 664a20e..0000000 --- a/book/02/Theory/01.ipynb +++ /dev/null @@ -1,3373 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "# 2. Modules, conditions, data structures and loops" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "fHmKWsUSKuj4", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## 2.1 Python Modules\n", - "\n", - "Previously, you have learned how to:

1) initialize variables in Python;
2) perform simple actions with them (eg.: adding numbers together, displaying variables content, etc);
3) work with functions (have your own code in a function to reuse it many times or use a function, which was written by another person).

However, the scope of the last Notebook was limited by your Python knowledge and available functions in standard/vanilla Python (so-called 'built-in' Python functions).\n", - "There are not many Python built-in functions that can be useful for you, such as functions for math, plotting, signal processing, etc. Luckily, there are countless modules/packages written by other people.\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "oyr90lgAQGtD", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### Python built-in modules\n", - "\n", - "By installing any version of Python, you also automatically install its built-in modules.

One may wonder — why do they provide some functions within built-in modules, but not directly as a built-in function, such as the abs() or print()?

The answers may vary, but, generally, it is to keep your code clean; compact; and, working.

It keeps your code clean and compact as you only load functions that you need. It keeps your code working as it allows you to define your own functions with (almost) any kind of name, and use them easily, without worrying that you might 'break' something if there is a function with the same name that does something completely different." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "67a2hkUyRh_P", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### math\n", - "\n", - "The math module is one of the most popular modules since it contains all implementations of basic math functions ($sin$, $cos$, $exp$, rounding, and other functions — the full list can be found here).

In order to access it, you just have to import it into your code with an import statement. Then using ``print()`` to show that ``math`` is actually a built-in Python module." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "A1WjrfHoHYFV", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "e14b2fc7-6b0b-4f6e-8342-45c3791030b9" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - } - ], - "source": [ - "import math\n", - "print(math) " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "0ssGu7FsTEtz", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "You can now use its functions like this:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "11FBTZH7TATg", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "41f2699c-47a3-4ed2-f7be-b1f2ea059819" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Square root of 16 is equal to 4\n" - ] - } - ], - "source": [ - "print(f'Square root of 16 is equal to {int(math.sqrt(16))}')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "0EscmfkpTxXv", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "You can also use the constants defined within the module, such as **`math.pi`**:" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "DtwKkug2TiGT", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "60ffed22-e0e0-459b-e1dc-d35edfb5a3ff" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "π is equal to 3.141592653589793\n", - "π is equal to 3.14\n", - "π is equal to 3.1\n", - "π with two decimals is 3.14,with three decimals is 3.142 and with four decimals is 3.1416\n" - ] - } - ], - "source": [ - "print(f'π is equal to {math.pi}')\n", - "print('π is equal to {:.2f}'.format(math.pi)) \n", - "print('π is equal to {:.1f}'.format(math.pi))\n", - "print('π with two decimals is {:.2f},'\n", - " 'with three decimals is {:.3f} and with four decimals is {:.4f}'.\\\n", - " format(math.pi, math.pi, math.pi))" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "`````{admonition} Let's break it down\n", - "\n", - "* ``print('π is equal to {:.2f}'.format(math.pi))`` print the variable up to some decimal, (two for example).\n", - "\n", - "* ``print('π is equal to {:.1f}'.format(math.pi))`` change the number 2 on the ':.2f' to print with more (or fewer) decimals.\n", - "\n", - "* The last line show how to print is quickly if you have to print a sentence with many variables in it.\n", - "\n", - "More information on printing best practices here.\n", - "\n", - "`````" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "M8OQGFnGf_S9", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### ``math.pi``\n", - "\n", - "As you can see, both constants and functions of a module are accessed by using: the module's name (in this case math) and a . followed by the name of the constant/function (in this case pi).

We are able to do this since we have loaded all contents of the module by using the import keyword. If we try to use these functions somehow differently — we will get an error:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 201 - }, - "collapsed": true, - "id": "98zHvteQUA3S", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "914a0a33-dfc6-45bc-d4c2-941ec4e666a9" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Square root of 16 is equal to\n", - "4.0\n" - ] - } - ], - "source": [ - "print('Square root of 16 is equal to')\n", - "print(sqrt(16))" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "LRTVWDEqhGyk", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "You could, however, directly specify the functionality of the module you want to access. Then, the above cell would work.

This is done by typing: from module_name import necessary_functionality, as shown below:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "By8SDKMXhBKD", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "b277aeda-58a3-4e6d-de0e-038d843d77fe" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Square root of 16 is equal to 4.\n" - ] - } - ], - "source": [ - "from math import sqrt\n", - "\n", - "print(f'Square root of 16 is equal to {int(sqrt(16))}.')" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "pVo16M0whkK7", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "053cee25-dc6b-4604-d69c-1025bbf60e6c" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "π is equal to 3.141592653589793.\n" - ] - } - ], - "source": [ - "from math import pi\n", - "\n", - "print(f'π is equal to {pi}.')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### Listing all functions\n", - "\n", - "Sometimes, when you use a module for the first time, you may have no clue about the functions inside of it. In order to unveil all the potential a module has to offer, you can either access the documentation on the corresponding web resource or you can use some Python code.\n", - "\n", - "\n", - "You can listing all contents of a module using ``dir()``. To learn something about, let's say, ``hypot`` thingy you can type the module name - dot -function name, for example ``math.hypot``." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "contents of math: ['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']\n", - "math hypot is a \n" - ] - } - ], - "source": [ - "import math\n", - "print('contents of math:', dir(math))\n", - "print('math hypot is a', math.hypot) " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can also use ``?`` or ``??`` to read the documentation about it in Python" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[1;31mDocstring:\u001b[0m\n", - "hypot(*coordinates) -> value\n", - "\n", - "Multidimensional Euclidean distance from the origin to a point.\n", - "\n", - "Roughly equivalent to:\n", - " sqrt(sum(x**2 for x in coordinates))\n", - "\n", - "For a two dimensional point (x, y), gives the hypotenuse\n", - "using the Pythagorean theorem: sqrt(x*x + y*y).\n", - "\n", - "For example, the hypotenuse of a 3/4/5 right triangle is:\n", - "\n", - " >>> hypot(3.0, 4.0)\n", - " 5.0\n", - "\u001b[1;31mType:\u001b[0m builtin_function_or_method\n" - ] - } - ], - "source": [ - "math.hypot?" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "2SUM0W23oAdC", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### Python third-party modules\n", - "\n", - "Besides built-in modules, there are also modules developed by other people and companies, which can be also used in your code.\n", - "\n", - "These modules are not installed by default in Python, they are usually installed by using the 'pip' or 'conda' package managers and accessed like any other Python module.

This YouTube video explains how to install Python Packages with 'pip' and 'conda'.\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "_o1yzxJC0NaZ", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### numpy\n", - "\n", - "The numpy module is one of the most popular Python modules for numerical applications. Due to its popularity, developers tend to skip using the whole module name and use a smaller version of it (np). A different name to access a module can be done by using the as keyword, as shown below." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "qWOdG82IhoiX", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "99446932-b303-4d84-912a-e1d4fb90545d" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "\n", - "x = [0. 0.12822827 0.25645654 0.38468481 0.51291309 0.64114136\n", - " 0.76936963 0.8975979 1.02582617 1.15405444 1.28228272 1.41051099\n", - " 1.53873926 1.66696753 1.7951958 1.92342407 2.05165235 2.17988062\n", - " 2.30810889 2.43633716 2.56456543 2.6927937 2.82102197 2.94925025\n", - " 3.07747852 3.20570679 3.33393506 3.46216333 3.5903916 3.71861988\n", - " 3.84684815 3.97507642 4.10330469 4.23153296 4.35976123 4.48798951\n", - " 4.61621778 4.74444605 4.87267432 5.00090259 5.12913086 5.25735913\n", - " 5.38558741 5.51381568 5.64204395 5.77027222 5.89850049 6.02672876\n", - " 6.15495704 6.28318531]\n", - "\n", - "\n", - "y = [ 1. 0.99179001 0.96729486 0.92691676 0.8713187 0.80141362\n", - " 0.71834935 0.6234898 0.51839257 0.40478334 0.28452759 0.1595999\n", - " 0.03205158 -0.09602303 -0.22252093 -0.34536505 -0.46253829 -0.57211666\n", - " -0.67230089 -0.76144596 -0.8380881 -0.90096887 -0.94905575 -0.98155916\n", - " -0.99794539 -0.99794539 -0.98155916 -0.94905575 -0.90096887 -0.8380881\n", - " -0.76144596 -0.67230089 -0.57211666 -0.46253829 -0.34536505 -0.22252093\n", - " -0.09602303 0.03205158 0.1595999 0.28452759 0.40478334 0.51839257\n", - " 0.6234898 0.71834935 0.80141362 0.8713187 0.92691676 0.96729486\n", - " 0.99179001 1. ]\n" - ] - } - ], - "source": [ - "import numpy as np\n", - "print(np)\n", - "x = np.linspace(0, 2 * np.pi, 50)\n", - "y = np.cos(x)\n", - "print('\\n\\nx =', x)\n", - "print('\\n\\ny =', y)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`````{admonition} Let's break it down\n", - "The code uses the ``numpy`` library in Python to perform the following tasks:\n", - "1. It imports the ``numpy`` library.\n", - "2. It prints information about the ``numpy`` package.\n", - "3. It creates an array ``x`` with 50 equally spaced values between $0$ and $2\\pi$.\n", - "4. It calculates the cosine of each element in the array ``x`` and stores the results in the array ``y``.\n", - "5. It prints the arrays ``x`` and ``y``.\n", - "\n", - "In summary, the code imports the ``numpy`` library, creates an array ``x`` with $50$ evenly spaced elements between $0$ and $2\\pi$, calculates the cosine of each element in ``x``, and finally prints the arrays ``x`` and ``y``.\n", - "````` " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "You will learn more about this and other packages in separate Notebooks since these packages are frequently used by the scientific programming community." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "bl_ufrrc2PGB", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### ``matplotlib``\n", - "\n", - "The matplotlib module is used to plot data. It contains a lot of visualization techniques and, for simplicity, it has many submodules within the main module. Thus, in order to access functions, you have to specify the whole path that you want to import.

For example, if the function you need is located within the matplotlib module and pyplot submodule, you need to import matplotlib.pyplot; then, the access command to that function is simply pyplot.your_function().

Below we use the data generated in the previous cell to create a simple plot using the pyplot.plot() function:\n", - "\n", - "In order to import a submodule the parent module must also be specified. It is common to import ``matplotlib.pyplot`` as ``plt``.\n", - "\n", - "The ``plt.plot()`` function takes x-axis values as the first argument and y-axis, or $f(x)$, values as the second argument\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 282 - }, - "collapsed": true, - "id": "COq85MFE06s1", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "67086bf1-4b12-4929-a420-ae9322bbbcce" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "plt.plot(x, y)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "``plt.scatter()`` works in a similar way, but it does not connect the dots." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 282 - }, - "collapsed": true, - "id": "bd01J-Dc8iDJ", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "792ba793-3ff8-4f5a-bcdd-8271082d6c83" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.scatter(x, y)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "qdHLw0oC84pg", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### Loading Python files as modules\n", - "\n", - "Finally, you can also load your own (or somebody else's) Python files as modules. This is quite helpful, as it allows you to keep your code projects well-structured without the need to copy and paste everything.

In order to import another *.py file as a module, you only need to have that file and your Notebook file in the same directory and use the import keyword. More info on this here." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "fHmKWsUSKuj4", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## 2.2 Conditions and if statements\n", - "\n", - "In previous Sections you have learned how to create variables, alter them with the help of operators and access the code of professional software developers/scientists. With this, you can already do plenty of stuff in Python. However, it still lacks versatility. If you want to apply other processing techniques for other data — you would need to manually rewrite your code and then change it back once the data changes again. Not that handy, right?

In this Section you will learn how to steer the flow of your code — process data differently based on some conditions. For that you will learn a construction called the if statement.\n", - "\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "oyr90lgAQGtD", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### if keyword\n", - "\n", - "The if statement in Python is similar to how we use it in English. \"If I have apples, I can make an apple pie\" — clearly states that an apple pie will exist under the condition of you having apples. Otherwise, no pie.

\n", - "Well, it is the same in Python:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "QGXlz9tvM56U", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "63cc3e01-7c4c-4829-d4b2-9ae08b587791" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "End of the cell block...\n" - ] - } - ], - "source": [ - "amount_of_apples = 0\n", - "\n", - "if amount_of_apples > 0:\n", - " print(\"You have apples!\\nLet's make a pie!\")\n", - "\n", - "print('End of the cell block...')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "qiElV_BSNYgl", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "As you can see - nothing is printed besides 'End of the cell block...'.

But we can clearly see that there is another print statement! Why it is not printed? Because we have no apples... thus no pie for you.

Let's acquire some fruit and see whether something will change...\n", - "\n", - "Adding 5 apples to our supply:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "ja5Tz_GLNoUH", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "6bd36f78-2958-4bb6-ffcc-420951b3f8ba" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "You have apples!\n", - "Let's make a pie!\n", - "End of the cell block...\n" - ] - } - ], - "source": [ - "amount_of_apples += 5\n", - "\n", - "if amount_of_apples > 0:\n", - " print(\"You have apples!\\nLet's make a pie!\") \n", - "\n", - "print('End of the cell block...')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "UYZHMFlmNyyA", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Now you can see that the same if statement prints text. It happened because our statement amount_of_apples > 0 is now True.

That's how an if statement works — you type the if keyword, a statement and a colon. Beneath it, with an indentation of 4 spaces (1 tab), you place any code you want to run in case that if statement is True. This indentation is the same as described in Notebook 1 when defining a function.

If the result of the conditional expression is False, then the code inside of the if statement block will not run. Here's another example:" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "b1eW-x-3QMbZ", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "5d7df045-b19f-432d-e620-30d7cb34f605" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "I'm an adult, I have to work right now :(\n", - "End of the cell block...\n" - ] - } - ], - "source": [ - "my_age = 25\n", - "\n", - "if my_age >= 18 and my_age <= 65:\n", - " print(\"I'm an adult, I have to work right now :(\")\n", - "\n", - "print('End of the cell block...')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "7dhdkRKERIz_", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Slightly different setting but still the same construction. As you can see in this case, the condition of the if statement is more complicated than the previous one. It combines two smaller conditions by using the keyword and. Only if both conditions are True the final result is True (otherwise it would be False).Thus, the condition can be as long and as complicated as you want it to be, just make sure that it is readable." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "h3uicp2sTA5x", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "

elif keyword


Now, let's add a bit more logic to our last example:" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "cZQHBzWcSdn8", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "0fdc9367-527d-4c1c-d4a2-b15d230a0f79" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "I'm an adult, I have to work right now :(\n", - "End of the cell block...\n" - ] - } - ], - "source": [ - "my_age = 25\n", - "\n", - "if my_age >= 18 and my_age <= 65:\n", - " print(\"I'm an adult, I have to work right now :(\")\n", - "elif my_age > 65:\n", - " print(\"I can finally retire!\")\n", - "\n", - "print('End of the cell block...')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "_6NOt61ZSufk", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Still the same output, but what if we change our age..." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "QZ-AGXaJSy7j", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "9208a2bb-328b-4fe0-d1fd-65c443c8902f" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "I can finally retire!\n", - "End of the cell block...\n" - ] - } - ], - "source": [ - "my_age = 66\n", - "\n", - "if my_age >= 18 and my_age <= 65:\n", - " print(\"I'm an adult, I have to work right now :(\") # msg #1\n", - "elif my_age > 65:\n", - " print(\"I can finally retire!\") # msg #2\n", - "\n", - "print('End of the cell block...')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "u8RcnX-sTm4G", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "See.. we have a different output. Changing the value of our variable my_age changed the output of the if statement. Furthermore, the elif keyword helped us to add more logic to our code. Now, we have three different output scenarios:
\n", - "- print message #$1$ if my_age is within the $[18, 65]$ range;
\n", - "- print message #$2$ if my_age is bigger than $65$; and,
\n", - "- print none of them if my_age doesn't comply with none of the conditions (as shown below)." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "9r9Mx2gkVyS7", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "4a513321-cca9-4c5e-ee7d-da2157e039d5" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "End of the cell block...\n" - ] - } - ], - "source": [ - "my_age = 15\n", - "\n", - "if my_age >= 18 and my_age <= 65:\n", - " print(\"I'm an adult, I have to work right now :(\") # msg #1\n", - "elif my_age > 65:\n", - " print(\"I can finally retire!\") # msg #2\n", - "\n", - "print('End of the cell block...')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "1lfzBWNfVwN0", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "One can also substitute an elif block by a different if block, however it is preferred to use elif instead to \"keep the condition together\" and to reduce code size.
\n", - "\n", - ":::{warning}\n", - "It is important to know that there should be only one if block and any number of elif blocks within it.\n", - ":::\n", - "\n", - "A last example below setting ``my_age = 88`` to run the first ``elif`` block and setting ``my_age = 7 `` to run the second ``elif`` block.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "0krMMx5DYpeO", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "19ac187f-b814-4aa5-ef91-9db6691ded6c" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "I can finally retire!\n", - "I'm really really young\n", - "End of the cell block...\n" - ] - } - ], - "source": [ - "my_age = 88\n", - "\n", - "if my_age >= 18 and my_age <= 65:\n", - " print(\"I'm an adult, I have to work right now :(\")\n", - "elif my_age > 65:\n", - " print(\"I can finally retire!\")\n", - "elif my_age < 10:\n", - " print(\"I'm really, really young\")\n", - "\n", - "\n", - "my_age = 7\n", - "\n", - "if my_age >= 18 and my_age <= 65:\n", - " print(\"I'm an adult, I have to work right now :(\")\n", - "elif my_age > 65:\n", - " print(\"I can finally retire!\")\n", - "elif my_age < 10:\n", - " print(\"I'm really really young\")\n", - "\n", - "print('End of the cell block...')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "WGUFngFNV6ys", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### else keyword\n", - "\n", - "We can go even further and add an additional scenario to our if statement with the else keyword. It runs the code inside of it only when none of the if and elif conditions are True:" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "ieXD271nW903", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "ff7edbd8-33b5-4b6e-c7e7-657ec1d4e8a0" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "I'm just young\n", - "End of the cell block...\n" - ] - } - ], - "source": [ - "my_age = 13\n", - "\n", - "if my_age >= 18 and my_age <= 65:\n", - " print(\"I'm an adult, I have to work right now :(\")\n", - "elif my_age > 65:\n", - " print(\"I can finally retire!\")\n", - "elif my_age < 10:\n", - " print(\"I'm really really young\")\n", - "else:\n", - " print(\"I'm just young\")\n", - "\n", - "print('End of the cell block...')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "5_e10m98XJIn", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "\n", - "On the previous example, since my_age is not between $[18,65]$, nor bigger than $65$, nor smaller than $10$, the else block is run.\n", - "\n", - "Below, a final example setting ``my_age = 27`` to run the ``if`` block, then setting ``my_age = 71 `` to run the first ``elif`` block. To run the second ``elif`` block we set ``my_age = 9 ``. Finally, setting ``my_age = 13 `` to run the ``else`` block." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "Qc9WVQTxX76r", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "e4a5e6aa-6ebc-43c0-f7f2-eab350c66a8f" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "I'm an adult, I have to work right now :(\n", - "End of the cell block...\n", - "------------------------\n", - "I can finally retire!\n", - "End of the cell block...\n", - "------------------------\n", - "I'm really really young\n", - "End of the cell block...\n", - "------------------------\n", - "I'm just young\n", - "End of the cell block...\n", - "------------------------\n" - ] - } - ], - "source": [ - "my_age = 27\n", - "\n", - "if my_age >= 18 and my_age <= 65:\n", - " print(\"I'm an adult, I have to work right now :(\")\n", - "elif my_age > 65:\n", - " print(\"I can finally retire!\")\n", - "elif my_age < 10:\n", - " print(\"I'm really really young\")\n", - "else:\n", - " print(\"I'm just young\")\n", - "\n", - "print('End of the cell block...')\n", - "print('------------------------')\n", - "\n", - "my_age = 71\n", - "\n", - "if my_age >= 18 and my_age <= 65:\n", - " print(\"I'm an adult, I have to work right now :(\")\n", - "elif my_age > 65: # first elif block\n", - " print(\"I can finally retire!\")\n", - "elif my_age < 10:\n", - " print(\"I'm really really young\")\n", - "else:\n", - " print(\"I'm just young\")\n", - "\n", - "print('End of the cell block...')\n", - "print('------------------------')\n", - "\n", - "\n", - "my_age = 9\n", - "\n", - "if my_age >= 18 and my_age <= 65:\n", - " print(\"I'm an adult, I have to work right now :(\")\n", - "elif my_age > 65:\n", - " print(\"I can finally retire!\")\n", - "elif my_age < 10: # second elif block\n", - " print(\"I'm really really young\")\n", - "else:\n", - " print(\"I'm just young\")\n", - "\n", - "print('End of the cell block...')\n", - "print('------------------------')\n", - "\n", - "\n", - "my_age = 13\n", - "\n", - "if my_age >= 18 and my_age <= 65:\n", - " print(\"I'm an adult, I have to work right now :(\")\n", - "elif my_age > 65:\n", - " print(\"I can finally retire!\")\n", - "elif my_age < 10:\n", - " print(\"I'm really really young\")\n", - "else: # else block\n", - " print(\"I'm just young\")\n", - "\n", - "print('End of the cell block...')\n", - "print('------------------------')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "xAytN9YkYOtw", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "That's almost everything you have to know about if statements! The last two things are:\n", - "\n", - "1. It goes from top to bottom. When the first condition to be True runs, it skips all conditions after it — as shown below:" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "clMld7oKa0n7", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "5cfedbfb-f653-4d90-abd0-658353746aea" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Condition #3\n" - ] - } - ], - "source": [ - "random_number = 17\n", - "\n", - "if random_number > 35:\n", - " print('Condition #1')\n", - "elif random_number > 25:\n", - " print('Condition #2')\n", - "elif random_number > 15:\n", - " print('Condition #3')\n", - "elif random_number > 5:\n", - " print('Condition #4')\n", - "else:\n", - " print('Condition #5')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "rfwRtedNbVs8", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "2. You can put almost everything inside each condition block and you can define variables within each block:" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 242 - }, - "collapsed": true, - "id": "5II4-Zcvbf3j", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "cb2f7c29-2970-48a2-eacc-56d6e3f1a829" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "I am a poor BSc student\n", - "x = 5\n" - ] - }, - { - "ename": "NameError", - "evalue": "name 'b' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[22], line 20\u001b[0m\n\u001b[0;32m 17\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39m'\u001b[39m\u001b[39mI am a poor MSc student\u001b[39m\u001b[39m'\u001b[39m)\n\u001b[0;32m 19\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39m'\u001b[39m\u001b[39mx =\u001b[39m\u001b[39m'\u001b[39m, x)\n\u001b[1;32m---> 20\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39m'\u001b[39m\u001b[39mb =\u001b[39m\u001b[39m'\u001b[39m, b)\n", - "\u001b[1;31mNameError\u001b[0m: name 'b' is not defined" - ] - } - ], - "source": [ - "my_income = 150\n", - "my_degree = 'BSc'\n", - "\n", - "if my_degree == 'BSc':\n", - " x = 5\n", - " if my_income > 300:\n", - " b = 2\n", - " print('I am a rich BSc student')\n", - " else:\n", - " print('I am a poor BSc student')\n", - "\n", - "elif my_degree == 'MSc':\n", - "\n", - " if my_income > 300:\n", - " print('I am a rich MSc student')\n", - " else:\n", - " print('I am a poor MSc student')\n", - "\n", - "print('x =', x)\n", - "print('b =', b)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "9nDrNWr2cjMd", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "As you can see, we can make it as complicated as we want in terms of conditional branching.

Additionally, you can see that only variables within the blocks which run were created, while other variables were not. Thus, we have a NameError that we tried to access a variable (b) that was not defined." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "fHmKWsUSKuj4", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## 2.3 Data Structures\n", - "\n", - "In this Section you will tackle a data management problem! In the first module you have learned how to create variables, which is cool. But when you populate a lot of variables, or you want to store & access them within one entity, you need to have a data structure.

There are plenty of them, which differ their use cases and complexity. Today we will tackle some of the standard Python built-in data structures. The most popular of those are: list, dict and tuple." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "BcEOnv2kTT9A", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### list\n", - "\n", - "First, the easiest and the most popular data structure in Python: list (which is similar to a typical array you could have seen in a different programming language).

\n", - "You can create a list in the following ways:\n", - "\n", - "1. Creating an empty list, option 1\n", - "2. Creating an empty list, option 2 - using the class constructor\n", - "3. Creating a list from existing data - option 1\n", - "4. Creating a list from existing data - option 2" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "U8OUPaXESz44", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "ee38751f-5efe-4a85-a9a9-a34efc3bfb02" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Type of my_list1 object \n", - "Contents of my_list1 []\n", - "--------------------\n", - "Type of my_list2 object \n", - "Contents of my_list2 []\n", - "--------------------\n", - "Type of my_list3 object \n", - "Contents of my_list3 [5, 'hello', 37.5]\n", - "--------------------\n", - "Type of my_list3 object \n", - "Contents of list_with_letters ['s', 'a', 'n', 'd', 's', 't', 'o', 'n', 'e']\n", - "--------------------\n" - ] - } - ], - "source": [ - "#1\n", - "empty_list1 = []\n", - "print('Type of my_list1 object', type(empty_list1))\n", - "print('Contents of my_list1', empty_list1)\n", - "print('--------------------')\n", - "\n", - "#2\n", - "empty_list2 = list()\n", - "print('Type of my_list2 object', type(empty_list2))\n", - "print('Contents of my_list2', empty_list2)\n", - "print('--------------------')\n", - "\n", - "#3\n", - "my_var1 = 5\n", - "my_var2 = \"hello\"\n", - "my_var3 = 37.5\n", - "\n", - "my_list = [my_var1, my_var2, my_var3]\n", - "print('Type of my_list3 object', type(my_list))\n", - "print('Contents of my_list3', my_list)\n", - "print('--------------------')\n", - "\n", - "\n", - "#4\n", - "cool_rock = \"sandstone\" # remember that a string is a collection of characters\n", - "\n", - "list_with_letters = list(cool_rock)\n", - "\n", - "print('Type of my_list3 object', type(list_with_letters))\n", - "print('Contents of list_with_letters', list_with_letters)\n", - "print('--------------------')\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "I-9MNCzBUgH9", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "As you can see, in all three cases we created a list, only the method how we did it was slightly different:\n", - "- the first method uses the bracket notation.\n", - "- the second method uses class constructor approach. \n", - "\n", - "Both methods also apply to the other data structures.\n", - "\n", - "Now, we have a list — what can we do with it?\n", - "\n", - "Well... we can access and modify any element of an existing list. In order to access a list element, square brackets [] are used with the index of the element we want to access inside. Sounds easy, but keep in mind that Python has a zero-based indexing (as mentioned in Section 1.4 in Notebook 1).\n", - "\n", - ":::{note}\n", - "A zero-based indexing means that the first element has index 0 (not 1), the second element has index 1 (not 2) and the n-th element has index n - 1 (not n)!\n", - ":::" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The ``len()` function returns the lengths of an iterable (string, list, array, etc). Since we have 3 elements, thus we can access 0th, 1st, and 2nd elements. \n", - "\n", - "After the element is accessed, it can be used as any variable, the list only provides a convenient storage. Since it is a storage - we can easily alter and swap list elements" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 295 - }, - "collapsed": true, - "id": "CksNFv0AVmLw", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "bbddff89-959c-4065-89a5-04500ceedf91" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3\n", - "First element of my list: 5\n", - "Last element of my list: 37.5\n", - "Sum of 5 and 37.5 is 42.5\n", - "[12, 'My new element', 37.5]\n" - ] - } - ], - "source": [ - "print(len(my_list))\n", - "print('First element of my list:', my_list[0])\n", - "print('Last element of my list:', my_list[2])\n", - "\n", - "summation = my_list[0] + my_list[2]\n", - "print(f'Sum of {my_list[0]} and {my_list[2]} is {summation}')\n", - "\n", - "\n", - "my_list[0] += 7\n", - "my_list[1] = \"My new element\"\n", - "\n", - "print(my_list)\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "we can only access data we have - Python will give us an error for the following" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "ename": "IndexError", - "evalue": "list assignment index out of range", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mIndexError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[4], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m my_list[\u001b[39m10\u001b[39m] \u001b[39m=\u001b[39m \u001b[39m199\u001b[39m\n", - "\u001b[1;31mIndexError\u001b[0m: list assignment index out of range" - ] - } - ], - "source": [ - "my_list[10] = 199" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "zxkLDWef7IM-", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "We can also add new elements to a list, or remove them! Adding is realized with the append method and removal of an element uses the del keyword. We can also store a list inside a list - list inception! Useful for matrices, images etc. " - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "Yos0Cl9C7W1H", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "ba48887c-c2ff-4fc6-a231-68543e8bf97a" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[12, 'My new element', 37.5, 'new addition to my variable collection!']\n", - "[12, 'My new element', 37.5, 'new addition to my variable collection!', ['another list', False, (1+2j)]]\n", - "[12, 'My new element', 'new addition to my variable collection!', ['another list', False, (1+2j)]]\n" - ] - } - ], - "source": [ - "my_list.append(\"new addition to my variable collection!\")\n", - "print(my_list)\n", - "\n", - "my_list.append(['another list', False, 1 + 2j])\n", - "print(my_list)\n", - "\n", - "del my_list[2]\n", - "print(my_list)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "WZgLxAbJ8icK", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Lists also have other useful functionalities, as you can see from the official documentation. Since lists are still objects you can try and apply some operations to them as well." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "UEBv_4u09K9T", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "96987502-088b-48d8-d114-2b9967f2de78" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[2, 4, False, 'second list', 0, 222]\n", - "['second list', 0, 222, 'second list', 0, 222, 'second list', 0, 222, 'second list', 0, 222]\n", - "['second list', 0, 222, 5050, 0, 222, 'second list', 0, 222, 'second list', 0, 222]\n" - ] - } - ], - "source": [ - "lst1 = [2, 4, False]\n", - "lst2 = ['second list', 0, 222]\n", - "\n", - "lst1 = lst1 + lst2\n", - "print(lst1)\n", - "\n", - "lst2 = lst2 * 4\n", - "print(lst2)\n", - "\n", - "lst2[3] = 5050\n", - "print(lst2)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "SVvYBl6H96du", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "As you can see, adding lists together concatenates them and multiplying them basically does the same thing (it performs addition several times, just like in real math...).

Additionally, you can also use the in keyword to check the presence of a value inside a list." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "15hwh0COFf-p", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "2b3d16c6-9487-49ea-a6f6-8ffb989ac95c" - }, - "outputs": [], - "source": [ - "print(lst1)\n", - "\n", - "if 222 in lst1:\n", - " print('We found 222 inside lst1')\n", - "else:\n", - " print('Nope, nothing there....')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "NAJZYyQd-fG2", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### tuple\n", - "\n", - "If you understood how list works, then you already understand 95% of tuple. Tuples are just like lists, with some small differences.

1. In order to create a tuple you need to use () brackets, comma or a tuple class constructor.
2. You can change the content of your list, however tuples are immutable (just like strings).\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 313 - }, - "collapsed": true, - "id": "QnEd7YSsE2Ih", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "1a2e1b57-dbff-4c7d-d7c4-8968fecf67a1" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Type of tupl1 \n", - "Content of tupl1 ()\n", - " ()\n" - ] - } - ], - "source": [ - "#1\n", - "tupl1 = tuple() \n", - "print('Type of tupl1', type(tupl1))\n", - "print('Content of tupl1', tupl1)\n", - "#2\n", - "tupl2 = () # option 2 with ()\n", - "print(type(tupl2), tupl2)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Creating a non-empty tuple using brackets or # Creating a non-empty tuple using comma. Can we change an element of a tuple?" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "my tuple (26.5, 'Oil', False, 'some additional stuff', 777)\n", - "A comma made tuple (2, 'hi!', 228)\n", - "4th element of my_tuple: some additional stuff\n" - ] - }, - { - "ename": "TypeError", - "evalue": "'tuple' object does not support item assignment", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[8], line 13\u001b[0m\n\u001b[0;32m 10\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39m'\u001b[39m\u001b[39mA comma made tuple\u001b[39m\u001b[39m'\u001b[39m, comma_tuple)\n\u001b[0;32m 12\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39m'\u001b[39m\u001b[39m4th element of my_tuple:\u001b[39m\u001b[39m'\u001b[39m, my_tuple[\u001b[39m3\u001b[39m])\n\u001b[1;32m---> 13\u001b[0m my_tuple[\u001b[39m3\u001b[39m] \u001b[39m=\u001b[39m \u001b[39m'\u001b[39m\u001b[39mwill I change?\u001b[39m\u001b[39m'\u001b[39m\n", - "\u001b[1;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" - ] - } - ], - "source": [ - "my_var1 = 26.5\n", - "my_var2 = 'Oil'\n", - "my_var3 = False\n", - "\n", - "my_tuple = (my_var1, my_var2, my_var3, 'some additional stuff', 777)\n", - "print('my tuple', my_tuple)\n", - "\n", - "\n", - "comma_tuple = 2, 'hi!', 228\n", - "print('A comma made tuple', comma_tuple)\n", - "\n", - "print('4th element of my_tuple:', my_tuple[3])\n", - "my_tuple[3] = 'will I change?'" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "1RxahCCiHJRl", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Since tuples are immutable, it has no append() method nor any other methods that alter the object they target.\n", - "\n", - "You might think that tuple is a useless class. However, there are some reasons for it to exist:\n", - "\n", - "1.Storing constants & objects which shouldn't be changed.\n", - "2.Saving memory (tuple uses less memory to store the same data than a list). ``.__sizeof__()`` determines the size of a variable in bytes.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "A9cA-BpNIMzd", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "d7100baa-0a2c-4498-b8c0-01d1733e732f" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "size of a = 48 bytes\n", - "size of b = 64 bytes\n" - ] - } - ], - "source": [ - "my_name = 'Vasyan'\n", - "my_age = 27\n", - "is_student = True\n", - "\n", - "a = (my_name, my_age, is_student)\n", - "b = [my_name, my_age, is_student]\n", - "\n", - "print('size of a =', a.__sizeof__(), 'bytes') \n", - "print('size of b =', b.__sizeof__(), 'bytes')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "IYyveiZJJOTZ", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### dict\n", - "\n", - "After seeing lists and tuples, you may think:

\"Wow, storing all my variables within another variable is cool and gnarly! But... sometimes it's boring & inconvenient to access my data by using it's position within a tuple/list. Is there a way that I can store my object within a data structure but access it via something meaningful, like a keyword...?\"

Don't worry if you had this exact same thought.. Python had it as well!

Dictionaries are suited especially for that purpose — to each element you want to store, you give it a nickname (i.e., a key) and use that key to access the value you want.\n", - "\n", - "To create an empty dictionary we used ``{}`` or class constructor ``dict()``" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "r5vjDJ8CKaT8", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "46ee6315-d5a5-40a5-8db3-175a681dbf0c" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Type of empty_dict1 \n", - "Content of it -> {}\n", - "Type of empty_dict2 \n", - "Content of it -> {}\n" - ] - } - ], - "source": [ - "empty_dict1 = {}\n", - "print('Type of empty_dict1', type(empty_dict1))\n", - "print('Content of it ->', empty_dict1)\n", - "\n", - "\n", - "empty_dict2 = dict()\n", - "print('Type of empty_dict2', type(empty_dict2))\n", - "print('Content of it ->', empty_dict2)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To create a non-empty dictionary we specify pairs of **key:value** pattern" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Content of my_dict>>> {'name': 'Jarno', 'color': 'red', 'year': 2007, 'is cool': True, 6: 'it works', (2, 22): 'that is a strange key'}\n" - ] - } - ], - "source": [ - "my_dict = {\n", - " 'name': 'Jarno',\n", - " 'color': 'red',\n", - " 'year': 2007,\n", - " 'is cool': True,\n", - " 6: 'it works',\n", - " (2, 22): 'that is a strange key'\n", - "}\n", - "\n", - "print('Content of my_dict>>>', my_dict)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "2tQEahKqM9p8", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "In the last example, you can see that only strings, numbers, or tuples were used as keys. Dictionaries can only use immutable data (or numbers) as keys:" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 242 - }, - "collapsed": true, - "id": "V38R-AweNbF7", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "6039cc3b-8d72-4f23-986f-e1027265aec5" - }, - "outputs": [ - { - "ename": "TypeError", - "evalue": "unhashable type: 'list'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[14], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m mutable_key_dict \u001b[39m=\u001b[39m {\n\u001b[0;32m 2\u001b[0m \u001b[39m5\u001b[39m: \u001b[39m'\u001b[39m\u001b[39mlets try\u001b[39m\u001b[39m'\u001b[39m,\n\u001b[0;32m 3\u001b[0m \u001b[39mTrue\u001b[39;00m: \u001b[39m'\u001b[39m\u001b[39mI hope it will run perfectly\u001b[39m\u001b[39m'\u001b[39m,\n\u001b[0;32m 4\u001b[0m \u001b[39m6.78\u001b[39m: \u001b[39m'\u001b[39m\u001b[39mheh\u001b[39m\u001b[39m'\u001b[39m,\n\u001b[0;32m 5\u001b[0m [\u001b[39m'\u001b[39m\u001b[39mNo problemo\u001b[39m\u001b[39m'\u001b[39m, \u001b[39m'\u001b[39m\u001b[39mright?\u001b[39m\u001b[39m'\u001b[39m]: \u001b[39mFalse\u001b[39;00m \n\u001b[0;32m 6\u001b[0m }\n\u001b[0;32m 8\u001b[0m \u001b[39mprint\u001b[39m(mutable_key_dict)\n", - "\u001b[1;31mTypeError\u001b[0m: unhashable type: 'list'" - ] - } - ], - "source": [ - "mutable_key_dict = {\n", - " 5: 'lets try',\n", - " True: 'I hope it will run perfectly',\n", - " 6.78: 'heh',\n", - " ['No problemo', 'right?']: False \n", - "}\n", - "\n", - "print(mutable_key_dict)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "erVQ8Yy6OFzW", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Alright, now it is time to access the data we have managed to store inside my_dict using keys!\n" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 313 - }, - "collapsed": true, - "id": "4_s_--xzORQx", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "d2dcabbb-057f-41e2-d54c-07d8ca3aa344" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Some random content of my_dict Jarno that is a strange key\n" - ] - } - ], - "source": [ - "print('Some random content of my_dict', my_dict['name'], my_dict[(2, 22)])" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Remember the mutable key dict? Let's make it work by omitting the list item." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Accessing weird dictionary...\n", - "I hope it will run perfectly\n", - "lets try\n", - "heh\n" - ] - } - ], - "source": [ - "mutable_key_dict = {\n", - " 5: 'lets try',\n", - " True: 'I hope it will run perfectly',\n", - " 6.78: 'heh'\n", - "}\n", - "\n", - "\n", - "print('Accessing weird dictionary...')\n", - "print(mutable_key_dict[True])\n", - "print(mutable_key_dict[5])\n", - "print(mutable_key_dict[6.78])" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Trying to access something we have and something we don't have" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "My favorite year is 2007\n" - ] - }, - { - "ename": "KeyError", - "evalue": "'song'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[17], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39m'\u001b[39m\u001b[39mMy favorite year is\u001b[39m\u001b[39m'\u001b[39m, my_dict[\u001b[39m'\u001b[39m\u001b[39myear\u001b[39m\u001b[39m'\u001b[39m])\n\u001b[1;32m----> 2\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39m'\u001b[39m\u001b[39mMy favorite song is\u001b[39m\u001b[39m'\u001b[39m, my_dict[\u001b[39m'\u001b[39;49m\u001b[39msong\u001b[39;49m\u001b[39m'\u001b[39;49m])\n", - "\u001b[1;31mKeyError\u001b[0m: 'song'" - ] - } - ], - "source": [ - "print('My favorite year is', my_dict['year'])\n", - "print('My favorite song is', my_dict['song'])" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "mVmNASbEPw27", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - ":::{warning} \n", - "It is best practice to use mainly strings as keys — the other options are weird and are almost never used.\n", - ":::\n", - "\n", - "What's next? Dictionaries are mutable, so let's go ahead and add some additional data and delete old ones." - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "C2Tm8iaXQ4ej", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "62ea0bcc-a09b-474e-dd7b-e2688746ff31" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "my_dict right now {'name': 'Jarno', 'color': 'red', 'year': 2007, 'is cool': True, 6: 'it works', (2, 22): 'that is a strange key'}\n", - "my_dict after some operations {'name': 'Jarno', 'color': 'red', 'is cool': True, 6: 'it works', (2, 22): 'that is a strange key', 'new_element': 'magenta', 'weight': 27.8}\n" - ] - } - ], - "source": [ - "print('my_dict right now', my_dict)\n", - "\n", - "my_dict['new_element'] = 'magenta'\n", - "my_dict['weight'] = 27.8\n", - "del my_dict['year']\n", - "\n", - "print('my_dict after some operations', my_dict)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "J80LstNFSFeN", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "You can also print all keys present in the dictionary using the .keys() method, or check whether a certain key exists in a dictionary, as shown below. More operations can be found here." - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "pEYa3nKRUZD1", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "2b850789-9071-414f-ce44-bb23203243a6" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "dict_keys(['name', 'color', 'is cool', 6, (2, 22), 'new_element', 'weight'])\n", - "\n", - "my_dict has a ['name'] key: True\n" - ] - } - ], - "source": [ - "print(my_dict.keys())\n", - "print(\"\\nmy_dict has a ['name'] key:\", 'name' in my_dict)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### Real life example: \n", - "\n", - "Analyzing satellite metadata

Metadata is a set of data that describes and gives information about other data. For Sentinel-1, the metadata of the satellite is acquired as an .xml file. It is common for Dictionaries to play an important role in classifying this metadata. One could write a function to read and obtain important information from this metadata and store them in a Dictionary. Some examples of keys for the metadata of Sentinel-1 are:\n", - " \n", - "_dict_keys(['azimuthSteeringRate', 'dataDcPolynomial', 'dcAzimuthtime', 'dcT0', 'rangePixelSpacing', 'azimuthPixelSpacing', 'azimuthFmRatePolynomial', 'azimuthFmRateTime', 'azimuthFmRateT0', 'radarFrequency', 'velocity', 'velocityTime', 'linesPerBurst', 'azimuthTimeInterval', 'rangeSamplingRate', 'slantRangeTime', 'samplesPerBurst', 'no_burst'])_\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "XvpRgp7eUsLP", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "The last important thing for this Notebook are slices. Similar to how you can slice a string (shown in Section 1.4, in Notebook 1). This technique allows you to select a subset of data from an iterable (like a list or a tuple)." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "S96Y3-HcXN3P", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "b0d9151f-f476-4ffa-de00-74f85a4b962c" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The first three elements of x: [1, 2, 3]\n", - "[1, 2, 3]\n", - "The last element is 7 or 7 or 7\n", - "[1, 2, 3]\n", - "[1, 2, 3]\n" - ] - } - ], - "source": [ - "x = [1, 2, 3, 4, 5, 6, 7]\n", - "n = len(x) \n", - "\n", - "print('The first three elements of x:', x[0:3])\n", - "print(x[:3])\n", - "print('The last element is', x[6], 'or', x[n - 1], 'or', x[-1])\n", - "print(x[0:-4])\n", - "print(x[0:3:1])" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`````{admonition} Let's break it down\n", - "This code demonstrates how to select specific elements from a list in Python using slicing:\n", - "\n", - "1. The list `x` contains numbers from 1 to 7.\n", - "2. `x[0:3]` selects the first three elements of `x`.\n", - "3. `x[:3]` achieves the same result by omitting the starting index.\n", - "4. `x[6]`, `x[n - 1]`, and `x[-1]` all access the last element of `x`.\n", - "5. `x[0:-4]` selects elements from the beginning to the fourth-to-last element.\n", - "6. `x[0:3:1]` selects elements with a step size of 1.\n", - "\n", - "`````" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "d4v9TBKyZJEh", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Thus, the general slicing call is given by iterable[start:end:step]. \n", - "\n", - "Here's another example:\n", - "\n", - "You can select all even numbers using `[::2]` or reverse the list using `[::-1]` or select a middle subset for example `[5:9]`." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "GO8qP2d1ZXkq", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "832458e8-6202-4fa8-8898-6d2a2a1ad423" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Selecting all even numbers [0, 2, 4, 6, 8, 10]\n", - "All odd numbers [1, 3, 5, 7, 9]\n", - "Normal order [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n", - "Reversed order [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]\n", - "Numbers from 5 to 8: [5, 6, 7, 8]\n" - ] - } - ], - "source": [ - "numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n", - "\n", - "print('Selecting all even numbers', numbers[::2])\n", - "print('All odd numbers', numbers[1::2])\n", - "print('Normal order', numbers)\n", - "print('Reversed order', numbers[::-1])\n", - "print('Numbers from 5 to 8:', numbers[5:9])" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "fHmKWsUSKuj4", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## 2.4 Loops\n", - "\n", - "Let's do another step to automatize things even more! Previous Sections introduced a lot of fundamental concepts, but they still don't unveil the true power of any programming language — loops!

If we want to perform the same procedure multiple times, then we would have to take the same code and copy-paste it. This approach would work, however it would require a lot of manual work and it does not look cool.

This problem is resolved with a loop construction. As the name suggest, this construction allows you to loop (or run) certain piece of code several times at one execution." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "BcEOnv2kTT9A", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### for loop\n", - "\n", - "The first and the most popular looping technique is a for loop. Let's see some examples:\n", - "\n", - "Let's create a list with some stuff in it. In order to iterate (or go through each element of a list) we use a `for` loop.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "fNaiOimubLMF", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "77085dd8-83cc-41d8-b7c1-17fc55dc38eb" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Start of the loop\n", - "In my list I can find: 100\n", - "In my list I can find: marble\n", - "In my list I can find: False\n", - "In my list I can find: 2\n", - "In my list I can find: 2\n", - "In my list I can find: [7, 7, 7]\n", - "In my list I can find: end\n", - "End of the loop\n" - ] - } - ], - "source": [ - "my_list = [100, 'marble', False, 2, 2, [7, 7, 7], 'end']\n", - "\n", - "print('Start of the loop')\n", - "for list_item in my_list:\n", - " print('In my list I can find:', list_item)\n", - "print('End of the loop')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "NkKA4qLDb9IM", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "General for loop construction looks like this:

\n", - "for iterator_variable in iterable:\n", - " do something with iterator_variable

\n", - "\n", - "During each iteration the following steps are happening under the hood (or above it):\n", - "1. iterator_variable = iterable[0]iterator_variable is assigned the first value from the iterable.\n", - "2. Then, you use iterator_variable as you wish.\n", - "3. By the end of the 'cycle', the next element from the iterable is selected (iterable[1]), i.e., we return to step 1, but now assigning the second element... and so on.\n", - "4. When there is not a next element (in other words, we have reached the end of the iterable) — it exits and the code under the loop is now executed.\n", - "\n", - "Looks cool, but what if we want to alter the original iterable (not the iterator_variable) within the loop?\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "1hZm9bOuhOiE", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "0b50490d-1d74-41cb-ba84-d4a595a7eede" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Try #1, before: [100, 'marble', False, 2, 2, [7, 7, 7], 'end']\n", - "Try #1, after [100, 'marble', False, 2, 2, [7, 7, 7], 'end']\n" - ] - } - ], - "source": [ - "x = my_list\n", - "print('Try #1, before:', x)\n", - "\n", - "for item in x:\n", - " item = [5,6,7]\n", - "\n", - "print('Try #1, after', x)\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Nothing has changed.... let's try another method. `range()` is used to generate a sequence of numbers more info [here](https://www.w3schools.com/python/ref_func_range.asp).\n", - "\n", - "`range(length_of_x)` will generate numbers from 0 till `length_of_x`, excluding the last one.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "range(0, 7)\n", - "Try #2, before [100, 'marble', False, 2, 2, [7, 7, 7], 'end']\n", - "Try #2, after [-1, -1, -1, -1, -1, -1, -1]\n" - ] - } - ], - "source": [ - "length_of_x = len(x)\n", - "\n", - "indices = range(length_of_x)\n", - "\n", - "print(indices)\n", - "print('Try #2, before', my_list)\n", - "\n", - "for id in indices:\n", - " my_list[id] = -1\n", - "\n", - "print('Try #2, after', my_list)\n", - " \n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Now we have a method in our arsenal which can not only loop through a list but also access and alter its contents. Also, you can generate new data by using a for loop and by applying some processing to it. Here's an example on how you can automatize your greetings routine!\n", - "\n", - "We create a variable `message` with a general greeting and a list with your friends names. Then an empty list where all greetings will be stored (otherwise you cannot use the `.append` in the for loop below!). \n" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['Ohayo, Mike-kun!', 'Ohayo, Alex-kun!', 'Ohayo, Maria-kun!']\n" - ] - } - ], - "source": [ - "\n", - "message = \"Ohayo\"\n", - "names = [\"Mike\", \"Alex\", \"Maria\"]\n", - "greetings = []\n", - "\n", - "for name in names:\n", - " personalized_greeting = f'{message}, {name}-kun!' \n", - " greetings.append(personalized_greeting) \n", - "\n", - "print(greetings)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "And you can also have loops inside loops!. Let's say that you put down all your expenses per day separately in euros. You can also keep them within one list together.Additionally, you can access also each expense separately! day3 is third array and 2nd expense is second element within that array." - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "All my expenses [[15, 100, 9], [200], [10, 12, 15, 5, 1]]\n", - "My second expense on day 3 is 12\n" - ] - } - ], - "source": [ - "day1_expenses = [15, 100, 9]\n", - "day2_expenses = [200]\n", - "day3_expenses = [10, 12, 15, 5, 1]\n", - "\n", - "expenses = [day1_expenses, day2_expenses, day3_expenses]\n", - "print('All my expenses', expenses)\n", - "\n", - "print(f'My second expense on day 3 is {expenses[2][1]}')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's use it in some calculations. The code bellow iterates over the expenses for each day, calculates the total expenses for each day, and then adds them together to obtain the overall total expenses. " - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Option #1: In total I have spent 367 euro!\n" - ] - } - ], - "source": [ - "total_expenses = 0\n", - "\n", - "for i in range(len(expenses)): \n", - " daily_expenses_list = expenses[i]\n", - " daily_expenses = 0\n", - " for j in range(len(daily_expenses_list)): \n", - " daily_expenses += daily_expenses_list[j]\n", - " total_expenses += daily_expenses\n", - " \n", - "print(f'Option #1: In total I have spent {total_expenses} euro!')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`````{admonition} Let's break it down\n", - "This code calculates the total expenses over multiple days using nested loops. Here's an explanation in simpler terms:\n", - "\n", - "1. We start with the variable `total_expenses` set to 0 to keep track of the total expenses.\n", - "2. The code loops over each day's expenses using the outer loop, which runs from 0 to the length of the `expenses` list.\n", - "3. Inside the loop, it accesses the expenses made on the current day by assigning `daily_expenses_list` to the expenses at index `i`.\n", - "4. It initializes `daily_expenses` as 0 to temporarily store the sum of expenses for the current day.\n", - "5. The code enters the inner loop, which iterates over the expenses for the current day using the range of the length of `daily_expenses_list`.\n", - "6. Inside the inner loop, it adds each expense to `daily_expenses` to calculate the total expenses for the current day.\n", - "7. After the inner loop completes, it adds `daily_expenses` to the `total_expenses` variable to accumulate the expenses across all days.\n", - "8. Once the outer loop finishes, it prints the total expenses using an f-string format to display the result.\n", - "`````\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Option #2" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Option #2: In total I have spent 367 euro!\n" - ] - } - ], - "source": [ - "total_expenses = 0\n", - "\n", - "for i in range(len(expenses)):\n", - " for j in range(len(expenses[i])):\n", - " total_expenses += expenses[i][j]\n", - " \n", - "print(f'Option #2: In total I have spent {total_expenses} euro!')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Option #3 - advanced techniques gathered after eternal suffering." - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Option #3: In total I have spent 367 euro!\n" - ] - } - ], - "source": [ - "total_expenses = 0\n", - "total_expenses = sum(map(sum, expenses))\n", - "print(f'Option #3: In total I have spent {total_expenses} euro!')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "TNGZ78d8LOYC", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### while loop\n", - "\n", - "The second popular loop construction is a while loop. The main difference is that it is suited for code structures that must repeat unless a certain logical condition is satisfied. It looks like this:

while logical_condition == True:
do something

And here is a working code example:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "rqsX011pL6p6", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "39bce5bb-bf01-469c-8758-6127efc4e943" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "sum in the beginning of the cycle: 0\n", - "sum in the end of the cycle: 1\n", - "sum in the beginning of the cycle: 1\n", - "sum in the end of the cycle: 2\n", - "sum in the beginning of the cycle: 2\n", - "sum in the end of the cycle: 3\n", - "sum in the beginning of the cycle: 3\n", - "sum in the end of the cycle: 4\n", - "sum in the beginning of the cycle: 4\n", - "sum in the end of the cycle: 5\n" - ] - } - ], - "source": [ - "sum = 0\n", - "\n", - "while sum < 5:\n", - " print('sum in the beginning of the cycle:', sum)\n", - " sum += 1\n", - " print('sum in the end of the cycle:', sum)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "mW02NDD4MJWn", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "As you can see, this loop was used to increase the value of the sum variable until it reached $5$. The moment it reached $5$ and the loop condition was checked — it returned False and, therefore, the loop stopped.

Additionally, it is worth to mention that the code inside the loop was altering the variable used in the loop condition statement, which allowed it to first run, and then stop. In the case where the code doesn't alter the loop condition, it won't stop (infinite loop), unless another special word is used.

Here's a simple example of an infinite loop, which you may run (by removing the #'s) but in order to stop it — you have to interrupt the Notebook's kernel or restart it." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 1000 - }, - "collapsed": true, - "id": "AmIcH59oNaxU", - "outputId": "e944bfe2-f906-45c9-ef2a-03280956679a" - }, - "outputs": [], - "source": [ - "# a, b = 0, 7\n", - "\n", - "# while a + b < 10:\n", - "# a += 1\n", - "# b -= 1\n", - "# print(f'a:{a};b:{b}')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "ryvB-qKfNxPh", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### break keyword\n", - "\n", - "After meeting and understanding the loop constructions, we can add a bit more control to it. For example, it would be nice to exit a loop earlier than it ends — in order to avoid infinite loops or just in case there is no need to run the loop further. This can be achieved by using the break keyword. The moment this keyword is executed, the code exits from the current loop." - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "hvib4ruNTN6_", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "b0f08946-864e-430a-a8cc-765303a9ac6e" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Before normal loop\n", - "0 iteration and still running...\n", - "1 iteration and still running...\n", - "2 iteration and still running...\n", - "3 iteration and still running...\n", - "4 iteration and still running...\n", - "5 iteration and still running...\n", - "6 iteration and still running...\n", - "After normal loop\n", - "Before interrupted loop\n", - "0 iteration and still running...\n", - "1 iteration and still running...\n", - "2 iteration and still running...\n", - "3 iteration and still running...\n", - "4 iteration and still running...\n", - "Leaving the loop\n", - "After interupted loop\n" - ] - } - ], - "source": [ - "stop_iteration = 4\n", - "\n", - "print('Before normal loop')\n", - "for i in range(7):\n", - " print(f'{i} iteration and still running...')\n", - "print('After normal loop')\n", - "\n", - "print('Before interrupted loop')\n", - "for i in range(7):\n", - " print(f'{i} iteration and still running...')\n", - "\n", - " if i == stop_iteration:\n", - " print('Leaving the loop')\n", - " break\n", - "print('After interupted loop')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "guxGK4uGUXBA", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "The second loop shows how a small intrusion of an if statement and the break keyword can help us with stopping the loop earlier. The same word can be also used in a while loop:" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "tVkdaOP8Ul-W", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "5f391d65-82a2-4408-d74d-af89b84a040b" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Before the loop\n", - "Inside the loop #1\n", - "Inside the loop #2\n", - "Inside the loop #3\n", - "Inside the loop #4\n", - "Inside the loop #5\n", - "Inside the loop #6\n", - "Too many iterations is bad for your health\n", - "After the loop\n" - ] - } - ], - "source": [ - "iteration_number = 0\n", - "\n", - "print('Before the loop')\n", - "while True:\n", - " iteration_number += 1\n", - "\n", - " print(f'Inside the loop #{iteration_number}')\n", - " if iteration_number > 5:\n", - " print('Too many iterations is bad for your health')\n", - " break\n", - "print('After the loop')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "AtRCfdMlWzhn", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### continue keyword\n", - "\n", - "Another possibility to be more flexible when using loops is to use the continue keyword.

This will allow you to skip some iterations (more precisely — the moment the keyword is used it will skip the code underneath it and will start the next iteration from the beginning)." - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "_1q4EB0bXMyk", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "57b11d07-251a-4319-d0ba-1d3ee1685b61" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Begin normal loop\n", - "\n", - "0 iteration and still running...\n", - "Calculating cool function for 0 -> f(0) = 3\n", - "1 iteration and still running...\n", - "Calculating cool function for 1 -> f(1) = 15\n", - "2 iteration and still running...\n", - "Calculating cool function for 2 -> f(2) = 41\n", - "3 iteration and still running...\n", - "Calculating cool function for 3 -> f(3) = 81\n", - "4 iteration and still running...\n", - "Calculating cool function for 4 -> f(4) = 135\n", - "5 iteration and still running...\n", - "Calculating cool function for 5 -> f(5) = 203\n", - "6 iteration and still running...\n", - "Calculating cool function for 6 -> f(6) = 285\n", - "\n", - "End normal loop\n", - "\n", - "-------------------\n", - "Begin altered loop\n", - "\n", - "0 iteration and still running...\n", - "1 iteration and still running...\n", - "Calculating cool function for 1 -> f(1) = 15\n", - "2 iteration and still running...\n", - "3 iteration and still running...\n", - "Calculating cool function for 3 -> f(3) = 81\n", - "4 iteration and still running...\n", - "5 iteration and still running...\n", - "Calculating cool function for 5 -> f(5) = 203\n", - "6 iteration and still running...\n", - "\n", - "End altered loop\n" - ] - } - ], - "source": [ - "def calculate_cool_function(arg):\n", - " res = 7 * arg ** 2 + 5 * arg + 3\n", - " print(f'Calculating cool function for {arg} -> f({arg}) = {res}')\n", - "\n", - "print('Begin normal loop\\n')\n", - "for i in range(7):\n", - " print(f'{i} iteration and still running...')\n", - " calculate_cool_function(i)\n", - "print('\\nEnd normal loop\\n')\n", - "\n", - "print('-------------------')\n", - "\n", - "print('Begin altered loop\\n')\n", - "for i in range(7):\n", - " print(f'{i} iteration and still running...')\n", - "\n", - " # skipping every even iteration\n", - " if i % 2 == 0:\n", - " continue\n", - " \n", - " calculate_cool_function(i)\n", - " \n", - "print('\\nEnd altered loop')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "_30hKsC4a1vy", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "As you can see, with the help of the continue keyword we managed to skip some of the iterations. Also worth noting that $0$ is divisible by any number, for that reason the calculate_cool_function(i) at i = 0 didn't run." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "lDKimbtECAAz", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## Additional study material\n", - "\n", - "* Official Python Documentation - https://docs.python.org/3/tutorial/modules.html\n", - "* https://realpython.com/python-modules-packages/\n", - "* Think Python (2nd ed.) - Sections 3 and 14 \n", - "\n", - "* Official Python Documentation - https://docs.python.org/3/tutorial/controlflow.html\n", - "* https://realpython.com/python-conditional-statements/\n", - "* Think Python (2nd ed.) - Section 5\n", - "\n", - "* Official Python Documentation - https://docs.python.org/3/tutorial/datastructures.html\n", - "* https://realpython.com/python-data-structures/\n", - "* Think Python (2nd ed.) - Sections 8, 10, 11, 12\n", - "\n", - "* Official Python Documentation - https://docs.python.org/3/tutorial/controlflow.html\n", - "* https://realpython.com/python-for-loop/\n", - "* Think Python (2nd ed.) - Section 7" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### After this Notebook you should be able to:\n", - "\n", - "- understand the difference between built-in and third-party modules\n", - "- use functions from the **`math`** module\n", - "- find available functions from any module\n", - "- generate an array for the x-axis\n", - "- calculate the **`cos`** or **`sin`** of the x-axis\n", - "- plot such functions\n", - "- understand how to load Python files as modules\n", - "- understand conditions with **`if`**, **`elif`** and, **`else`**\n", - "- understand the differences between **`list`**, **`tuple`**, and **`dict`**\n", - "- slice lists and tuples\n", - "- use **`for`** and **`while`** loops\n", - "- use the **`break`** and **`continue`** keywords inside of loops\n" - ] - } - ], - "metadata": { - "colab": { - "collapsed_sections": [], - "name": "Python_2_1.ipynb", - "provenance": [] - }, - "kernelspec": { - "display_name": "base", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.13" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/book/03/In_a_Nutshell/01.ipynb b/book/03/In_a_Nutshell/01.ipynb deleted file mode 100644 index 8d5e63c..0000000 --- a/book/03/In_a_Nutshell/01.ipynb +++ /dev/null @@ -1,534 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 3. Advanced strings and functions, files and debugging." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from math import pi \n", - "import os " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3.1 Advanced Strings\n", - "In Python, strings are created using quotes ('' or \"\") and are immutable, while f-strings are formatted strings that allow embedding expressions inside curly braces { } for dynamic value substitution during runtime. Here is a couple of examples for strings:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Alice 25 engineer\n" - ] - } - ], - "source": [ - "name = \"Alice\"\n", - "age = 25\n", - "profession = \"engineer\"\n", - "\n", - "print (name,age,profession)\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Here is the same example made as a complete sentence using f-strings. " - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "My name is Alice, I'm 25 years old, and I work as an engineer.\n" - ] - } - ], - "source": [ - "intro = f\"My name is {name}, I'm {age} years old, and I work as an {profession}.\"\n", - "\n", - "print (intro)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Formatting numbers\n", - "Python's f-strings provide a convenient way to format numbers by using the colon character and specifying the desired format. The following table demonstrates a couple of examples with the number $1$ using f-strings:

\n", - "\n", - "| Code | Result|\n", - "|------|------|\n", - "| 1:.2f | 1.00|\n", - "| 1:.0f| 1|\n", - "| 1:.10f| 1.0000000000 | \n", - "| 1:%| 100.000000%|\n", - "| 1:.1%| 100.0% |\n", - "| 1:e| 1.000000e+00 |" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In the example below, the sleep() function from the time module is used to simulate the passage of time and provide a simple demonstration of a progress bar implementation. We define a function simulate_long_running_algorithm() that performs a loop with a sleep of 0.5 seconds between iterations. Within each iteration, the progress of the algorithm is calculated and used to construct a progress bar string. The progress bar consists of a series of equal signs (=) that visually represent the progress, followed by the percentage completion formatted to one decimal defined inside an f-strings." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[====================] 100.0%\n", - "Algorithm complete!\n" - ] - } - ], - "source": [ - "import time\n", - "\n", - "def simulate_long_running_algorithm():\n", - " total_iterations = 10\n", - " for i in range(total_iterations):\n", - " time.sleep(0.5) # Simulating processing time\n", - " progress = (i + 1) / total_iterations\n", - " progress_bar = f\"[{'=' * int(progress * 20):20s}] {progress * 100:.1f}%\"\n", - " print(progress_bar, end='\\r') # Print on the same line\n", - " print(\"\\nAlgorithm complete!\")\n", - "\n", - "simulate_long_running_algorithm()\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "

Escape characters

\n", - "\n", - "Escape characters in programming are special characters that are used to represent certain non-printable or special characters within strings. They are typically represented by a backslash (' \\ ') followed by a specific character or sequence. We used two escape characters in the previous example, can you identify them?\n", - "\n", - "| Code | Result| Description |\n", - "|------|------|------ |\n", - "| \\\\' | ' | represents the escape sequence for a single quote (').|\n", - "| \\\\\\ | \\\\ | represents the escape sequence for a backslash (' \\ ').|\n", - "| \\\\n | new line| represents the escape sequence for a new line character, which moves the cursor to the beginning of the next line. | \n", - "| \\\\r | carriage return | represents the escape sequence for a carriage return character, which moves the cursor to the beginning of the current line.|\n", - "| \\\\t | tab |represents the escape sequence for a tab character, which adds horizontal spacing. |\n", - "| \\\\b | backspace | represents the escape sequence for a backspace character, which moves the cursor one position back. |" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3.2 Advanced Functions\n", - "\n", - "An example of an advanced fuction can be the lambda function. It is an anonymous function in Python that can be defined in a single line using the lambda keyword. It is typically used for simple and concise operations without the need for a formal function definition.\n", - "\n", - "Here's an example that showcases the difference between lambda functions and normal functions:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "12\n", - "12\n" - ] - } - ], - "source": [ - "# Normal function\n", - "def multiply(x, y):\n", - " return x * y\n", - "\n", - "result = multiply(3, 4)\n", - "print(result) # Output: 12\n", - "\n", - "# Lambda function\n", - "multiply_lambda = lambda x, y: x * y\n", - "\n", - "result_lambda = multiply_lambda(3, 4)\n", - "print(result_lambda) # Output: 12\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Both the normal function and the lambda function are used to multiply 3 and 4. The results obtained from both approaches are identical (12). The key difference is that the normal function is defined with the def keyword, whereas the lambda function is defined using the lambda keyword without a formal function name.\n", - "\n", - "lambda functions are particularly useful in scenarios where a small, one-time function is needed without the need for a full function definition and name." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3.3 Working with files\n", - "\n", - "A lot of the work you'll do in Python will have the following structure:\n", - "1. Read data from a file\n", - "2. Perform computations on the data\n", - "3. Visualize the results and/or save the results to a file" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### File paths\n", - "File paths on computers work based on a hierarchical structure, often represented as a tree. The root directory serves as the starting point, typically represented by a drive letter (e.g., C: on Windows). From the root directory, you can navigate to other directories using a delimiter character (\\ on Windows or / on Unix-based systems). Each directory can contain files and subdirectories, forming a hierarchical structure.\n", - "\n", - "Absolute paths specify the complete path from the root directory, while relative paths are relative to the current working directory. By understanding and manipulating file paths, you can effectively locate and access files and directories on a computer's file system." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### ``pathlib`` and os modules\n", - "\n", - "The os module in Python provides functions for interacting with the operating system, offering operations related to file management, directory handling, process management, and environment variables. It allows you to perform tasks such as creating, deleting, and modifying files and directories, launching external processes, accessing and modifying environment variables, and writing platform-independent code.\n", - "\n", - "On the other hand, the pathlib module introduced in Python 3.4 offers an object-oriented approach to working with file paths and directories. It provides the Path class, which represents paths as objects, allowing for more intuitive and expressive manipulation of paths compared to the traditional string-based operations in os. With pathlib, you can perform operations like joining paths, checking file existence, accessing file attributes, and creating directories in a more convenient and readable manner.\n", - "\n", - "The table below summuraizes some codes you can use for creating and adjusting your own file paths:" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "| Code | Result | Description |\n", - "|------|--------|-------------|\n", - "| `os.path.join(path, *paths)` | Path string | Joins one or more path components intelligently. It concatenates the arguments using the appropriate path delimiter for the operating system. |\n", - "| `os.path.abspath(path)` | Absolute path string | Returns the absolute path of the specified path. It resolves any symbolic links and references to parent directories. |\n", - "| `os.path.exists(path)` | Boolean | Checks if the specified path exists in the file system. Returns `True` if the path exists, and `False` otherwise. |\n", - "| `os.path.isdir(path)` | Boolean | Checks if the specified path is a directory. Returns `True` if the path is a directory, and `False` otherwise. |\n", - "| `os.path.isfile(path)` | Boolean | Checks if the specified path is a regular file. Returns `True` if the path is a file, and `False` otherwise. |\n", - "| `os.path.splitext(path)` | Tuple (base, ext) | Splits the specified path into its base name and extension. Returns a tuple where the first element is the base name and the second element is the extension (including the dot). |\n", - "| `os.path.basename(path)` | Base name string | Returns the base name (the file or directory name) from the specified path. |\n", - "| `os.path.dirname(path)` | Directory name string | Returns the directory name from the specified path. |\n", - "\n", - "Here are some examples of how to use these codes: " - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Path: folder\\subfolder\\file.txt\n", - "Absolute Path: c:\\Users\\ahmed\\Documents\\GitHub\\learn-python\\book\\03\\In_a_Nutshell\\folder\\subfolder\\file.txt\n", - "Exists: False\n", - "Is Directory: False\n", - "Is File: False\n", - "Base Name: file.txt\n", - "Directory Name: folder\\subfolder\n", - "Extension: .txt\n" - ] - } - ], - "source": [ - "import os\n", - "\n", - "path = os.path.join('folder', 'subfolder', 'file.txt') # Joining path components intelligently using appropriate delimiter.\n", - "absolute_path = os.path.abspath(path) # Getting the absolute path of the specified path.\n", - "exists = os.path.exists(path) # Checking if the specified path exists.\n", - "is_directory = os.path.isdir(path) # Checking if the specified path is a directory.\n", - "is_file = os.path.isfile(path) # Checking if the specified path is a file.\n", - "base_name, extension = os.path.splitext(path) # Splitting the path into base name and extension.\n", - "basename = os.path.basename(path) # Getting the base name (file or directory name) from the path.\n", - "dirname = os.path.dirname(path) # Getting the directory name from the path.\n", - "\n", - "# Printing the information\n", - "print(\"Path:\", path) # Path string\n", - "print(\"Absolute Path:\", absolute_path) # Absolute path string\n", - "print(\"Exists:\", exists) # Boolean indicating if path exists\n", - "print(\"Is Directory:\", is_directory) # Boolean indicating if path is a directory\n", - "print(\"Is File:\", is_file) # Boolean indicating if path is a file\n", - "print(\"Base Name:\", basename) # Base name of the file or directory\n", - "print(\"Directory Name:\", dirname) # Directory name of the path\n", - "print(\"Extension:\", extension) # File extension with the dot\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This code demonstrates the usage of various os.path functions to perform operations on file paths, such as joining paths, obtaining absolute paths, checking existence, identifying directories or files, splitting paths into base names and extensions, and retrieving the base name and directory name from a path. The corresponding outputs are displayed to provide the relevant information." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3.4 Debugging \n", - "\n", - "Debugging in Python refers to the process of identifying and resolving errors or issues in a program. It involves analyzing the code execution, tracking down bugs, and correcting them to ensure the program functions as intended. \n", - "\n", - "Python provides several built-in tools and techniques for debugging, including print statements, using a debugger, logging, and exception handling. Debugging allows developers to gain insights into the program's flow, variable values, and identify the root cause of errors, ultimately improving the program's reliability and performance.\n", - "\n", - "### 1. Syntax errors\n", - "\n", - "Syntax errors in Python are mistakes in the structure or grammar of the code that violate the language's syntax rules, resulting in the program failing to execute.\n", - "\n", - "Example with a syntax error:\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "ename": "SyntaxError", - "evalue": "incomplete input (3691034111.py, line 1)", - "output_type": "error", - "traceback": [ - "\u001b[1;36m Cell \u001b[1;32mIn[9], line 1\u001b[1;36m\u001b[0m\n\u001b[1;33m print(\"Hello, World!\"\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m incomplete input\n" - ] - } - ], - "source": [ - "print(\"Hello, World!\"" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Could you spot and fix the syntax error? The error was missing to close the parenthesis,the solution is shown below: " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(\"Hello, World!\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2. Runtime errors\n", - "\n", - "Runtime errors, also known as exceptions, occur during the execution of a program when unexpected conditions or behaviors are encountered, leading to program termination or abnormal behavior.\n", - "\n", - "For example:" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "ename": "IndexError", - "evalue": "list index out of range", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mIndexError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[16], line 3\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[39m# Runtime error: accessing an index that is out of range\u001b[39;00m\n\u001b[0;32m 2\u001b[0m numbers \u001b[39m=\u001b[39m [\u001b[39m1\u001b[39m, \u001b[39m2\u001b[39m, \u001b[39m3\u001b[39m]\n\u001b[1;32m----> 3\u001b[0m \u001b[39mprint\u001b[39m(numbers[\u001b[39m3\u001b[39;49m])\n", - "\u001b[1;31mIndexError\u001b[0m: list index out of range" - ] - } - ], - "source": [ - "# Runtime error: accessing an index that is out of range\n", - "numbers = [1, 2, 3]\n", - "print(numbers[3])" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Solution: Use a valid index within the range of the list. See the cell below:" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3\n" - ] - } - ], - "source": [ - "numbers = [1, 2, 3]\n", - "print(numbers[2])" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 3. Semantic errors\n", - "\n", - "Semantic errors, also known as logic errors, are mistakes in the program's logic or algorithm that lead to undesired or incorrect behavior without causing the program to terminate or throw an error.\n", - "\n", - "For example: " - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "7.8\n" - ] - } - ], - "source": [ - "# Semantic error: incorrect calculation of the average\n", - "numbers = [5, 8, 12, 3, 6]\n", - "total = sum(numbers)\n", - "average = total / len(numbers) + 1\n", - "print (average)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Solution: Move the addition after calculating the average. Like this:" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "7.0\n" - ] - } - ], - "source": [ - "real_average = (total + 1) / len(numbers)\n", - "print (real_average)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Debugging strategies\n", - "\n", - "\n", - "Debugging strategies are a set of techniques and approaches used to identify and fix errors or issues in code during the software development process, ensuring the program functions correctly and as intended. Some debugging strategies that can be applied by you during your work could include:\n", - "\n", - "1. Using print statements: Inserting print statements at critical points in the code to display the values of variables and track the program's flow.\n", - "2. Utilizing a debugger: Running the code in a debugger, setting breakpoints, and stepping through the code line by line to examine variable values and identify issues.\n", - "3. Logging: Adding log statements to record the program's execution and capture relevant information for analysis.\n", - "4. Exception handling: Wrapping sections of code in try-except blocks to catch and handle specific exceptions, allowing for graceful error handling and troubleshooting.\n", - "5. Code review: Having someone else review the code to spot potential errors or provide fresh insights.\n", - "\n", - "\n", - "By employing these strategies, you can effectively identify and resolve issues in your code, enhancing program functionality and reliability." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.2" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/book/03/Theory/01.ipynb b/book/03/Theory/01.ipynb deleted file mode 100644 index 4a1ef44..0000000 --- a/book/03/Theory/01.ipynb +++ /dev/null @@ -1,1065 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "# 3. Advanced strings and functions, files and debugging." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "It is common to have the first cell in a Notebook with all imports needed.\n", - "\n", - "We start to impor `pi` function from the `math` module and `os` module that we will use later.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [], - "source": [ - "from math import pi \n", - "import os " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## 3.1 Advanced Strings\n", - "\n", - "Welcome to the third Notebook. In this Notebook we are going to learn some advanced Python. Let's first start with strings. Run the code below and see what it prints out." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "This is an F-String\n", - "This is a string\n" - ] - } - ], - "source": [ - "MyFString = f\"This is an F-String\"\n", - "MyString = \"This is a string\"\n", - "print(MyFString)\n", - "print(MyString)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "\n", - "Now let's try inserting some data into our print() function. We'll use the list of integers [1,2,3,4]. " - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Data1: 1, Data2: 2, Data3: 3, Data4: 4\n", - "Data1: 1 ,Data2: 2 ,Data3: 3 ,Data4: 4\n" - ] - } - ], - "source": [ - "Data = [1,2,3,4]\n", - "\n", - "MyFString = f\"Data1: {Data[0]}, Data2: {Data[1]}, Data3: {Data[2]}, Data4: {Data[3]}\"\n", - "\n", - "print(MyFString)\n", - "print(\"Data1:\",Data[0],\",Data2:\",Data[1],\",Data3:\",Data[2],\",Data4:\",Data[3])" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "As you can see from the above code, it is much easier to insert variables in a string by using an f-string (formatted string)." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### Formatting numbers\n", - "\n", - "Using f-strings makes formatting numbers really easy. Just add a colon character after a number value and specify how you want to format the number. The following table demonstrates a couple of examples with the number $1$:

\n", - "\n", - "| Code | Result|\n", - "|------|------|\n", - "| 1:.2f | 1.00|\n", - "| 1:.0f| 1|\n", - "| 1:.10f| 1.0000000000 | \n", - "| 1:%| 100.000000%|\n", - "| 1:.1%| 100.0% |\n", - "| 1:e| 1.000000e+00 |\n", - "\n", - "As you can see the default number of decimal places is six. Furthermore, the % formatting operator assumes that $1$ is equal to $100$%, which is usual when working with fractions, and the formatting operator e formats using scientific notation." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Now let's use our newfound knowledge of strings to make a simple progress bar. During other courses, you'll sometimes have to write algorithms that take a long time to run. In this case, it is useful to have a progress bar. Our example of a progress bar makes use of the sleep() function, from the time module, to simulate elapsed time." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Loading: 0%\n", - "Loading: 10%\n", - "Loading: 20%\n", - "Loading: 30%\n", - "Loading: 40%\n", - "Loading: 50%\n", - "Loading: 60%\n", - "Loading: 70%\n", - "Loading: 80%\n", - "Loading: 90%\n", - "Loading: 100%\n" - ] - } - ], - "source": [ - "import time\n", - "\n", - "for i in range(11):\n", - " print(f\"Loading: {i*10}%\", )\n", - " time.sleep(0.5) " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "This works! Though it is not that pretty to look at. It would look nicer to not have it print a new line each time. This is where escape characters come in. These characters can do some special things in strings. Below an example of some escape characters:\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "

Escape characters

\n", - "\n", - "| Code | Result|\n", - "|------|------|\n", - "| \\\\' | ' |\n", - "| \\\\\\ | \\\\ |\n", - "| \\\\n | new line| \n", - "| \\\\r | carriage return |\n", - "| \\\\t | tab |\n", - "| \\\\b | backspace |\n", - "\n", - "We can use some of these characters in our code. Let's use the carriage return character to make our progress bar not print out a new line every time. We can do this by adding end=\"\\r\" into our print function. The end keyword specifies a string that gets printed at the end. The string we print at the end here is the carriage return character. This carriage resets the print function to the start of the line; thus making the next print function overwrite the current printed line. Try it and see what happens:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "This is a very important message\n" - ] - } - ], - "source": [ - "print(\"Will I get overwritten?\", end=\"\\r\")\n", - "print(\"This is a very important message\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Now let's add this to our progress bar... " - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Loading complete!\n" - ] - } - ], - "source": [ - "import time\n", - "for i in range(11):\n", - " print(f\"Loading: {i*10}%\", end=\"\\r\")\n", - " time.sleep(0.5) \n", - "print(\"Loading complete!\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "As you can see, it works beautifully!" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## 3.2 Advanced Functions\n", - "\n", - "Sometimes you want to use the same code multiple times, so you could embed this code into a function. However, sometimes the code you want to use is so short that putting it into a function feels a bit over the top. This is where lambda functions are useful.

Lambda functions are functions that can take any number of arguments but can only have one expression in their function body. To demonstrate, see the code below. Here we have two functions that do exactly the same, but one is a lambda function and the other one is a normal function. " - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The square root of 16 is equal to 4\n", - "The square root of 16 is equal to 4\n" - ] - } - ], - "source": [ - "sqrt_lambda = lambda x : x**0.5\n", - "\n", - "def sqrt(x):\n", - " sqrt = x**0.5\n", - " return sqrt\n", - "\n", - "print(f\"The square root of 16 is equal to {sqrt_lambda(16):.0f}\")\n", - "print(f\"The square root of 16 is equal to {sqrt(16):.0f}\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "
\n", - "As you can see, the lambda version is much more concise. It automatically returns the computed value for you as well." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3.3 Working with files\n", - "\n", - "A lot of the work you'll do in Python will have the following structure:\n", - "1. Read data from a file\n", - "2. Perform computations on the data\n", - "3. Visualize the results and/or save the results to a file\n", - "\n", - "So far, we have only learned about computations. So let's learn a bit about how to manage files. Actually, opening or saving files is usually done with the help of modules which you will learn in more detail in Notebook 4 and 6. What we'll discuss here is how to manage file paths.\n", - "\n", - "### File paths\n", - "\n", - "To learn how to use files we need to learn how file paths in computers work. If you are tech-savvy and know how file paths work you can skip this part.\n", - "\n", - "File paths in computers work like a tree. They start at the root directory, which is often the C: drive (in Windows). This is the name of the hard drive that stores your Operating System. From the C: drive you can navigate into other directories. This is done using the **``\\``** character, however in other Operating Systems often the / delimiter is used.\n", - "\n", - "If a file is in the folder Users, which is stored in the C: directory, the file path would be C:\\Users. These types of file paths are called absolute paths. This file path is valid for most computers that run Windows, but some other Operating Systems may have different folder setups. This is why it is useful to use relative paths. Relative paths do not start from the root directory. Instead, they start from the directory you are currently in. By default, Jupyter Notebooks are stored in C:\\Users\\CurrentUser (where CurrentUser is your Windows username). To move into a directory using a relative path, for example, to the desktop folder, you would just write .\\Desktop. To move back a directory, using a relative path, you would type ..\n", - "\n", - "`os.listdir()` or `os.listdir('./')` list all the entries in your current directory `os.listdir('../')` list all entries if we go back one level. \n", - "\n", - ":::{note}\n", - "We use the `/` as delimiter, since a `\\` won't work on macOS\n", - ":::" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['01.ipynb']\n", - "['01.ipynb']\n", - "['Exercises', 'In_a_Nutshell', 'Theory']\n" - ] - } - ], - "source": [ - "import os\n", - "\n", - "print(os.listdir())\n", - "print(os.listdir('./'))\n", - "\n", - "print(os.listdir('../'))" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - ":::{warning}\n", - "Keep in mind that, in Python, all file paths must be strings!\n", - ":::" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### ``pathlib`` and os modules\n", - "\n", - "These modules are very useful in managing and navigating your file paths. The function path.expanduser('~'), from the os module, allows you to find your root directory, independent of your Operating System. Try the below cell to see it." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "C:\\Users\\mmendozalugo\n" - ] - } - ], - "source": [ - "from pathlib import Path\n", - "import os\n", - "\n", - "root_path = os.path.expanduser('~')\n", - "print(root_path)\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "The path shown above is thus the absolute path to your current directory.\n", - "\n", - "This can come in handy when you write a code that needs to create directories in the user's computer to save data files and/or plots. As an example, the code below checks if a directory exists and, if it doesn't, it creates one.\n", - "\n", - "The `os.path.join` is used to concatenate two strings to form a path string with the appropriate delimiter.\n", - "\n", - "The code will check if a directory named `plots` exists in your current directory if not, it will create one." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print('Contents of current directory (before):')\n", - "print(os.listdir(root_path))\n", - "\n", - "imdir = os.path.join(root_path,'plots') \n", - "print(f'\\nimdir = {imdir}')\n", - "\n", - "Path(imdir).mkdir(parents=True, exist_ok=True)\n", - "\n", - "print('\\nContents of current directory (after creating the new directory):')\n", - "print(os.listdir(root_path))\n" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "tags": [ - "remove-input" - ] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Contents of current directory (before):\n", - "['Exercises', 'In_a_Nutshell', 'Theory']\n", - "imdir = C:\\Users\\mmendozalugo\\plots\n", - "\n", - "Contents of current directory (after creating the new directory):\n", - "['Exercises', 'In_a_Nutshell', 'plots', 'Theory']\n" - ] - } - ], - "source": [ - "root_path = r'C:\\Users\\mmendozalugo\\OneDrive\\PhD\\Work\\Python_MOOC\\PM\\learn-python\\book\\03'\n", - "\n", - "print('Contents of current directory (before):')\n", - "print(os.listdir(root_path))\n", - "\n", - "imdir = os.path.join(root_path,'plots') \n", - "print('imdir = ',r'C:\\Users\\mmendozalugo\\plots')\n", - "\n", - "Path(imdir).mkdir(parents=True, exist_ok=True)\n", - "\n", - "print('\\nContents of current directory (after creating the new directory):')\n", - "print(os.listdir(root_path))\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To delete the folder that was just created we run the code bellow." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "try:\n", - " os.rmdir(imdir)\n", - " print(f'Directory {imdir} has been deleted.')\n", - "except:\n", - " print('You already deleted the folder. :)')" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "tags": [ - "remove-input" - ] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Directory C:\\Users\\mmendozalugo\\plots has been deleted.\n" - ] - } - ], - "source": [ - "print('Directory', r'C:\\Users\\mmendozalugo\\plots','has been deleted.')\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Now you are, hopefully, a bit more used to working with file paths. For the next test, we are going to try to open a file. We can use some built-in Python functions to open a *.txt file and print its contents." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## 3.4 Debugging\n", - "\n", - "It is very easy (and common) to make mistakes when programming. We call these errors bugs. Finding these bugs in your program and resolving them is what we call debugging.\n", - "\n", - "Errors\n", - "According to Think PythonAppendix A, there are three different types of errors:\n", - "\n", - "### 1. Syntax errors\n", - "\n", - "\"In computer science, the syntax of a computer language is the set of rules that defines the combinations of symbols that are considered to be correctly structured statements or expressions in that language.\"

Therefore, a syntax error is an error that does not obey the rules of the programming language. For example, parenthesis always comes in pairs... so (1+2) is OK, but 1+2) is not. Below another example of a syntax error. As you will see — this error is caught by the interpreter before running the code (hence, the print statements do not result in anything being printed).\n", - "\n", - "For example if I want to raise 2 to the 3rd power applying the wrong syntax, it will cause a syntax error." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "ename": "SyntaxError", - "evalue": "invalid syntax (2052218902.py, line 4)", - "output_type": "error", - "traceback": [ - "\u001b[1;36m Cell \u001b[1;32mIn[12], line 4\u001b[1;36m\u001b[0m\n\u001b[1;33m 2***3\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n" - ] - } - ], - "source": [ - "print('Message before')\n", - "2***3\n", - "print('Message after')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### 2. Runtime errors\n", - "\n", - "\"The second type of error is a runtime error. This type of error does not appear until after the program has started running. These errors are also called exceptions, as they usually indicate that something exceptional (and bad) has happened.\"\n", - "\n", - "Below an example of a small script to express fractions as decimals that will cause a runtime error. The error will appear, since you cannot divide by 0." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "New fraction was added from 1and 6!\n", - " It is equal to 0.167\n", - "New fraction was added from 7and 8!\n", - " It is equal to 0.875\n", - "New fraction was added from 5and -1!\n", - " It is equal to -5.000\n" - ] - }, - { - "ename": "ZeroDivisionError", - "evalue": "division by zero", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[1], line 6\u001b[0m\n\u001b[0;32m 3\u001b[0m fractions \u001b[39m=\u001b[39m []\n\u001b[0;32m 5\u001b[0m \u001b[39mfor\u001b[39;00m i \u001b[39min\u001b[39;00m \u001b[39mrange\u001b[39m(\u001b[39mlen\u001b[39m(numerators)):\n\u001b[1;32m----> 6\u001b[0m fractions\u001b[39m.\u001b[39mappend(numerators[i] \u001b[39m/\u001b[39;49m denominators[i])\n\u001b[0;32m 7\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39mf\u001b[39m\u001b[39m'\u001b[39m\u001b[39mNew fraction was added from \u001b[39m\u001b[39m{\u001b[39;00mnumerators[i]\u001b[39m}\u001b[39;00m\u001b[39m'\u001b[39m \n\u001b[0;32m 8\u001b[0m \u001b[39mf\u001b[39m\u001b[39m'\u001b[39m\u001b[39mand \u001b[39m\u001b[39m{\u001b[39;00mdenominators[i]\u001b[39m}\u001b[39;00m\u001b[39m!\u001b[39m\u001b[39m\\n\u001b[39;00m\u001b[39m It is equal to \u001b[39m\u001b[39m{\u001b[39;00mfractions[i]\u001b[39m:\u001b[39;00m\u001b[39m.3f\u001b[39m\u001b[39m}\u001b[39;00m\u001b[39m'\u001b[39m)\n", - "\u001b[1;31mZeroDivisionError\u001b[0m: division by zero" - ] - } - ], - "source": [ - "numerators = [1, 7, 5, 12, -1]\n", - "denominators = [6, 8, -1, 0, 5]\n", - "fractions = []\n", - "\n", - "for i in range(len(numerators)):\n", - " fractions.append(numerators[i] / denominators[i])\n", - " print(f'New fraction was added from {numerators[i]}' \n", - " f'and {denominators[i]}!\\n It is equal to {fractions[i]:.3f}')\n", - " " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### 3. Semantic errors\n", - "\n", - "According to the Oxford Dictionary, 'semantic' is an adjective relating to meaning. Therefore, a 'semantic error' is an error in the meaning of your code. Your code will still run without giving any error back, but it will not result in what you expected (or desired). For that reason, semantic errors are the hardest to identify. Below an example:\n", - "\n", - "I want to raise 2 to the 3rd power. However, I apply the wrong syntax that does not represent \"pow()\". \n", - "\n", - "No error message is created, because this syntax is used for another function in Python. However, this results in an output I did not expect nor desire." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2 to the 3rd power is 1\n" - ] - } - ], - "source": [ - "power_of_2 = 2^3\n", - "print(f'2 to the 3rd power is {power_of_2}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Want to learn more about erros? Check the MUDE notebook for more detailed information about errors! MUDEWeek 1.6: Errors - Error Types " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### Debugging strategies\n", - "\n", - "There are a few ways to debug a program. A simple one is to debug by tracking your values using print statements. By printing the values of the variables in between, we can find where the program does something unwanted. For example, the code block below:" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The sum of the elements of the list A is 3.\n" - ] - } - ], - "source": [ - "A = [0, 1, 2, 3]\n", - "\n", - "def sumA(my_list):\n", - " \"returns the sum of all the values in a given list\"\n", - " my_sum = 0\n", - " i = 0\n", - " while i < len(A):\n", - " my_sum = A[i]\n", - " i += 1\n", - " return my_sum\n", - "\n", - "print('The sum of the elements of the list A is {}.'.format(sumA(A)))" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "We see that our sumA() function outputs $3$, which isn't the sum of the contents of the list $A$. By adding a print(my_sum) inside the loop we can get a clearer understanding of what goes wrong." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "var my_sum[0] = 0\n", - "var my_sum[1] = 1\n", - "var my_sum[2] = 2\n", - "var my_sum[3] = 3\n", - "The sum of the elements of the list A is 3.\n" - ] - } - ], - "source": [ - "def sumA(my_list):\n", - " \"returns the sum of all the values in a given list\"\n", - " my_sum = 0\n", - " i = 0\n", - " while i < len(A):\n", - " my_sum = A[i]\n", - " print('var my_sum[{}] = {}'.format(i,my_sum))\n", - " i += 1\n", - " return my_sum\n", - "\n", - "print('The sum of the elements of the list A is {}.'.format(sumA(A)))" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "It looks like the function is just stating the values of the list $A$, but not adding them... so we must have forgotten to add something. Below the fixed version of that function." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [], - "source": [ - "def sumA_fixed(my_list):\n", - " \"returns the sum of all the values in a given list\"\n", - " my_sum = 0\n", - " i = 0\n", - " while i < len(A):\n", - " my_sum += A[i]\n", - " print('var my_sum[{}] = {}'.format(i,my_sum))\n", - " i += 1\n", - " return my_sum\n", - "\n", - "print('The sum of the elements of the list A is {}.'.format(sumA_fixed(A)))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "print is simple and direct, and ideal for small scripts or quick troubleshooting, helping you quickly observe the state of your program. However, it is insufficient for more complex or systematic debugging needs. There are more debugging tools as Traceback, Raising Errors, Handling Errors, and Assertations. You can know more debugging tools by checking MUDEThe Python Traceback, The Python Traceback, Raising Errors, Handling Errors and Assertations." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## Additional study material\n", - "\n", - "* Official Python Documentation - https://docs.python.org/3/tutorial/inputoutput.html\n", - "* https://realpython.com/python-f-strings/\n", - "* Official Python Documentation - https://docs.python.org/3/reference/expressions.html\n", - "* https://realpython.com/python-lambda/\n", - "* Official Python Documentation - https://docs.python.org/3/library/filesys.html\n", - "* https://realpython.com/working-with-files-in-python/\n", - "* Think Python (2nd ed.) - Section 14 \n", - "* Official Python Documentation - https://docs.python.org/3/library/debug.html\n", - "* Think Python (2nd ed.) - Appendix A and all (sub-)sections\n", - "* MUDE - Week 1.6: Errors" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "After this Notebook you should be able to:\n", - "\n", - "- print a variable, formatting it in an appropriate manner\n", - "- know the existence of escape characters\n", - "- know how to use lambda functions\n", - "- understand how file paths work\n", - "- create and delete new directories \n", - "- know the three different types of errors\n", - "- have a plan when debugging your code" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "base", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.13" - }, - "latex_envs": { - "LaTeX_envs_menu_present": true, - "autoclose": false, - "autocomplete": true, - "bibliofile": "biblio.bib", - "cite_by": "apalike", - "current_citInitial": 1, - "eqLabelWithNumbers": true, - "eqNumInitial": 1, - "hotkeys": { - "equation": "Ctrl-E", - "itemize": "Ctrl-I" - }, - "labels_anchors": false, - "latex_user_defs": false, - "report_style_numbering": false, - "user_envs_cfg": false - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/book/06/In_a_Nutshell/01.ipynb b/book/06/In_a_Nutshell/01.ipynb deleted file mode 100644 index 340f64e..0000000 --- a/book/06/In_a_Nutshell/01.ipynb +++ /dev/null @@ -1,452 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 6. Pandas\n", - "\n", - "## 6.1 Introduction \n", - "\n", - "`Pandas` offers a wide range of functions to read data from various sources, such as CSV files, Excel files, SQL databases, and more. You can perform operations like filtering, sorting, grouping, merging, reshaping, and aggregating data using Pandas. It also integrates well with other popular libraries in the Python ecosystem, such as `numpy` and `matplotlib`.\n", - "\n", - "It provides powerful data structures and functions to efficiently work with structured data, such as tabular data, time series, and more. With `pandas`, you can easily load, manipulate, analyze, and visualize data for tasks like data cleaning, exploration, transformation, and modeling.\n", - "\n", - "To start using `pandas`, you need to import it into your Python script or Jupyter Notebook. The standard way to import Pandas is as follows:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The two primary data structures provided by Pandas are:\n", - "\n", - "1. `Series`: A Series in Pandas is a one-dimensional labeled array that can hold any data type. It is similar to a column in a spreadsheet or a single column of a SQL table. Each element in a Series is associated with a unique label called an `index`.\n", - "\n", - "2. `DataFrame`: A two-dimensional labeled data structure with columns of potentially different types. It is similar to a spreadsheet or a SQL table." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 6.2 ``Series``\n", - "\n", - "Here is an example where we create a list of data containing some numbers and an index list with corresponding labels. We then use these lists to create a Series using pd.Series() function. " - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Original series:\n", - "A 10\n", - "B 20\n", - "C 30\n", - "D 40\n", - "E 50\n", - "dtype: int64\n" - ] - } - ], - "source": [ - "data = [10, 20, 30, 40, 50]\n", - "index = ['A', 'B', 'C', 'D', 'E']\n", - "\n", - "s = pd.Series(data, index=index)\n", - "print(\"\\nOriginal series:\")\n", - "print (s)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We also change the created labels without having any effect on the data as follows:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Updated series:\n", - "X 10\n", - "Y 20\n", - "Zebra 30\n", - "W 40\n", - "V 50\n", - "dtype: int64\n" - ] - } - ], - "source": [ - "s.index = ['X', 'Y', 'Zebra', 'W', 'V']\n", - "print(\"\\nUpdated series:\")\n", - "print(s)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Two helpful functions when working with pandas are the `iloc[ ]` and `loc[ ]` functions. For more information see the table below:" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "| Function | Description | Example |\n", - "|----------|---------------------------------------------|----------------------------------------------------|\n", - "| `iloc[ ]` | Integer-based indexing and selection | s.iloc[0] accesses the first row of a DataFrame |\n", - "| | | s.iloc[2:4] accesses a slice of rows in a DataFrame |\n", - "| `loc[ ]` | Label-based indexing and selection | s.loc['X'] accesses a row labeled 'A' in a DataFrame |\n", - "| | | s.loc[['X', 'W']] accesses multiple rows in a DataFrame |\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Zebra 30\n", - "W 40\n", - "dtype: int64" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "s.iloc[2:4] " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 6.3 ``DataFrame``\n", - "In the example below, we start by creating a dictionary data that contains information about names, ages, and cities. We then use this dictionary to create a `dataframe` df using pd.DataFrame( ). " - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Original DataFrame:\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
NameAgeCity
0John25London
1Alice28Paris
2Bob22Berlin
\n", - "
" - ], - "text/plain": [ - " Name Age City\n", - "0 John 25 London\n", - "1 Alice 28 Paris\n", - "2 Bob 22 Berlin" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "data2 = {'Name': ['John', 'Alice', 'Bob'],\n", - " 'Age': [25, 28, 22],\n", - " 'City': ['London', 'Paris', 'Berlin']}\n", - "\n", - "df = pd.DataFrame(data2)\n", - "\n", - "print(\"Original DataFrame:\")\n", - "df " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can then use the `loc[ ]` and `loc[ ]` functions to locate specific data from your `dataframe`. For example:" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Using iloc[]:\n", - "Name John\n", - "Age 25\n", - "City London\n", - "Name: 0, dtype: object\n", - " Name Age City\n", - "1 Alice 28 Paris\n", - "2 Bob 22 Berlin\n", - "25\n", - "\n", - "Using loc[]:\n", - "Name John\n", - "Age 25\n", - "City London\n", - "Name: 0, dtype: object\n", - " Name Age City\n", - "1 Alice 28 Paris\n", - "2 Bob 22 Berlin\n", - "25\n" - ] - } - ], - "source": [ - "print(\"\\nUsing iloc[]:\")\n", - "print(df.iloc[0]) \n", - "print(df.iloc[1:3]) \n", - "print(df.iloc[0, 1]) \n", - "\n", - "print(\"\\nUsing loc[]:\")\n", - "print(df.loc[0]) \n", - "print(df.loc[1:2]) \n", - "print(df.loc[0, 'Age']) " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We then add and remove some data from the created `dataframe`. You can remove rows and columns from a datafram by using the Yourdataframename.drop() function." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Updated DataFrame:\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
NameCitySalary
0JohnNew York5000
2BobBerlin4500
\n", - "
" - ], - "text/plain": [ - " Name City Salary\n", - "0 John New York 5000\n", - "2 Bob Berlin 4500" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.loc[0, 'City'] = 'New York'\n", - "df['Salary'] = [5000, 6000, 4500]\n", - "\n", - "df = df.drop(1) \n", - "df = df.drop('Age', axis=1) \n", - "\n", - "print(\"\\nUpdated DataFrame:\")\n", - "df" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 6.4 Importing data into DataFrames and exploring its attributes\n", - "\n", - "You can also make a `dataframes` from any csv file (excel files, delimited text files, etc). The table below summarizes the important functions you need to remember when applying the `pd.read_csv()` command.\n", - "\n", - "| Aspect | Description | Function |\n", - "|--------------|---------------------------------------------------|------------------------------------|\n", - "| File Path | Specify the path or filename of the CSV file | pd.read_csv('file_path.csv') |\n", - "| Delimiter | Define the delimiter used in the CSV file | pd.read_csv('file.csv', delimiter=',') |\n", - "| Header | Specify whether the CSV file has a header row | pd.read_csv('file.csv', header=0) |\n", - "| Columns | Select specific columns from the CSV file | pd.read_csv('file.csv', usecols=['col1', 'col2']) |\n", - "| Index Column | Set a specific column as the index of the DataFrame | pd.read_csv('file.csv', index_col='column') |\n", - "| Data Types | Specify data types for columns in the DataFrame | pd.read_csv('file.csv', dtype={'col1': int, 'col2': float}) |\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "```{note}\n", - ":class: Collapsed \n", - "The excel file needs to be in the same place in the folder that the python file is at for this to work!\n", - "```" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.2" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/book/07/Theory/01.ipynb b/book/07/Theory/01.ipynb deleted file mode 100644 index 0bf08ab..0000000 --- a/book/07/Theory/01.ipynb +++ /dev/null @@ -1,571 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "# 7. Matplotlib\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## 7.1 Introduction\n", - "Matplotlib is a Python module that allows you to create visualizations. Until now, you have probably used Excel to make graphs, but Python offers much more versatility. In this section, you will learn how to use matplotlib to make good-looking graphs.\n", - "\n", - "As always, let's import the module. We will also import numpy and pandas." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import pandas as pd" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "From the matplotlib library we will discuss the following functions:\n", - "- plt.subplot()\n", - "- plt.plot()\n", - "- plt.title()\n", - "- plt.suptitle()\n", - "- plt.xlabel() and plt.ylabel()\n", - "- plt.xlim() and plt.ylim()\n", - "- plt.legend()\n", - "- plt.grid()\n", - "- plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 7.2 Simple plot\n", - "Let's start by creating a simple line plot of the equation $y=3x+5$. We will use numpy to create an array which acts as our x-axis" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "x = np.linspace(0,10)\n", - "y = 3*x + 5\n", - "\n", - "plt.figure(figsize=(6,3))\n", - "plt.plot(x, y)\n", - "plt.xlabel('X-axis')\n", - "plt.ylabel('Y-axis')\n", - "plt.title('Line Plot')\n", - "plt.show()\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`````{admonition} Let's break it down\n", - "Here's a breakdown of what each line does:\n", - "1. `x = np.linspace(0, 10)`: This line generates a sequence of evenly spaced numbers between 0 and 10. `np.linspace()` creates an array of numbers with a specified start and end point.\n", - "2. `y = 3*x + 5`: This line calculates the values for the y-axis based on the values of x. It uses a simple equation `3*x + 5`, which means each y-value is obtained by multiplying the corresponding x-value by 3 and adding 5.\n", - "3. `plt.figure(figsize=(6,3))`: This line creates a new figure (or plot) with a specified size. The `figsize` parameter sets the width and height of the figure. In this case, the width is 6 units and the height is 3 units.\n", - "4. `plt.plot(x, y)`: This line plots the x and y values on the figure. It takes the x and y values as input and connects them with a line.\n", - "5. `plt.xlabel('X-axis')`: This line sets the label for the x-axis of the plot to 'X-axis'.\n", - "6. `plt.ylabel('Y-axis')`: This line sets the label for the y-axis of the plot to 'Y-axis'.\n", - "7. `plt.title('Line Plot')`: This line sets the title of the plot to 'Line Plot'.\n", - "8. `plt.show()`: This line displays the plot on the screen. `plt.show()` is a function that shows the plot that has been created.\n", - "`````" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 7.3 Customizing the Plot\n", - "\n", - "`matplotlib` provides numerous options for customizing your plots. Let's make some modifications to our previous plot. " - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.figure(figsize=(4,2))\n", - "plt.plot(x, y, linestyle='--', linewidth=5, color='r')\n", - "plt.xlim(2, 8) \n", - "plt.ylim(15, 25)\n", - "plt.xlabel('X-axis', fontsize=14, color='b')\n", - "plt.ylabel('Y-axis', fontsize=14, color='b')\n", - "plt.title('Customized plot', fontsize=18)\n", - "plt.grid(True)\n", - "plt.show() " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`````{admonition} Let's break it down\n", - "1. `plt.figure(figsize=(4,2))`: Creates a new plot with a width of 4 units and height of 2 units.\n", - "2. `plt.plot(x, y, linestyle='--', linewidth=5, color='r')`: Plots the x and y values with a dashed line style, a line width of 5 units, and a red color.\n", - "3. `plt.xlim(2, 8)`: Sets the x-axis limits to range from 2 to 8.\n", - "4. `plt.ylim(10, 30)`: Sets the y-axis limits to range from 15 to 25.\n", - "5. `plt.xlabel('X-axis', fontsize=14, color='b')`: Adds a blue x-axis label with a font size of 14 units.\n", - "6. `plt.ylabel('Y-axis', fontsize=14, color='b')`: Adds a blue y-axis label with a font size of 14 units.\n", - "7. `plt.title('Customized plot', fontsize=18)`: Sets the plot's title to 'Customized plot' with a font size of 18 units.\n", - "8. `plt.grid(True)`: Adds a grid to the plot.\n", - "9. `plt.show()`: Displays the plot on the screen.\n", - "`````" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 7.4 Scatter plot.\n", - "\n", - "A scatter plot is a type of plot used to display the relationship between two variables. In civil engineering, scatter plots can be used to analyze various aspects of data. Let's consider a scenario where civil engineers are studying the relationship between the compressive strength of concrete and the curing time. To investigate this relationship, the engineers collect data from concrete samples. For each sample, they measure the compressive strength after different curing times. The collected data might look like this:\n", - "\n", - "| Curing Time (days) | Compressive Strength (MPa) |\n", - "|--------------------|----------------------------|\n", - "| 3 | 18 |\n", - "| 7 | 28 |\n", - "| 14 | 38 |\n", - "| 21 | 46 |\n", - "| 28 | 55 |\n", - "\n", - "To visualize this data, the engineers can create a scatter plot, where the x-axis represents the curing time in days, and the y-axis represents the compressive strength in megapascals (MPa). Each data point in the plot corresponds to a specific curing time and the corresponding compressive strength. By examining the scatter plot, the civil engineers can observe the trend or pattern of the data points. They can determine if there is a correlation between curing time and compressive strength, and analyze how the strength changes with the increase in curing time. \n", - "\n", - "Let's create the corresponding scatter plot:" - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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sDA8+OCDRvsvXryIIUOGwM3NDXfddVeDa5Xm5eXhxRdfRFhYGFxdXREREYFZs2YZxabVatGjR49653744YdwcXFBUVERAODTTz/FfffdB1dXV2g0Gjz22GM4ePCg4fiQkBA88sgjWLly5S3viWyDs1CSWWpra/HTTz9Bq9VCqVRate5nn30WL730EmbNmgU3N7dGjzty5AgWLVqEhQsX4vr165g2bRqee+45w7J0QggMHToUly5dwscffwyVSoVFixbhjz/+gELRePtm/PjxyM3NxZo1a7Bz504AgJeXV5MxT5o0CWPHjsWECRPw73//G88//zx+++03HD9+HB999BGys7Mxbdo0hIWFGboviouL8dhjj8HDwwPLli2DSqXCsmXL8MQTT+D06dNo27Zto9f7/vvv0b1793r7hw4ditzcXHz44Yfw9vbGwoULkZOTg9at//e/ekFBAdRqNZYsWYI2bdrg1KlTmDdvHvLy8rBixQoANxa2HjhwIDIzMxEVFWU499NPP8VTTz0FtVqNvXv3Yty4cXj11VcxaNAgVFRU4Oeff64393z37t2xffv2Jn9/ZEP2/lOCWqb8/HwBQMyYMeOWx549e1YAMFoMWoj63QgrVqwQAMTChQvr1QHAaEHwXr16CXd3d3H58uV65+fk5Agh/tedtHfvXsMxZWVlQqVS3bL7orHumpv3181S+frrrxv26XQ60apVK9GuXTtx7do1w36tViseeOABw89z5swRKpVKXLp0ybCvqqpKBAcHi9dee63R2PR6vXB2djb6fQghxDfffCMAiB07dhjF4unp2eT91tTUiNWrV4vWrVuLq1evCiGEuH79uggODja6r2PHjgkA4rvvvhNCCLFo0SKhVqsbrbfOihUrhCRJorS09JbHkvWxu4YsIkmS1euMi4sz6bgHHnjA6KFjhw4dANzoAgGAgwcPwtvbG48//rjhGA8PD5ssy9evXz/Dv1UqFdq2bYuePXsa/ZUTGRmJnJwcw8/fffcd+vTpA7VajdraWtTW1qJVq1bo1auXUZfHzYqLi1FdXV3vgeuBAwegUqnwxBNPGMXy50W4gRt/4SQnJ6NDhw5wdXWFUqnEqFGjUFtbi+zsbACAQqHAuHHjsGrVKtTW1gK40YoPCQkx/P66dOmCoqIijB07Ftu3b2908WsfHx8IIeqtEEa3B5M8mUWj0cDFxQXnz5+3et03L/zdmJsXl3ZycgIAVFVVAbjR99zQyJOmukHM1VAsDe2riw240W2yadMmKJVKo+3zzz83+jK4WV0dzs7ORvsbu9+bf5/JycmYPn06hg4dis2bN+Pnn3/G+++/b1Q3ALz44ou4cuUKtm3bhpqaGnzxxRcYO3asoavriSeewOeff47//ve/iI2NhY+PD0aPHm3or69TF2dlZWWj90S2wz55Mkvr1q3Ro0cP7NixA7W1tUZ9vjdzcXEBAFy7ds1of3FxcYPHW+uvg4CAgAbHkF++fNkq9VtKrVZjwIAB+Oc//1mv7OYEfvN5AOr1fTd2vze3oFNTUzFkyBAkJSUZ9p04caLeeUFBQRgwYAA+/fRT1NbWoqCgAC+88ILRMc899xyee+45FBQUYPPmzUhMTIRSqcTy5csNx9TFqdFoGr0nsh225Mls06ZNQ35+Pt58880Gy7dt2wbgRstZqVTi5MmThrJr165hz549No3v4Ycfhk6nw969ew37ysvLjdYrbYyTk1O9kTDWFhMTgxMnTuDee+/FQw89ZLTdf//9jZ7n4uKC4OBgnD171mj/I488gpKSEsPDYgAoKSnB999/b3RcZWWl4a+eOqtXr27wWhMmTMDWrVvxzjvvoG/fvggJCWnwOB8fH4wbNw79+vUz+pyBG6OrVCpVi1r425GwJU9mGzRoEF5//XXMmzcPJ06cwDPPPAMfHx+cPXsWn376KUpKSjBo0CAoFAoMHz4c7733Hu655x74+PjgvffegxDCJn36dQYOHIguXbrg2WefRVJSEry9vfH222/D09OzydE1AHDvvfeitrYWKSkp6N69O7y8vIxGmVjDtGnTsHr1avTq1QuvvPIKgoODceXKFRw4cACBgYFITExs9NwePXrUG2o5YMAAdOnSBaNGjcJbb70Fb29vJCUl1RsZ1K9fP6SkpOC9995DZGQkvvjiC6N1bP8sLi4Ovr6+yMjIwNq1a43K5s6di8LCQvTu3Rtt27bFsWPH8O2332LatGlGxx06dAjdu3e/5e+cbMTOD37JAWzatEnExMQIb29voVQqxd133y1efvllcfr0acMxly9fFsOGDRNeXl7irrvuEsnJyY2Orrly5Uq9a6CB0TVxcXFGx/z6668CgNi1a5dhX05Ojhg0aJBwcXERAQEBIikpSYwdO9ZolEtDampqxF//+lfh5+cnJEkSvXr1EkI0Prrm4MGDRueHhISI+Ph4o30NjdjJy8sT48aNM6z9GxQUJJ5++mnx008/NRnfhg0bhIuLS70RKzk5OSIuLs5wvwsWLKj3ey4rKxNjx44Vbdq0EW3atBETJkwQW7ZsafA+hBDipZdeEm3atBFVVVVG+7ds2SL69u0rfH19hbOzswgPDxdz584VNTU1hmOuXbsm1Gq1WL58eZP3Q7bDNV7pjnLt2jV06NABjz/+uGFMeEtUU1OD4OBgvPXWWxg9erTNrqPX6xEeHo4nn3wSy5Ytk33+1q1b8eyzz+LChQvNZs6fOw27a8ihffLJJ9Dr9YiKikJxcTE+/PBDnDt3DuvWrbN3aBZRKpWYMWMGUlJSbJLkr127ht9++w3r169HTk4OJk+ebFY9ixcvxvTp05ng7YhJnhyai4sLFi5ciHPnzgEAOnfujK1bt+Khhx6yb2BWMHHiRJSWlqKgoAA+Pj5WrfvixYt45JFH4Ovri/fee8+s5xHl5eXo1atXk88WyPbYXUNE5MD4uJuIyIExyRMROTAmeSIiB8YkT0TkwJjkiYgcGJM8EZEDY5InInJgTPJERA6MSZ6IyIH9P9khWQ34s8yzAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "curing_time = [3,7,14,21,28]\n", - "compressive_strength = [10,20,30,40,50]\n", - "\n", - "fig, ax = plt.subplots(figsize = (4,3))\n", - "ax.scatter(curing_time, compressive_strength, color='black', s=100)\n", - "ax.set_xlabel('Curing time (days)', fontsize=11)\n", - "ax.set_ylabel('Compressive strength (MPa)', fontsize=11)\n", - "plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "`````{admonition} Let's break it down\n", - "1. `curing_time = [3,7,14,21,28]` and `compressive_strength = [10,20,30,40,50]`: These lines define two lists representing the curing time and corresponding compressive strength data points.\n", - "2. `fig, ax = plt.subplots(figsize=(4, 3))`: This line creates a plot with a figure size of 4 units wide and 3 units high. The plot will contain the figure (`fig`) and axes (`ax`) objects.\n", - "3. `ax.scatter(curing_time, compressive_strength, color='gray', s=100)`: This line creates a scatter plot using the data from `curing_time` and `compressive_strength`. The dots are colored gray and have a size of 100 units.\n", - "4. `ax.set_xlabel('Curing time (days)', fontsize=11)`: This line sets the x-axis label as 'Curing time (days)' with a font size of 11 units.\n", - "5. `ax.set_ylabel('Compressive strength (MPa)', fontsize=11)`: This line sets the y-axis label as 'Compressive strength (MPa)' with a font size of 11 units.\n", - "6. `plt.show()`: This line displays the plot on the screen.\n", - "`````\n", - "\n", - ":::{note}\n", - "Notice the line `fig, ax = plt.subplots(figsize=(8, 6))`.\n", - "\n", - "When plotting with `matplotlib`, we often work with two main objects: the figure (`fig`) and the axes (`ax`).\n", - "- The figure (`fig`) is the entire window or page that everything is drawn on.\n", - "- The axes (`ax`) represents the actual plot or chart area within the figure.\n", - "\n", - "This is special helpful when dealing wit multiple subplots.\n", - ":::" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 7.5 Histograms\n", - "\n", - "A histogram is a graphical representation of the distribution of a dataset. It consists of a set of rectangular bars, where the width of each bar represents a range of values, and the height of each bar represents the frequency or count of data points falling within that range. Histograms are commonly used to visualize the distribution and frequency of data in various fields, including geosciences. For example, the study of earthquakes often involves analyzing the distribution of earthquake magnitudes. The magnitudes of earthquakes can provide valuable insights into the frequency and severity of seismic events.\n", - "\n", - "Let's consider a scenario where we have a dataset containing earthquake magnitudes. We want to visualize the distribution of these magnitudes using a histogram." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAi8AAAHHCAYAAAB3K7g2AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy88F64QAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA+PklEQVR4nO3dd3QUZf/+8WtJ2YQSCCQQkBA60hEQREC6lICCShUNiIo+KGCwoc9DERVUQCwIwlcJiHRRbHRBlKIUAanSawAJJYQSILl/f3CyPzabQLLZsBl4v87Zc5h77p353Ds7m4spuzZjjBEAAIBF5PJ2AQAAAJlBeAEAAJZCeAEAAJZCeAEAAJZCeAEAAJZCeAEAAJZCeAEAAJZCeAEAAJZCeAEAAJZCeEG2GDJkiGw22y1ZV+PGjdW4cWPH9PLly2Wz2TRnzpxbsv4ePXqoZMmSt2Rd7kpISNDTTz+tsLAw2Ww29e/f39sl3dD+/ftls9k0cuRIb5dyQynv85MnT3q7lBwlZR9cvnz5LVlf6s8A3P4IL7ipmJgY2Ww2xyMgIEDFihVTy5Yt9fHHH+vcuXMeWc/Ro0c1ZMgQbdy40SPL86ScXFtGvPvuu4qJidHzzz+vr776Sk888US6fUuWLOm0va9/tGrVyqN1/fzzzxoyZIhHl3m7ady4sWw2m8qVK5fm/MWLFzu2z60K7O6YNm2axowZ4+0ycJvw9XYBsI633npLpUqV0pUrV3Ts2DEtX75c/fv31+jRo/X999+rWrVqjr7//e9/9frrr2dq+UePHtXQoUNVsmRJ1ahRI8PPW7RoUabW444b1TZx4kQlJydnew1Z8csvv+i+++7T4MGDM9S/Ro0aGjBggEt7sWLFPFrXzz//rLFjxxJgbiIgIEC7d+/Wn3/+qTp16jjN+/rrrxUQEKBLly55qTpXDzzwgC5evCh/f39H27Rp07Rly5Ycf9QP1kB4QYa1bt1atWvXdkwPHDhQv/zyi9q2bauHHnpI27dvV2BgoCTJ19dXvr7Z+/a6cOGCcufO7fQB6Q1+fn5eXX9GnDhxQpUqVcpw/7vuukvdu3fPtnrOnz+vPHnyZNvybzdlypTR1atXNX36dKfwcunSJX377beKjIzUN99848UKneXKlUsBAQHeLgO3MU4bIUuaNm2q//3vfzpw4ICmTp3qaE/rmpfFixerQYMGKlCggPLmzasKFSrojTfekHTtHPm9994rSerZs6fjMHhMTIyka4fOq1SpovXr1+uBBx5Q7ty5Hc9N73x3UlKS3njjDYWFhSlPnjx66KGHdOjQIac+JUuWVI8ePVyee/0yb1ZbWte8nD9/XgMGDFB4eLjsdrsqVKigkSNHKvWPuNtsNr3wwgv67rvvVKVKFdntdlWuXFkLFixI+wVP5cSJE+rVq5eKFCmigIAAVa9eXZMnT3bMT7n2YN++ffrpp58cte/fvz9Dy7+RzZs3q0ePHipdurQCAgIUFhamp556SnFxcU79Ut4L27ZtU7du3RQcHKwGDRqoR48eGjt2rON1SHmkNmHCBJUpU0Z2u1333nuv1q5d69In5fULCAhQlSpV9O2337psl/Suw0i5viZle2ZmbGk5cOCAypYtqypVquj48eOSpDNnzqh///6O90PZsmX13nvvZeqIXdeuXTVz5kyn5/zwww+6cOGCOnXqlGYd//nPf1ShQgUFBgaqUKFC6tixY5rbfvPmzWrUqJECAwNVvHhxvf3225o0aZLLe6VkyZJq27atfv/9d9WpU0cBAQEqXbq0pkyZ4rS81K9148aN9dNPP+nAgQOO7ZyybVJOS6euK73tlfJ+CAwMVJ06dfTbb7+l+XolJiZq8ODBKlu2rOx2u8LDw/Xqq68qMTHRqd+NPpeQc3HkBVn2xBNP6I033tCiRYv0zDPPpNln69atatu2rapVq6a33npLdrtdu3fv1sqVKyVJFStW1FtvvaVBgwbp2WefVcOGDSVJ999/v2MZcXFxat26tbp06aLu3burSJEiN6zrnXfekc1m02uvvaYTJ05ozJgxat68uTZu3Og4QpQRGantesYYPfTQQ1q2bJl69eqlGjVqaOHChXrllVd05MgRffjhh079f//9d82dO1f/+c9/lC9fPn388cd69NFHdfDgQRUqVCjdui5evKjGjRtr9+7deuGFF1SqVCnNnj1bPXr00JkzZ9SvXz9VrFhRX331lV566SUVL17ccSooNDT0hmO+cuVKmheh5smTx/HaLV68WHv37lXPnj0VFhamrVu3asKECdq6davWrFnjEkQ6duyocuXK6d1335UxRvfcc4+OHj2qxYsX66uvvkqzjmnTpuncuXPq3bu3bDab3n//fT3yyCPau3ev44jXokWL9Oijj6pSpUoaPny4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H12uOXF3bLly5dLUqVPVvn17derUST///LOaNm2qV155Rd9//73atm3ruKX4/Pnz+vvvvzVnzhzt379fISEhGR5v/vz5M/SNxG3bttVXX32l/Pnzq1KlSlq9erWWLFnicvv9q6++qqlTp6pFixZ68cUXHbdKlyhRQqdOnfLYEdFatWpp5syZio6O1r333qu8efOqXbt2qly5su677z4NHDhQp06dUsGCBTVjxgyXUOfn56e3335bvXv3VtOmTdW5c2ft27dPkyZNcrnm5YknntCsWbP03HPPadmyZapfv76SkpK0Y8cOzZo1SwsXLlTt2rUz9LmEHMp7NzrBKlJuZUx5+Pv7m7CwMNOiRQvz0UcfOd2SmyL1rdJLly41Dz/8sClWrJjx9/c3xYoVM127dnW5fXTevHmmUqVKxtfX1+n21etvF00tvVulp0+fbgYOHGgKFy5sAgMDTWRkpDlw4IDL80eNGmXuuusuY7fbTf369c26detclnmj2lLfKm2MMefOnTMvvfSSKVasmPHz8zPlypUzH3zwgUlOTnbqJ8n06dPHpab0buFO7fjx46Znz54mJCTE+Pv7m6pVq6Z5O7enbpW+fpyHDx82HTp0MAUKFDD58+c3HTt2NEePHjWSzODBgx39rr+dOLWrV6+aF1980YSGhhqbzeZ4z6TcvvzBBx+4PCf18o0x5ptvvjEVK1Y0drvdVKpUycydOzfN7fLvv/+aRx991OTOndsEBweb3r17my1btrjcKp2VsV24cME0atTI5M2b16xZs8YYc+39MHDgQFO2bFnj7+9vQkJCzP33329GjhxpLl++fMPtcaP3foq0bpU+ffq0472RN29e07JlS7Njx44031t//fWXadiwobHb7aZ48eJm+PDh5uOPPzaSzLFjxxz90nsfpbcPXn+rdEJCgunWrZspUKCAy3tpz549pnnz5sZut5siRYqYN954wyxevDjNW9s/++wzU6pUKWO3203t2rXNihUr0txfL1++bN577z1TuXJlY7fbTXBwsKlVq5YZOnSoOXv2rDEm459LyHlsxuTwqwIBwA09evTQ8uXLs/3usttV//799fnnnyshIYELV5HjcM0LANzhLl686DQdFxenr776Sg0aNCC4IEfimhcAuMPVq1dPjRs3VsWKFXX8+HF98cUXio+P1//+9z9vlwakifACAHe4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XgAAQLZyK7z4+/tr5syZGjZsmDZt2qTAwEBVrVpVERERnq4PAADAiVvhJUX58uVVvnx5T9UCAABwU26Fl6SkJMXExGjp0qU6ceKEkpOTneb/8ssvHikOAAAgNbfCS79+/RQTE6PIyEhVqVJFNpvN03UBAACkya3wMmPGDM2aNUtt2rTxdD0AAAA35Nat0v7+/ipbtqynawEAALgpt8LLgAED9NFHH8kY4+l6AAAAbsit00a///67li1bpvnz56ty5cry8/Nzmj937lyPFAcAAJCaW+GlQIEC6tChg6drAQAAuCm3wsukSZM8XQcAAECGuHXNiyRdvXpVS5Ys0eeff65z585Jko4ePaqEhASPFQcAAJCaW0deDhw4oFatWungwYNKTExUixYtlC9fPr333ntKTEzU+PHjPV0nAACAJDePvPTr10+1a9fW6dOnFRgY6Gjv0KGDli5d6rHiAAAAUnPryMtvv/2mVatWyd/f36m9ZMmSOnLkiEcKAwAASItbR16Sk5OVlJTk0n748GHly5cvy0UBAACkx63w8uCDD2rMmDGOaZvNpoSEBA0ePJifDAAAANnKrdNGo0aNUsuWLVWpUiVdunRJ3bp1065duxQSEqLp06d7ukYAAAAHt8JL8eLFtWnTJs2YMUObN29WQkKCevXqpccff9zpAl4AAABPcyu8SJKvr6+6d+/uyVoAAABuyq3wMmXKlBvOf/LJJ90qBgAA4GbcCi/9+vVzmr5y5YouXLggf39/5c6dm/ACAACyjVt3G50+fdrpkZCQoJ07d6pBgwZcsAsAALKV279tlFq5cuU0YsQIl6MyNzJu3DhVq1ZNQUFBCgoKUr169TR//nxPlQQAAG5DHgsv0rWLeI8ePZrh/sWLF9eIESO0fv16rVu3Tk2bNtXDDz+srVu3erIsAABwG3Hrmpfvv//eadoYo9jYWH366aeqX79+hpfTrl07p+l33nlH48aN05o1a1S5cmV3SgMAALc5t8JL+/btnaZtNptCQ0PVtGlTjRo1yq1CkpKSNHv2bJ0/f1716tVzaxkAAOD251Z4SU5O9lgBf//9t+rVq6dLly4pb968+vbbb1WpUqU0+yYmJioxMdExHR8f77E6AACANXj0mhd3VKhQQRs3btQff/yh559/XlFRUdq2bVuafYcPH678+fM7HuHh4be4WgAA4G1uHXmJjo7OcN/Ro0ffcL6/v7/Kli0rSapVq5bWrl2rjz76SJ9//rlL34EDBzqtOz4+ngADAMAdxq3w8tdff+mvv/7SlStXVKFCBUnSP//8Ix8fH9WsWdPRz2azZXrZycnJTqeGrme322W3290pGQAA3CbcCi/t2rVTvnz5NHnyZAUHB0u69sV1PXv2VMOGDTVgwIAMLWfgwIFq3bq1SpQooXPnzmnatGlavny5Fi5c6E5ZAADgDuBWeBk1apQWLVrkCC6SFBwcrLffflsPPvhghsPLiRMn9OSTTyo2Nlb58+dXtWrVtHDhQrVo0cKdsgAAwB3ArfASHx+vf//916X933//1blz5zK8nC+++MKd1QMAgDuYW3cbdejQQT179tTcuXN1+PBhHT58WN9884169eqlRx55xNM1AgAAOLh15GX8+PF6+eWX1a1bN125cuXagnx91atXL33wwQceLRAAAOB6boWX3Llz67PPPtMHH3ygPXv2SJLKlCmjPHnyeLQ4AACA1LL0JXWxsbGKjY1VuXLllCdPHhljPFUXAABAmtwKL3FxcWrWrJnKly+vNm3aKDY2VpLUq1evDN9pBAAA4A63wstLL70kPz8/HTx4ULlz53a0d+7cWQsWLPBYcQAAAKm5dc3LokWLtHDhQhUvXtypvVy5cjpw4IBHCgMAAEiLW0dezp8/73TEJcWpU6f4+n4AAJCt3AovDRs21JQpUxzTNptNycnJev/999WkSROPFQcAAJCaW6eN3n//fTVr1kzr1q3T5cuX9eqrr2rr1q06deqUVq5c6ekaAQAAHNw68lKlShX9888/atCggR5++GGdP39ejzzyiP766y+VKVPG0zUCAAA4ZPrIy5UrV9SqVSuNHz9eb775ZnbUBAAAkK5MH3nx8/PT5s2bs6MWAACAm3LrtFH37t35RWgAAOAVbl2we/XqVX355ZdasmSJatWq5fKbRqNHj/ZIcQAAAKllKrzs3btXJUuW1JYtW1SzZk1J0j///OPUx2azea46AACAVDIVXsqVK6fY2FgtW7ZM0rWfA/j4449VpEiRbCkOAAAgtUxd85L6V6Pnz5+v8+fPe7QgAACAG3Hrgt0UqcMMAABAdstUeLHZbC7XtHCNCwAAuJUydc2LMUY9evRw/PjipUuX9Nxzz7ncbTR37lzPVQgAAHCdTIWXqKgop+nu3bt7tBgAAICbyVR4mTRpUnbVAQAAkCFZumAXAADgViO8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAAS/FqeBk+fLjuvfde5cuXT4ULF1b79u21c+dOb5YEAAByOK+Gl19//VV9+vTRmjVrtHjxYl25ckUPPvigzp8/782yAABADubrzZUvWLDAaTomJkaFCxfW+vXr9cADD3ipKgAAkJN5NbykdvbsWUlSwYIF05yfmJioxMREx3R8fPwtqQsAkPNs377d2yXcEUJCQlSiRAlvl+Ekx4SX5ORk9e/fX/Xr11eVKlXS7DN8+HANHTr0FlcGAMhJkhJOSzabunfv7u1S7ggBgbm1c8f2HBVgckx46dOnj7Zs2aLff/893T4DBw5UdHS0Yzo+Pl7h4eG3ojwAQA6RnJggGaNCbQfIrxB/A7LTlbhDivtxlE6ePEl4Se2FF17Qjz/+qBUrVqh48eLp9rPb7bLb7bewMgBATuVXKFz2sLLeLgNe4NXwYozRiy++qG+//VbLly9XqVKlvFkOAACwAK+Glz59+mjatGmaN2+e8uXLp2PHjkmS8ufPr8DAQG+WBgAAciivfs/LuHHjdPbsWTVu3FhFixZ1PGbOnOnNsgAAQA7m9dNGAAAAmcFvGwEAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEvxanhZsWKF2rVrp2LFislms+m7777zZjkAAMACvBpezp8/r+rVq2vs2LHeLAMAAFiIrzdX3rp1a7Vu3dqbJQAAAIvxanjJrMTERCUmJjqm4+PjvVgNAADwBktdsDt8+HDlz5/f8QgPD/d2SQAA4BazVHgZOHCgzp4963gcOnTI2yUBAIBbzFKnjex2u+x2u7fLAAAAXmSpIy8AAABePfKSkJCg3bt3O6b37dunjRs3qmDBgipRooQXKwMAADmVV8PLunXr1KRJE8d0dHS0JCkqKkoxMTFeqgoAAORkXg0vjRs3ljHGmyUAAACL4ZoXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKTkivIwdO1YlS5ZUQECA6tatqz///NPbJQEAgBzK6+Fl5syZio6O1uDBg7VhwwZVr15dLVu21IkTJ7xdGgAAyIG8Hl5Gjx6tZ555Rj179lSlSpU0fvx45c6dW19++aW3SwMAADmQV8PL5cuXtX79ejVv3tzRlitXLjVv3lyrV6/2YmUAACCn8vXmyk+ePKmkpCQVKVLEqb1IkSLasWOHS//ExEQlJiY6ps+ePStJio+P93htCQkJ19Z5bLeSL1/y+PJxzZW4Q5J4nbMbr/Otwet8a/A63zpXTh2WdO1voif/1qYsyxjj3gKMFx05csRIMqtWrXJqf+WVV0ydOnVc+g8ePNhI4sGDBw8ePHjcBo9Dhw65lR+8euQlJCREPj4+On78uFP78ePHFRYW5tJ/4MCBio6OdkwnJyfr1KlTKlSokGw2W7bX62nx8fEKDw/XoUOHFBQU5O1ybpk7ddwSY78Tx36njlti7Hfi2DM6bmOMzp07p2LFirm1Hq+GF39/f9WqVUtLly5V+/btJV0LJEuXLtULL7zg0t9ut8tutzu1FShQ4BZUmr2CgoLuqDd3ijt13BJjvxPHfqeOW2Lsd+LYMzLu/Pnzu718r4YXSYqOjlZUVJRq166tOnXqaMyYMTp//rx69uzp7dIAAEAO5PXw0rlzZ/37778aNGiQjh07pho1amjBggUuF/ECAABIOSC8SNILL7yQ5mmi253dbtfgwYNdToXd7u7UcUuM/U4c+506bomx34ljv1Xjthnj7n1KAAAAt57Xv2EXAAAgMwgvAADAUggvAADAUggvAADAUggv2WDEiBGy2Wzq379/un1iYmJks9mcHgEBAU59jDEaNGiQihYtqsDAQDVv3ly7du3K5uqzJiNjb9y4scvYbTabIiMjHX169OjhMr9Vq1a3YAQZN2TIEJca77777hs+Z/bs2br77rsVEBCgqlWr6ueff3aab4VtntlxT5w4UQ0bNlRwcLCCg4PVvHlz/fnnn059rLC9pcyP/XbazzM79ttlP5ekI0eOqHv37ipUqJACAwNVtWpVrVu37obPWb58uWrWrCm73a6yZcsqJibGpc/YsWNVsmRJBQQEqG7dui77RU6Q2bHPnTtXLVq0UGhoqIKCglSvXj0tXLjQqY87n52pEV48bO3atfr8889VrVq1m/YNCgpSbGys43HgwAGn+e+//74+/vhjjR8/Xn/88Yfy5Mmjli1b6tKlnPlDZBkd+9y5c53GvWXLFvn4+Khjx45O/Vq1auXUb/r06dlZvlsqV67sVOPvv/+ebt9Vq1apa9eu6tWrl/766y+1b99e7du315YtWxx9rLLNMzPu5cuXq2vXrlq2bJlWr16t8PBwPfjggzpy5IhTPytsbylzY5dur/08M2O/Xfbz06dPq379+vLz89P8+fO1bds2jRo1SsHBwek+Z9++fYqMjFSTJk20ceNG9e/fX08//bTTH/GZM2cqOjpagwcP1oYNG1S9enW1bNlSJ06cuBXDyhB3xr5ixQq1aNFCP//8s9avX68mTZqoXbt2+uuvv5z6ZXY/cuHWLyIhTefOnTPlypUzixcvNo0aNTL9+vVLt++kSZNM/vz5052fnJxswsLCzAcffOBoO3PmjLHb7Wb69OkerNozMjP21D788EOTL18+k5CQ4GiLiooyDz/8sOcL9aDBgweb6tWrZ7h/p06dTGRkpFNb3bp1Te/evY0x1tnmmR13alevXjX58uUzkydPdrRZYXsbk/mx3077eVa3u1X389dee800aNAgU8959dVXTeXKlZ3aOnfubFq2bOmYrlOnjunTp49jOikpyRQrVswMHz48awV7kDtjT0ulSpXM0KFDHdNZfS8ZYwxHXjyoT58+ioyMVPPmzTPUPyEhQREREQoPD9fDDz+srVu3Oubt27dPx44dc1pW/vz5VbduXa1evdrjtWdVZsd+vS+++EJdunRRnjx5nNqXL1+uwoULq0KFCnr++ecVFxfnqXI9ZteuXSpWrJhKly6txx9/XAcPHky37+rVq11en5YtWzq2p5W2eWbGndqFCxd05coVFSxY0KndCttbyvzYb6f9PCvb3ar7+ffff6/atWurY8eOKly4sO655x5NnDjxhs+52b5++fJlrV+/3qlPrly51Lx58xy13d0Ze2rJyck6d+6cy/6elfeSxGkjj5kxY4Y2bNig4cOHZ6h/hQoV9OWXX2revHmaOnWqkpOTdf/99+vw4cOSpGPHjkmSy88kFClSxDEvp8js2K/3559/asuWLXr66aed2lu1aqUpU6Zo6dKleu+99/Trr7+qdevWSkpK8lTZWVa3bl3FxMRowYIFGjdunPbt26eGDRvq3LlzafY/duzYDbenVbZ5Zsed2muvvaZixYo5fXBbYXtLmR/77bSfZ2W7W3k/37t3r8aNG6dy5cpp4cKFev7559W3b19Nnjw53eekt6/Hx8fr4sWLOnnypJKSknL8dndn7KmNHDlSCQkJ6tSpk6Mtq58hkjht5AkHDx40hQsXNps2bXK0ZfbUyeXLl02ZMmXMf//7X2OMMStXrjSSzNGjR536dezY0XTq1MkjdXtCVsf+7LPPmqpVq9603549e4wks2TJEndLzXanT582QUFB5v/+7//SnO/n52emTZvm1DZ27FhTuHBhY4x1tnlqNxv39YYPH26Cg4Od3i9pscL2NiZzYzfGuvt5WjIzdivv535+fqZevXpObS+++KK577770n1OuXLlzLvvvuvU9tNPPxlJ5sKFC+bIkSNGklm1apVTn1deecXUqVPHc8VnkTtjv97XX39tcufObRYvXnzDfpndj4zhtJFHrF+/XidOnFDNmjXl6+srX19f/frrr/r444/l6+ubof9F+Pn56Z577tHu3bslSWFhYZKk48ePO/U7fvy4Y15OkJWxnz9/XjNmzFCvXr1uup7SpUsrJCTE8frkRAUKFFD58uXTrTEsLOyG29Mq2zy1m407xciRIzVixAgtWrTophd1W2F7Sxkfewqr7udpyejYrb6fFy1aVJUqVXJqq1ix4g1Pc6S3rwcFBSkwMFAhISHy8fHJ8dvdnbGnmDFjhp5++mnNmjXrppcTZHY/kjht5BHNmjXT33//rY0bNzoetWvX1uOPP66NGzfKx8fnpstISkrS33//raJFi0qSSpUqpbCwMC1dutTRJz4+Xn/88Yfq1auXbWPJrKyMffbs2UpMTFT37t1vup7Dhw8rLi7O8frkRAkJCdqzZ0+6NdarV89pe0rS4sWLHdvTKts8tZuNW7p2R82wYcO0YMEC1a5d+6bLtML2ljI29utZdT9PS0bHbvX9vH79+tq5c6dT2z///KOIiIh0n3Ozfd3f31+1atVy6pOcnKylS5fmqO3uztglafr06erZs6emT5/udGt8ejK7H0nitFF2SX3q5IknnjCvv/66Y3ro0KFm4cKFZs+ePWb9+vWmS5cuJiAgwGzdutXRZ8SIEaZAgQJm3rx5ZvPmzebhhx82pUqVMhcvXryVQ8m0m409RYMGDUznzp1d2s+dO2defvlls3r1arNv3z6zZMkSU7NmTVOuXDlz6dKl7Cw9UwYMGGCWL19u9u3bZ1auXGmaN29uQkJCzIkTJ4wxruNeuXKl8fX1NSNHjjTbt283gwcPNn5+fubvv/929LHCNs/suEeMGGH8/f3NnDlzTGxsrONx7tw5Y4x1trcxmR/77bSfZ3bsKay+n//555/G19fXvPPOO2bXrl2OUyFTp0519Hn99dfNE0884Zjeu3evyZ07t3nllVfM9u3bzdixY42Pj49ZsGCBo8+MGTOM3W43MTExZtu2bebZZ581BQoUMMeOHbul47sRd8b+9ddfG19fXzN27Fin/f3MmTOOPjd7L2UE4SWbpP4D3qhRIxMVFeWY7t+/vylRooTx9/c3RYoUMW3atDEbNmxwWkZycrL53//+Z4oUKWLsdrtp1qyZ2blz5y0agftuNnZjjNmxY4eRZBYtWuTy/AsXLpgHH3zQhIaGGj8/PxMREWGeeeaZHLVTG3Pt1seiRYsaf39/c9ddd5nOnTub3bt3O+anNe5Zs2aZ8uXLG39/f1O5cmXz008/Oc23wjbP7LgjIiKMJJfH4MGDjTHW2d7GZH7st9N+7s77/XbYz40x5ocffjBVqlQxdrvd3H333WbChAlO86OiokyjRo2c2pYtW2Zq1Khh/P39TenSpc2kSZNclvvJJ5843h916tQxa9asycZRuCezY2/UqFGa+/v1742bvZcywmaMMRk/TgMAAOBdXPMCAAAshfACAAAshfACAAAshfACAAAshfACAAAshfACAAAshfACAAAshfACIMcbMmSIatSokS3LjomJUYECBbJl2QCyB+EFgJMePXrIZrPpueeec5nXp08f2Ww29ejR45bW9PLLLzv9DkyPHj3Uvn37W1oDgJyD8ALARXh4uGbMmKGLFy862i5duqRp06apRIkSt7yevHnzqlChQrd8vQByJsILABc1a9ZUeHi45s6d62ibO3euSpQooXvuucfRtmDBAjVo0EAFChRQoUKF1LZtW+3Zs8dpWatWrVKNGjUUEBCg2rVr67vvvpPNZtPGjRslScuXL5fNZtPSpUtVu3Zt5c6dW/fff7/Tr9lef9poyJAhmjx5subNmyebzSabzably5c7lnPmzBnH8zZu3Cibzab9+/c72mJiYlSiRAnlzp1bHTp0UFxcnMv4582bp5o1ayogIEClS5fW0KFDdfXq1Sy8ogA8ifACIE1PPfWUJk2a5Jj+8ssv1bNnT6c+58+fV3R0tNatW6elS5cqV65c6tChg5KTkyVJ8fHxateunapWraoNGzZo2LBheu2119Jc35tvvqlRo0Zp3bp18vX11VNPPZVmv5dfflmdOnVSq1atFBsbq9jYWN1///0ZGtMff/yhXr166YUXXtDGjRvVpEkTvf322059fvvtNz355JPq16+ftm3bps8//1wxMTF65513MrQOANnP19sFAMiZunfvroEDB+rAgQOSpJUrV2rGjBlavny5o8+jjz7q9Jwvv/xSoaGh2rZtm6pUqaJp06bJZrNp4sSJCggIUKVKlXTkyBE988wzLut755131KhRI0nS66+/rsjISF26dEkBAQFO/fLmzavAwEAlJiYqLCwsU2P66KOP1KpVK7366quSpPLly2vVqlVasGCBo8/QoUP1+uuvKyoqSpJUunRpDRs2TK+++qoGDx6cqfUByB4ceQGQptDQUEVGRiomJkaTJk1SZGSkQkJCnPrs2rVLXbt2VenSpRUUFKSSJUtKkg4ePChJ2rlzp6pVq+YUQOrUqZPm+qpVq+b4d9GiRSVJJ06c8OSQtH37dtWtW9eprV69ek7TmzZt0ltvvaW8efM6Hs8884xiY2N14cIFj9YDwD0ceQGQrqeeekovvPCCJGns2LEu89u1a6eIiAhNnDhRxYoVU3JysqpUqaLLly9nel1+fn6Of9tsNklynH7KiFy5rv1fzBjjaLty5Uqm60hISNDQoUP1yCOPuMxLfRQIgHcQXgCkq1WrVrp8+bJsNptatmzpNC8uLk47d+7UxIkT1bBhQ0nS77//7tSnQoUKmjp1qhITE2W32yVJa9euzXJd/v7+SkpKcmoLDQ2VJMXGxio4OFiSHBcFp6hYsaL++OMPp7Y1a9Y4TdesWVM7d+5U2bJls1wngOzBaSMA6fLx8dH27du1bds2+fj4OM0LDg5WoUKFNGHCBO3evVu//PKLoqOjnfp069ZNycnJevbZZ7V9+3YtXLhQI0eOlPT/j664o2TJktq8ebN27typkydP6sqVKypbtqzCw8M1ZMgQ7dq1Sz/99JNGjRrl9Ly+fftqwYIFGjlypHbt2qVPP/3U6XoXSRo0aJCmTJmioUOHauvWrdq+fbtmzJih//73v27XC8CzCC8AbigoKEhBQUEu7bly5dKMGTO0fv16ValSRS+99JI++OADl+f+8MMP2rhxo2rUqKE333xTgwYNkpS1UzDPPPOMKlSooNq1ays0NFQrV66Un5+fpk+frh07dqhatWp67733XO4kuu+++zRx4kR99NFHql69uhYtWuQSSlq2bKkff/xRixYt0r333qv77rtPH374oSIiItyuF4Bn2cz1J4gBIJt9/fXX6tmzp86ePavAwEBvlwPAgrjmBUC2mjJlikqXLq277rpLmzZt0muvvaZOnToRXAC4jfACIFsdO3ZMgwYN0rFjx1S0aFF17NiRL3wDkCWcNgIAAJbCBbsAAMBSCC8AAMBSCC8AAMBSCC8AAMBSCC8AAMBSCC8AAMBSCC8AAMBSCC8AAMBSCC8AAMBS/h903yzyYwO93QAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "earthquake_magnitudes = [4.5, 5.2, 4.8, 5.7, 4.9, 6.2, 5.1,\n", - " 5.5, 4.6, 5.9, 5.3, 4.7, 5.8, 4.4,\n", - " 4.8, 5.1, 5.3, 5.2, 4.9, 5.4, 5.6]\n", - "\n", - "plt.hist(earthquake_magnitudes, bins=5, edgecolor='black')\n", - "plt.xlabel('Magnitude')\n", - "plt.ylabel('Frequency')\n", - "plt.title('Distribution of Earthquake Magnitudes')\n", - "plt.show()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`````{admonition} Let's break it down\n", - "In the example, we first define the earthquake magnitudes in the `earthquake_magnitudes` list. We then create a histogram using `plt.hist()`, where `earthquake_magnitudes` is the data, and `bins=5` specifies the number of bins or bars in the histogram. The `edgecolor='black'` parameter sets the color of the edges of the bars.\n", - "\n", - "We then set the x-axis label as 'Magnitude', the y-axis label as 'Frequency', and the title as 'Distribution of Earthquake Magnitudes' using the appropriate `plt.xlabel()`, `plt.ylabel()`, and `plt.title()` functions.\n", - "\n", - "Finally, we display the histogram on the screen using `plt.show()`.\n", - "\n", - "The resulting histogram will visualize the distribution of earthquake magnitudes, showing the frequency of magnitudes falling within each bin. This information can help geoscientists understand the distribution and characteristics of earthquakes in the studied region.\n", - "`````" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 7.6 Subplots\n", - "\n", - "In Python, subplots refer to the division of a single figure into multiple smaller plots or subplots. Each subplot is an independent plot area within the larger figure. Subplots are useful when you want to display multiple plots or visualizations side by side or in a grid-like arrangement.\n", - "\n", - "The `subplots()` function in the matplotlib library is used to create subplots. It allows you to specify the number of rows and columns in the subplot grid, which determines the overall layout of the subplots.\n", - "\n", - "Here's an example to help you understand subplots. We will use the dataset of a sample of 100 vehicles corresponding to the 3-axle vehicle type _3C_ (remember the Maximum bending moment on a simply supported bridge example on `numpy` section?)\n", - "\n", - "First we will read the data set using `pandas`" - ] - }, - { - "cell_type": "code", - "execution_count": 60, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
A1_kNA2_kNA3_kND1_mD2_m
042.177.565.35.11.4
148.780.150.25.41.2
251.790.261.65.21.2
341.275.758.65.41.2
425.048.433.55.61.2
\n", - "
" - ], - "text/plain": [ - " A1_kN A2_kN A3_kN D1_m D2_m\n", - "0 42.1 77.5 65.3 5.1 1.4\n", - "1 48.7 80.1 50.2 5.4 1.2\n", - "2 51.7 90.2 61.6 5.2 1.2\n", - "3 41.2 75.7 58.6 5.4 1.2\n", - "4 25.0 48.4 33.5 5.6 1.2" - ] - }, - "execution_count": 60, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dataset = pd.read_csv(\"https://raw.githubusercontent.com/\"\n", - " \"mike-mendoza/Bivariate_NPBN_workshop_files/\"\n", - " \"a991bc3d9391a92437af1c3d69ae9fdfe6baf6da/\"\n", - " \"files_pyhton_book_test/V3AX_WIM_BR.csv\")\n", - "dataset.head()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's create one figure with one histogram per colum in the dataset using `for` loop." - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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cR1vH8unT59K+2Nubi78/PzElStXsr2Osl6Lhw4dEiNHjhQVKlQQ5ubmYuDAgeLx48dq2/Dx8RE+Pj5qbZmZmeKrr74Snp6eQqlUigoVKggvLy8RHBwsHfeIiAjRvXt34eTkJIyNjYWTk5MYMGCAuHr1ar7HLrd6385OZGSkACAiIyPzXF9umYiNjRUAxNdff51tmbePrRBC3LhxQwwZMkQ4ODgIIyMjUblyZdG1a1exefPmfPfp8ePHYvDgwcLS0lJYWVmJwYMHi7NnzwoAaq+5guZGCCHmzJkjKleuLMqVKycAiNjYWCGEEDt27BD169cXJiYmwtXVVXz11Vfi559/Vpvn77//FgMGDBBVq1YVSqVS2NnZia5du4ro6Ohsta9cuVJ4eXkJU1NTYWFhIerVqyemTp0q7t+/L82TkJAgunTpIiwsLASAbK8ZIiIiOVIIUcQrVxIREZFWnDt3Do0aNcKvv/6KgQMH6rscIiIiIqJixWtKERER6cGzZ8+ytS1evBjlypVDmzZt9FAREREREZFu8ZpSREREerBgwQKcOXMG7dq1g6GhIfbs2YM9e/Zg5MiRcHZ21nd5RERERETFjqfvERER6cGBAwcQHByMy5cvIy0tDVWrVsXgwYPx+eefw9CQfzMiIiIiotKPnVJERERERERERKRzvKYUERERERERERHpHDuliIiIiIiIiIhI59gpRUREREREREREOsdOKSIiIiIiIiIi0jl2ShERERERERERkc6xU4qIiIiIiIiIiHSOnVJERERERERERKRz7JQiIiIiIiIiIiKdY6cUERERERERERHpHDuliIiIiIiIiIhI59gpRUREREREREREOsdOKSIiIiIiIiIi0jl2ShERERERERERkc6xU4qIiIiIiIiIiHSOnVJERERERERERKRz7JQiIiIiIiIiIiKdY6cUERERERERERHpHDuliIiIiIiIiIhI59gpRUREREREREREOsdOKSIiIiIiIiIi0jl2ShERERERERERkc6xU4qIiIiIiIiIiHSOnVJERERERERERKRz7JSiXMXFxUGhUCA8PFzfpRBRITC7RPLE7BLp3qxZs6BQKPSyHVdXVwQEBBT7tolKI2a39GCnVCm0bNkyKBQKNGvWTN+lZLNhwwYMGjQIHh4eUCgUaNu2rb5LIioxSmp2Hz9+jK+//hpt2rSB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iIiIiIgKwNHREXXq1FFrq127Nm7fvg0AcHBwAAAkJiaqzZOYmChNe9v06dORnJwsPe7cuVMMlRPpll47pdLT09GgQQMsXbo013k6duyI+Ph46fHbb7/psEIiIiIiIiKiwmnZsiViYmLU2q5evQoXFxcAgJubGxwcHBARESFNT0lJwalTp+Dt7Z3jOpVKpXSqHk/Zo9JCr6fvderUCZ06dcpzHqVSmWtPMREREREREVFJM3HiRLRo0QLz5s1D37598ddff2HlypVYuXIlgNfX3ZkwYQLmzp0LDw8PuLm5YcaMGXByckKPHj30WzyRDpX4a0pFRUXBzs4OFSpUQPv27TF37lxUrFgx1/nfvvhbSkqKLsokIiIiIiIiAgA0adIEW7duxfTp0zF79my4ublh8eLFGDhwoDTP1KlTkZ6ejpEjRyIpKQmtWrXC3r17YWJiosfKiXSrRHdKdezYEb169YKbmxtu3LiBzz77DJ06dcKJEydgYGCQ4zJl4eJvrtN2abxs3PwustsuEcmTpu8ZfL8gKhr+viZ6jVkgfevatSu6du2a63SFQoHZs2dj9uzZxVYDc0AlXYnulOrfv7/0/3r16qF+/fqoXr06oqKi0KFDhxyXmT59OiZNmiQ9T0lJgbOzc7HXSkREREREREREBafXC50XVrVq1VCpUiVcv34913l48TciIiIiIiIiopJPVp1Sd+/exePHj+Ho6KjvUoiIiIiIiIiIqAj0evpeWlqa2qin2NhYnDt3DjY2NrCxsUFwcDB69+4NBwcH3LhxA1OnToW7uzv8/Pz0WDURERERERERERWVXjuloqOj0a5dO+l51rWg/P39ERoaigsXLmD16tVISkqCk5MT3nvvPcyZMwdKpVJfJRMRERERERERkRbo9fS9tm3bQgiR7REeHg5TU1Ps27cPDx48QGZmJuLi4rBy5UrY29vrs2QiIiIiIp0JDQ1F/fr1pWulent7Y8+ePdL058+fIzAwEBUrVoS5uTl69+6NxMREPVZMRERUcLK6phQRERERUVlSpUoVzJ8/H2fOnEF0dDTat2+P7t2749KlSwCAiRMn4o8//sCmTZtw6NAh3L9/H7169dJz1URERAWj19P3iIiIiIgod926dVN7/uWXXyI0NBQnT55ElSpV8NNPP2HdunVo3749ACAsLAy1a9fGyZMn0bx5c32UTEREVGAcKUVEREREJAOvXr3C+vXrkZ6eDm9vb5w5cwYvXryAr6+vNE+tWrVQtWpVnDhxQo+VEhERFQxHShEREREVE9dpuzReNm5+Fy1WQnJ28eJFeHt74/nz5zA3N8fWrVtRp04dnDt3DsbGxrC2tlab397eHgkJCXmuMyMjAxkZGdLzlJSU4iidiIgoT+yUolJN0y8D/CJAREREJUXNmjVx7tw5JCcnY/PmzfD398ehQ4eKtM6QkBAEBwdrqUIiIiLN8PQ9IiIiIqISzNjYGO7u7vDy8kJISAgaNGiA7777Dg4ODsjMzERSUpLa/ImJiXBwcMhzndOnT0dycrL0uHPnTjHuARERUc7YKUVEREREJCMqlQoZGRnw8vKCkZERIiIipGkxMTG4ffs2vL2981yHUqmEpaWl2oOIiEjXePoeEREREVEJNX36dHTq1AlVq1ZFamoq1q1bh6ioKOzbtw9WVlYYPnw4Jk2aBBsbG1haWmLs2LHw9vbmnfeIiEgWOFKKiIiojDh8+DC6desGJycnKBQKbNu2TW16QEAAFAqF2qNjx476KZaIAAAPHjzAkCFDULNmTXTo0AGnT5/Gvn378O677wIAFi1ahK5du6J3795o06YNHBwcsGXLFj1XTUREVDAcKUVERFRGpKeno0GDBhg2bBh69eqV4zwdO3ZEWFiY9FypVOqqPCLKwU8//ZTndBMTEyxduhRLly7VUUVERETaw04pIiKiMqJTp07o1KlTnvMolcp8L5BMRERERKQNPH2PiIiIJFFRUbCzs0PNmjUxatQoPH78WN8lEREREVEpxZFSREREBOD1qXu9evWCm5sbbty4gc8++wydOnXCiRMnYGBgkOMyGRkZyMjIkJ6npKToqlwiIiIikjl2ShEREREAoH///tL/69Wrh/r166N69eqIiopChw4dclwmJCQEwcHBuiqRiIiIiEoRnr5HREREOapWrRoqVaqE69ev5zrP9OnTkZycLD3u3LmjwwqJiIiISM7K/Egp12m7NF42bn4XLVZCRERUsty9exePHz+Go6NjrvMolUreoY+IiIiINMKRUkRUaIcPH0a3bt3g5OQEhUKBbdu2qU0PCAiAQqFQe3Ts2FE/xRKRJC0tDefOncO5c+cAALGxsTh37hxu376NtLQ0TJkyBSdPnkRcXBwiIiLQvXt3uLu7w8/PT7+FExEREVGpxE4pIiq09PR0NGjQAEuXLs11no4dOyI+Pl56/PbbbzqskIhyEh0djUaNGqFRo0YAgEmTJqFRo0aYOXMmDAwMcOHCBbz//vuoUaMGhg8fDi8vLxw5coQjoYiIiIioWJT50/eIqPA6deqETp065TmPUqmEg4ODjioiooJo27YthBC5Tt+3b58OqyEiIiKiso4jpYioWERFRcHOzg41a9bEqFGj8PjxY32XRERERERERCUIR0oRkdZ17NgRvXr1gpubG27cuIHPPvsMnTp1wokTJ2BgYJDjMhkZGcjIyJCep6Sk6KpcIiIiIiIi0gN2ShGR1vXv31/6f7169VC/fn1Ur14dUVFR6NChQ47LhISEIDg4WFclEhERERERkZ7x9D0iKnbVqlVDpUqVcP369VznmT59OpKTk6XHnTt3dFghERERERER6RpHShFRsbt79y4eP34MR0fHXOdRKpW8wxcREREREVEZwk4pIiq0tLQ0tVFPsbGxOHfuHGxsbGBjY4Pg4GD07t0bDg4OuHHjBqZOnQp3d3f4+fnpsWoiIiIiIiIqSdgpRUSFFh0djXbt2knPJ02aBADw9/dHaGgoLly4gNWrVyMpKQlOTk547733MGfOHI6EIiIiIiIiIgk7pUgnXKft0njZuPldtFgJaUPbtm0hhMh1+r59+3RYDREREREREckRL3ROREREREREREQ6x04pIiIiIiIiIiLSOXZKERERERERERGRzvGaUkREOiLHa6sVpWYiIiIiIqK8cKQUERERERERERHpHEdKEREREZVAHKlIREREpR1HShERERERERERkc6xU4qIiIiIiIiIiHSOnVJERERERERERKRz7JQiIiIiIiIiIiKd44XOqcTjhV6JiIiIiIiISh+NRkrdvHlT23UQkQ4wu0TyxOwSyROzSyRPzC6R7mjUKeXu7o527drh119/xfPnz7VdExEVE2aXSJ6YXSJ5YnaJ5InZJdIdjTql/v77b9SvXx+TJk2Cg4MDPv74Y/z111/aro2ItIzZJZInZpdInphdInkqjuzOnz8fCoUCEyZMkNqeP3+OwMBAVKxYEebm5ujduzcSExOLWD2RvGjUKdWwYUN89913uH//Pn7++WfEx8ejVatWqFu3LhYuXIiHDx9qu04i0gJml0iemF0ieWJ2ieRJ29k9ffo0VqxYgfr166u1T5w4EX/88Qc2bdqEQ4cO4f79++jVq5c2d4WoxCvS3fcMDQ3Rq1cvbNq0CV999RWuX7+OyZMnw9nZGUOGDEF8fLy26iQiLWJ2ieSJ2aXi5jptl8YPyh2zSyRP2shuWloaBg4ciFWrVqFChQpSe3JyMn766ScsXLgQ7du3h5eXF8LCwnD8+HGcPHmyOHeLqEQpUqdUdHQ0Ro8eDUdHRyxcuBCTJ0/GjRs3cODAAdy/fx/du3fPc/nDhw+jW7ducHJygkKhwLZt29SmCyEwc+ZMODo6wtTUFL6+vrh27VpRSiYiFD27RKQfzC6RPDG7RPKkjewGBgaiS5cu8PX1VWs/c+YMXrx4odZeq1YtVK1aFSdOnMhxXRkZGUhJSVF7EMmdoSYLLVy4EGFhYYiJiUHnzp3xyy+/oHPnzihX7nUfl5ubG8LDw+Hq6prnetLT09GgQQMMGzYsx2GKCxYswPfff4/Vq1fDzc0NM2bMgJ+fHy5fvgwTExNNSicq07SVXSLSLWaXSJ6YXSJ50lZ2169fj7///hunT5/ONi0hIQHGxsawtrZWa7e3t0dCQkKO6wsJCUFwcLBG+0RUUmnUKRUaGophw4YhICAAjo6OOc5jZ2eHn376Kc/1dOrUCZ06dcpxmhACixcvxhdffCH1QP/yyy+wt7fHtm3b0L9/f01KJyrTtJVdItItZpdInphdInnSRnbv3LmD8ePH48CBA1obUDF9+nRMmjRJep6SkgJnZ2etrJtIXzTqlCrIKXTGxsbw9/fXZPUAgNjYWCQkJKgNZ7SyskKzZs1w4sQJdkoRaUAX2SUi7WN2ieSJ2SWSJ21k98yZM3jw4AHeeecdqe3Vq1c4fPgwfvjhB+zbtw+ZmZlISkpSGy2VmJgIBweHHNepVCqhVCoLviNEMqDRNaXCwsKwadOmbO2bNm3C6tWri1wUAGnIor29vVp7XsMZAZ5nS5QXXWSXiLSP2SWSJ2aXSJ60kd0OHTrg4sWLOHfunPRo3LgxBg4cKP3fyMgIERER0jIxMTG4ffs2vL29tbYvRCWdRiOlQkJCsGLFimztdnZ2GDlypF7/2sPzbIlyV5KzW1hFudNT3PwuWqxEN8ra/pK60pRdorKE2SWSJ21k18LCAnXr1lVrMzMzQ8WKFaX24cOHY9KkSbCxsYGlpSXGjh0Lb29vNG/eXDs7QiQDGo2Uun37Ntzc3LK1u7i44Pbt20UuCoA0ZDExMVGtPa/hjMDr82yTk5Olx507d7RSD1FpoIvsEpH2MbtE8sTsEsmTrrK7aNEidO3aFb1790abNm3g4OCALVu2aG39RHKg0UgpOzs7XLhwIdvdBs6fP4+KFStqoy64ubnBwcEBERERaNiwIYDXF3I7deoURo0aletyPM+WKHe6yC4RaR+zSyRP2shuSEgItmzZgitXrsDU1BQtWrTAV199hZo1a0rzPH/+HJ9++inWr1+PjIwM+Pn5YdmyZdkug1EUHLFLZUlx/d6NiopSe25iYoKlS5di6dKlGq+TSO406pQaMGAAxo0bBwsLC7Rp0wYAcOjQIYwfP75QFyBPS0vD9evXpeexsbE4d+4cbGxsULVqVUyYMAFz586Fh4cH3NzcMGPGDDg5OaFHjx6alE1U5mkru0SkW8zua/r6UlyU7VLZpo3sHjp0CIGBgWjSpAlevnyJzz77DO+99x4uX74MMzMzAMDEiROxa9cubNq0CVZWVhgzZgx69eqFY8eOFdu+EZVm/L1LpDsadUrNmTMHcXFx6NChAwwNX69CpVJhyJAhmDdvXoHXEx0djXbt2knPs25v6e/vj/DwcEydOhXp6ekYOXIkkpKS0KpVK+zdu1drt9QkKmu0lV0i0i1ml0ietJHdvXv3qj0PDw+HnZ0dzpw5gzZt2iA5ORk//fQT1q1bh/bt2wN4fZHm2rVr4+TJk7w2DZEG+HuXSHc06pQyNjbGhg0bMGfOHJw/fx6mpqaoV68eXFxcCrWetm3bQgiR63SFQoHZs2dj9uzZmpRJRG/RVnaJSLeYXSJ5Ko7sJicnAwBsbGwAvL7t/IsXL+Dr6yvNU6tWLVStWhUnTpxgpxSRBvh7l0h3NOqUylKjRg3UqFFDW7UQkY4wu0TyxOwSyZO2sqtSqTBhwgS0bNlSuntXQkICjI2NYW1trTavvb09EhIScl1XRkYGMjIypOcpKSlFro+otOHvXaLip1Gn1KtXrxAeHo6IiAg8ePAAKpVKbfrBgwe1UhwRaRezSyRPzC6RPGk7u4GBgfjnn39w9OjRItcWEhKC4ODgIq+HqDTi710i3dGoU2r8+PEIDw9Hly5dULduXSgUCm3XRUTFgNklkidtZffw4cP4+uuvcebMGcTHx2Pr1q1qNw8RQiAoKAirVq1CUlISWrZsidDQUHh4eGhpT4jKFm3+3h0zZgx27tyJw4cPo0qVKlK7g4MDMjMzkZSUpDZaKjExEQ4ODrmub/r06dL1XIHXI6WcnZ01ro+oNOFnZiLd0ahTav369di4cSM6d+6s7XqIqBgxu0TypK3spqeno0GDBhg2bBh69eqVbfqCBQvw/fffY/Xq1dJdb/38/HD58mXeZIRIA9rIrhACY8eOxdatWxEVFQU3Nze16V5eXjAyMkJERAR69+4NAIiJicHt27fh7e2d63qVSiWUSqXGdRGVZvzMTKQ7Gl/o3N3dXdu1EFExY3aJ5Elb2e3UqRM6deqU4zQhBBYvXowvvvgC3bt3BwD88ssvsLe3x7Zt23gLbCINaCO7gYGBWLduHbZv3w4LCwvpOlFWVlYwNTWFlZUVhg8fjkmTJsHGxgaWlpYYO3YsvL29eZFzIg3xMzOR7pTTZKFPP/0U3333XZ53ziOikofZJZInXWQ3NjYWCQkJanfwsrKyQrNmzXDixIli2y5RaaaN7IaGhiI5ORlt27aFo6Oj9NiwYYM0z6JFi9C1a1f07t0bbdq0gYODA7Zs2aKNXSAqk/iZmUh3NBopdfToUURGRmLPnj3w9PSEkZGR2nT+EiQqmZhdInnSRXazRl/Y29urtfMOXkSa00Z2C/Kl2MTEBEuXLsXSpUs1rpWI/g8/MxPpjkadUtbW1ujZs6e2ayGiYsbsEslTSc5uYe/g5TptVzFWQ1SylOTsElHumF0i3dGoUyosLEzbdRCRDmgru7yDF5Fu6eL3btZduhITE+Ho6Ci1JyYmomHDhrkuxzt4EeWOn5mJ5InZJdIdja4pBQAvX77En3/+iRUrViA1NRUAcP/+faSlpWmtOCLSPm1kN+sOXrmdJpB1B6/ly5fj1KlTMDMzg5+fH54/f66VfSAqi4r7966bmxscHBwQEREhtaWkpODUqVP53sHL0tJS7UFE/4efmYnkidkl0g2NRkrdunULHTt2xO3bt5GRkYF3330XFhYW+Oqrr5CRkYHly5dru04i0gJtZZd38CLSLW1lNy0tDdevX5eex8bG4ty5c7CxsUHVqlUxYcIEzJ07Fx4eHnBzc8OMGTPg5OSkNhKSiAqOn5mJ5InZJdIdjUZKjR8/Ho0bN8bTp09hamoqtffs2VPtL6xEVLLoIrua3sErIyMDKSkpag8iek1b2Y2OjkajRo3QqFEjAMCkSZPQqFEjzJw5EwAwdepUjB07FiNHjkSTJk2QlpaGvXv3wsTERLs7RFRG8DMzkTwxu0S6o9FIqSNHjuD48eMwNjZWa3d1dcW9e/e0UhgRaZ8usqvpHbwKe7FkorJEW9lt27ZtnnfyUigUmD17NmbPnq1xrUT0f/iZmUiemF0i3dFopJRKpcKrV6+ytd+9excWFhZFLoqIikdJzu706dORnJwsPe7cuaPXeohKkpKcXSLKHbNLJE/MLpHuaNQp9d5772Hx4sXSc4VCgbS0NAQFBaFz587aqo2ItEwX2X3zDl5vSkxMlKblhBdLJsodf+8SyROzSyRPzC6R7mh0+t63334LPz8/1KlTB8+fP8eHH36Ia9euoVKlSvjtt9+0XSMRaYkusvvmHbyybiOfdQevUaNGaWUbRGUNf+8SyROzSyRPzC6R7mjUKVWlShWcP38e69evx4ULF5CWlobhw4dj4MCBaheCK+1cp+3SeNm4+V20WAlRwWgru7yDF5Fu8fcukTwxu0TyxOwS6Y5GnVIAYGhoiEGDBmmzFiLSAW1kNzo6Gu3atZOeT5o0CQDg7++P8PBwTJ06Fenp6Rg5ciSSkpLQqlUr3sGLqIj4e5dInphdInlidol0Q6NOqV9++SXP6UOGDNGoGCIqXtrKLu/gRaRb/L1LJE/MLpE8MbtEuqNRp9T48ePVnr948QL//fcfjI2NUb58eYaUqIRidonkidklkidml0iemF0i3dHo7ntPnz5Ve6SlpSEmJgatWrXihd+ISjBml0iemF0ieWJ2ieSJ2SXSHY2vKfU2Dw8PzJ8/H4MGDcKVK1e0tVoiKmbMbulXlJsyUMnF7BLJE7MrD5r+7uTNjEovZpeoeGg0Uio3hoaGuH//vjZXSUQ6wOwSyROzSyRPzC6RPDG7RNqn0UipHTt2qD0XQiA+Ph4//PADWrZsqZXCiEj7mF0ieWJ2ieSJ2SWSJ2aXSHc06pTq0aOH2nOFQgFbW1u0b98e3377rTbqIqJiwOwSyROzSyRPzC6RPDG7RLqjUaeUSqXSdh1EpAPMLpE8MbtE8sTsEskTs0ukO1q9phQREREREREREVFBaDRSatKkSQWed+HChZpsgooJ78JVtjG7RPLE7BLJE7NLJE/MLpHuaNQpdfbsWZw9exYvXrxAzZo1AQBXr16FgYEB3nnnHWk+hUKhnSqJSCuYXSJ5YnaJ5InZJZInZpdIdzTqlOrWrRssLCywevVqVKhQAQDw9OlTDB06FK1bt8ann36q1SKJSDuYXSJ5YnaJ5InZJZInZpdIdzS6ptS3336LkJAQKaAAUKFCBcydO5d3IyAqwZhdInlidonkidklkidml0h3NOqUSklJwcOHD7O1P3z4EKmpqUUuioiKB7NLJE/MLpE8MbtE8sTsEumORp1SPXv2xNChQ7FlyxbcvXsXd+/exe+//47hw4ejV69e2q6RiLSE2SWSJ2aXSJ6YXSJ5YnaJdEeja0otX74ckydPxocffogXL168XpGhIYYPH46vv/5aqwUSkfYwu0TyxOwSyROzSyRPzC6R7mjUKVW+fHksW7YMX3/9NW7cuAEAqF69OszMzLRaHBFpF7NLJE/MLpE8MbtE8sTsEumORqfvZYmPj0d8fDw8PDxgZmYGIYS26iKiYsTsEskTs0skT8wukTwxu0TFT6ORUo8fP0bfvn0RGRkJhUKBa9euoVq1ahg+fDgqVKjAOxIQlVDMLpE8MbtF5zptl75LoDKI2SWSJ2aXSHc0Gik1ceJEGBkZ4fbt2yhfvrzU3q9fP+zdu1drxRGRdjG7RPLE7BLJE7NLJE/MLpHuaDRSav/+/di3bx+qVKmi1u7h4YFbt25ppTAi0j5ml0iemF0ieWJ2ieSJ2S17ijKiOm5+Fy1WUvZo1CmVnp6u1mOc5cmTJ1AqlUUuioiKB7P7Gn/pkNwwu0TyxOwSyROzS6Q7Gp2+17p1a/zyyy/Sc4VCAZVKhQULFqBdu3ZaK46ItIvZJZInZpdInphdInlidol0R6ORUgsWLECHDh0QHR2NzMxMTJ06FZcuXcKTJ09w7NgxbddIRFrC7BLJE7NLJE/MLpE8MbtEuqPRSKm6devi6tWraNWqFbp374709HT06tULZ8+eRfXq1bVdIxFpCbNLJE/MLpE8MbtE8qSN7IaEhKBJkyawsLCAnZ0devTogZiYGLV5nj9/jsDAQFSsWBHm5ubo3bs3EhMTi2OXiEqsQo+UevHiBTp27Ijly5fj888/L46aiKgYMLtE8sTsEskTs0skT9rK7qFDhxAYGIgmTZrg5cuX+Oyzz/Dee+/h8uXLMDMzA/D6Ln+7du3Cpk2bYGVlhTFjxqBXr14cjUVlSqE7pYyMjHDhwoXiqCWbWbNmITg4WK2tZs2auHLlik62T1Sa6DK7RKQ9zC6RPDG7RPKkrezu3btX7Xl4eDjs7Oxw5swZtGnTBsnJyfjpp5+wbt06tG/fHgAQFhaG2rVr4+TJk2jevHmRayCSA41O3xs0aBB++uknbdeSI09PT8THx0uPo0eP6mS7RKWRLrNLRNrD7BLJE7NLJE/Fkd3k5GQAgI2NDQDgzJkzePHiBXx9faV5atWqhapVq+LEiRM5riMjIwMpKSlqDyK50+hC5y9fvsTPP/+MP//8E15eXtLwwywLFy7USnEAYGhoCAcHB62tj6gs02V2iUh7mF0ieWJ2ieRJ29lVqVSYMGECWrZsibp16wIAEhISYGxsDGtra7V57e3tkZCQkON6QkJCsp1JRCR3heqUunnzJlxdXfHPP//gnXfeAQBcvXpVbR6FQqG96gBcu3YNTk5OMDExgbe3N0JCQlC1atVc58/IyEBGRob0nL3HRPrJLhEVHbNLJE/azu7hw4fx9ddf48yZM4iPj8fWrVvRo0cPaboQAkFBQVi1ahWSkpLQsmVLhIaGwsPDQyv7Q1RWFNfv3cDAQPzzzz9FPutn+vTpmDRpkvQ8JSUFzs7ORVonkb4VqlPKw8MD8fHxiIyMBAD069cP33//Pezt7YuluGbNmiE8PBw1a9ZEfHw8goOD0bp1a/zzzz+wsLDIcRn2HhNlp+vslmau03bpuwQqQ5hdInnSdnbT09PRoEEDDBs2DL169co2fcGCBfj++++xevVquLm5YcaMGfDz88Ply5dhYmJSpH0hKkuK4/fumDFjsHPnThw+fBhVqlSR2h0cHJCZmYmkpCS10VKJiYm5nimkVCqhVCo1roWoJCpUp5QQQu35nj17kJ6ertWC3tSpUyfp//Xr10ezZs3g4uKCjRs3Yvjw4Tkuw95joux0nV0i0g5ml0ietJ3dTp06qX0ufntbixcvxhdffIHu3bsDAH755RfY29tj27Zt6N+/v8bbJSprtJldIQTGjh2LrVu3IioqCm5ubmrTvby8YGRkhIiICPTu3RsAEBMTg9u3b8Pb21uzHSAqoKL8oT1ufhctVqLhhc6zvB3a4mZtbY0aNWrg+vXruc6jVCphaWmp9iAidbrOLhFpR3Fnd9asWVAoFGqPWrVqFes2icqC4sxubGwsEhIS1C6WbGVlhWbNmuV6sWQiKpiiZDcwMBC//vor1q1bBwsLCyQkJCAhIQHPnj0D8Dqnw4cPx6RJkxAZGYkzZ85g6NCh8Pb25p33qEwp1EiprA+ob7fpSlpaGm7cuIHBgwfrbJtEpYG+s0tEmtFHdj09PfHnn39Kzw0NNbonClGZpsvsZl0Q+e3Ti/K6WDLA67AS5USb2Q0NDQUAtG3bVq09LCwMAQEBAIBFixahXLly6N27NzIyMuDn54dly5ZptD0iuSr06XsBAQHSeazPnz/HJ598ku1uBFu2bNFKcZMnT0a3bt3g4uKC+/fvIygoCAYGBhgwYIBW1k9UVug6u0SkHfrILu96S1R0cvi9y+uwEmWnzewWZJSViYkJli5diqVLl2pWMFEpUKhOKX9/f7XngwYN0moxb7t79y4GDBiAx48fw9bWFq1atcLJkydha2tbrNslKm10nd1Zs2Zl+6Bbs2ZNXLlypVi3S1Ta6Dq7QOHvektE2ekyu1mdyImJiXB0dJTaExMT0bBhw1yX43VYibLTx+9dorKuUJ1SYWFhxVVHjtavX6/T7RGVVrrOLsBTgIi0QdfZ1eSutzwFiCg7XWbXzc0NDg4OiIiIkDqhUlJScOrUKYwaNSrX5XgXL6Ls9PGZmais47dEIioWPAWISH40uestTwEiKn5paWlqN/qJjY3FuXPnYGNjg6pVq2LChAmYO3cuPDw84ObmhhkzZsDJyQk9evTQX9FEREQFUKS77xER5SbrFKBq1aph4MCBuH37dp7zZ2RkICUlRe1BRPpVkLveTp8+HcnJydLjzp07OqyQqGyIjo5Go0aN0KhRIwDApEmT0KhRI8ycORMAMHXqVIwdOxYjR45EkyZNkJaWhr1798LExESfZRMREeWLI6WISOs0OQWIoy0oi+u0XRovGze/ixYroYLc9ZanABEVv7Zt2+Z50WSFQoHZs2dj9uzZOqyKcsLfYUREhcORUkSkdZ06dcIHH3yA+vXrw8/PD7t370ZSUhI2btyY6zIcbUGkf5MnT8ahQ4cQFxeH48ePo2fPnrzrLREREREVG46UIqJiV5BTgDjagkj/eNdbIiIiItIldkoRUbEryClARKR/vOstEREREekST98jIq3jKUBERERERESUH46UIiKt4ylARERERIXDi6QTUVnETiki0jqeAkRERERERET54el7RERERERERESkc+yUIiIiIiIiIiIinWOnFBERERERERER6Rw7pYiIiIiIiIiISOfYKUVERERERERERDrHTikiIiIiIiIiItI5Q30XQFQSuU7bpfGycfO7aLESIiIiIiIiotKJI6WIiIiIiIiIiEjn2ClFREREREREREQ6x04pIiIiIiIiIiLSOXZKERERERERERGRzrFTioiIiIiIiIiIdI533yMiolKDd84kIiIiIpIPdkoRERERERHJGP8oQ0RyxdP3iIiIiIiIiIhI59gpRUREREREREREOsdOKSIiIiIiIiIi0jleU0pPinLeNxERERERERGR3HGkFBERERERERER6Rw7pYiIiIiIiIiISOd4+h4RERER6RVvZ09ERFQ2caQUERERERERERHpHDuliIiIiIiIiIhI53j6HhERERERFRuenll68WdLREXFkVJERERERERERKRz7JQiIiIiIiIiIiKdY6cUERERERERERHpHDuliIiIiIiIiIhI59gpRUREREREREREOse77xERERFRkRXlLlxEueHrioiodONIKSIiIiIiIiIi0jl2ShERERERERERkc6xU4qIiIiIiIiIiHSOnVJERERERERERKRzsrjQ+dKlS/H1118jISEBDRo0wJIlS9C0aVN9l0VE+WB2ieSJ2SWSJ2aXNMGLyesfs0tlWYkfKbVhwwZMmjQJQUFB+Pvvv9GgQQP4+fnhwYMH+i6NiPLA7BLJE7NLJE/MLpE8MbtU1pX4TqmFCxfio48+wtChQ1GnTh0sX74c5cuXx88//6zv0ogoD8wukTwxu0TyxOwSyROzS2Vdie6UyszMxJkzZ+Dr6yu1lStXDr6+vjhx4oQeKyOivDC7RPLE7BLJE7NLJE/MLlEJv6bUo0eP8OrVK9jb26u129vb48qVKzkuk5GRgYyMDOl5cnIyACAlJSXH+VUZ/2mpWqLXcnutvTlNCKGrcvSC2SU5YnaZXZInZpfZJXnK7bVWVnILFD67hc0tULTs5rXe0qasHafi2F9Ns1uiO6U0ERISguDg4Gztzs7OeqiGyiKrxfnPk5qaCisrq2KvRU6YXdI3ZlczzC7pG7OrGWaX9C2/7DK32ek6twV5f6Wyd5y0nd0S3SlVqVIlGBgYIDExUa09MTERDg4OOS4zffp0TJo0SXquUqnw5MkTVKxYEQqFItv8KSkpcHZ2xp07d2BpaandHdAz7lvJI4RAamoqnJyc9F1KsdJF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6tWrh/nz50t1+vn5YefOndi/fz+aNGmC5s2bY9GiRXBxcSnCESIqmZhdyo9CCCH0XQTp10cffYQrV67gyJEjWl+3q6srJkyYgAkTJmh93Vni4uLg5uaGs2fPomHDhsW2HaKShtklkh/mlog0ERAQgKSkJGzbtk1r69TFewZRWcfs5o8jpcqgb775BufPn8f169exZMkSrF69OsfTDrTlf//7H8zNzZGcnKz1dXfq1Amenp5aXy9RScTsEskPc0tE2rJz506Ym5tj586dRVrPvHnzYG5urvGoSyIqHGY3bxwpVQb17dsXUVFRSE1NRbVq1TB27Fh88sknxbKtW7du4cWLFwCAatWqFfoaGPm5d+8enj17BgCoWrUqjI2Ntbp+opKE2SWSH+aWiLThwYMHSElJAQA4OjrCzMxM43U9efIET548AQDY2trCyspKKzUSUXbMbv7YKUVERERERERERDrH0/eIiIiIiIiIiEjn2ClFREREREREREQ6x04pIiIiIiIiIiLSOXZKERERERERERGRzrFTioiIiIiIiIiIdI6dUkREREREREREpHPslCIiIiIiIiIiIp1jpxQREREREREREekcO6WIiIiIiIiIiEjn/h/jOBxoVLkrMAAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "variable_names = ['Axle 1', 'Axle 2', 'Axle 3',\n", - " 'Inter-axle distance 1', 'Inter-axle distance 2']\n", - "\n", - "xlabels =['Weight [kN]', 'Weight [kN]', 'Weight [kN]',\n", - " 'Distance [m]', 'Distance [m]']\n", - "\n", - "fig, axes = plt.subplots(nrows=1, ncols=5, figsize=(12,3))\n", - "for i,column in enumerate(dataset.columns):\n", - " axes[i].hist(dataset[column])\n", - " axes[i].set_xlabel(xlabels[i])\n", - " axes[i].set_ylabel('Frequency')\n", - " axes[i].set_title(variable_names[i])\n", - "plt.suptitle('Histograms of variables in the dataset') \n", - "plt.tight_layout()\n", - "plt.show()\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`````{admonition} Let's break it down\n", - "1. `variable_names` is a list containing the names of different variables in a dataset.\n", - "2. `xlabels` is a list containing the x-axis labels for each histogram.\n", - "3. The code creates a figure with 1 row and 5 columns of subplots using `plt.subplots(nrows=1, ncols=5, figsize=(12, 3))`.\n", - "4. `for i, column in enumerate(dataset.columns)` initiates a loop that iterates over the columns of the dataset. It uses the `enumerate()` function to retrieve both the index (`i`) and the column name (`column`) at each iteration.\n", - "5. It then loops over the columns of the dataset and creates a histogram for each column using `axes[i].hist(dataset[column])`.\n", - "6. The x-axis label, y-axis label, and title of each subplot are set using `axes[i].set_xlabel(xlabels[i])`, `axes[i].set_ylabel('Frequency')`, and `axes[i].set_title(variable_names[i])`, respectively.\n", - "7. The super title for the entire figure is set using `plt.suptitle('Histograms of variables in the dataset')`.\n", - "8. `plt.tight_layout()` adjusts the spacing between subplots.\n", - "9. Finally, `plt.show()` displays the figure with all the subplots.\n", - "`````\n", - "\n" - ] - } - ], - "metadata": { - "hide_input": false, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.13" - }, - "latex_envs": { - "LaTeX_envs_menu_present": true, - "autoclose": false, - "autocomplete": true, - "bibliofile": "biblio.bib", - "cite_by": "apalike", - "current_citInitial": 1, - "eqLabelWithNumbers": true, - "eqNumInitial": 1, - "hotkeys": { - "equation": "Ctrl-E", - "itemize": "Ctrl-I" - }, - "labels_anchors": false, - "latex_user_defs": false, - "report_style_numbering": false, - "user_envs_cfg": false - }, - "varInspector": { - "cols": { - "lenName": 16, - "lenType": 16, - "lenVar": 40 - }, - "kernels_config": { - "python": { - "delete_cmd_postfix": "", - "delete_cmd_prefix": "del ", - "library": "var_list.py", - "varRefreshCmd": "print(var_dic_list())" - }, - "r": { - "delete_cmd_postfix": ") ", - "delete_cmd_prefix": "rm(", - "library": "var_list.r", - "varRefreshCmd": "cat(var_dic_list()) " - } - }, - "types_to_exclude": [ - "module", - "function", - "builtin_function_or_method", - "instance", - "_Feature" - ], - "window_display": false - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/book/08/sympy.ipynb b/book/08/sympy.ipynb deleted file mode 100644 index f1478f8..0000000 --- a/book/08/sympy.ipynb +++ /dev/null @@ -1,1543 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "tags": [ - "thebe-remove-input-init" - ] - }, - "outputs": [], - "source": [ - "import sympy as sym\n", - "import numpy as np\n", - "from sympy import pi, latex\n", - "from sympy.printing.mathml import mathml\n", - "\n", - "import operator\n", - "import ipywidgets as widgets\n", - "from IPython.display import display, Latex, display_jpeg, Math, Markdown\n", - "sym.init_printing(use_latex=True) \n", - "\n", - "check_equation = lambda eq1, eq2: sym.simplify(eq1-eq2) == 0\n", - "\n", - "def check_answer(variable_name, expected, comparison = operator.eq):\n", - " output = widgets.Output()\n", - " button = widgets.Button(description=\"Check answer\")\n", - " def _inner_check(button):\n", - " with output:\n", - " if comparison(globals()[variable_name], expected):\n", - " output.outputs = [{'name': 'stdout', 'text': 'Correct!',\n", - " 'output_type': 'stream'}]\n", - " else:\n", - " output.outputs = [{'name': 'stdout', 'text': 'Incorrect!',\n", - " 'output_type': 'stream'}]\n", - " button.on_click(_inner_check)\n", - " display(button, output)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# SymPy\n", - "\n", - "SymPy is a Python library for symbolic mathematics. You can use it as a tool to evaluate basic and complicated math operations, whenever they become tedious or error prone.\n", - "\n", - "```{custom_download_link} ./sympy_stripped.ipynb\n", - ":replace_default: \"True\"\n", - "```\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For example, SymPy is able to solve the differential equation $y'' - y = e^t$ for you!" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQEAAAAyCAYAAABcdW5KAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAMSElEQVR4Ae2d7ZXdNBCGb/ZsARAqIHQQoIKQDvioIKEDOPmXf3ugA0gFIekAqICQDoAKCNtBeB9F48i+/pBkW9f3WjrHa1keSTOvRqPRx/Xeefv27aGGikAJBJ4+ffqr6vle99cl6ttyHcLgA/H3QtdXit+ekterU1Ze694PAlJ0FP5FNQDv2tx3/O/19KfiGISThWoETgb9fir2BuBv3X/ej9TTkgoPPCJnCKap16O4U6cD64FbSz4cpOiPhcO3un+6FzwkKyP7n7oeKv73lNyi+UE093T/aop2jffVE1gD1VqmQ0BKfU8RFPwkyn3CZvhCdSP7mxgehBPewH3dMZjFQzUCxSHfVYUsBN5IuSdHwwtD5aHkYfqTsuCHIfhBeYqvD1QjcGHatxVx/Kh2V/cft8JTQT7wBF6m1CecoMdY4jkVDddFa6uV7QkBlHk3C4HqxHT8b3UxkjMVwL1nR+SPBEOIN/Cr6PEIinlPdWFQqNewLAJS4O9UIkbgQ8VTXOJlGTlBaZL3S1XLVuidnOqVjwVFphLF1lHqdCCnpWqeKQQYEV9KkXdlADworAfMOQx1o/xfCrtiawPVCPiWq7dlEJDy3ldJuMMo8x4D04LfZghueYvtFFQjMKO1atZeBJ4o9VbGYM5o2Fvw1hP96I0BZFckK6gMvCcMAd5UkVCNQBGY16tESsOxUxRvK2HuSLgVOXL4QPaD2sNGc+I5bj0LihweWq1dVXajN9UI5DT1RvJ4BWMVuthK8pjo4oOpAEqfPRKOlX8G71rrAcKDRcKcjvyLl9UZlaXl7urNIkZAhUYJGku3tNAXXB5KsiW325S2GQkvGPs+0e4q0Rlk39EYzZPbR3mYEnBhVNYILb25nluDGGY7CMFjRiNAYeVzjwdI5kLd5Bd+GF3mjIw0zL/Zjnuue7LCKd+SAaWFnxhdWLLerZTFPv9Pkt8t6uk+R89fqSw8q8WC+OnVm1nnBFQoSvi57ggfFUSL0UBRNnmQRHzhztKITqEDoTjE8bMuB6Tu0TIHZSwaFQ/sKXMsN+l02qJMBIWJj//0+Er3rBFM+c4G+0DsVaLCAsP+ne5Z5w3GmFKZLb25GiMee+cb7InuvZ2B97r+0kWnaYKesY78qowG31QQTxiofzxTfOyhuZT2Rs8/6c589y9Pc+obI8UmXG/fnrRplhdwhtiv3fZOx4SLTbGWrK+lN3OmA1gqOsVQgHkMwJseAvKRv9g2SA8PTZJXYLciq8QHej5yq5XG4RdGOGRatOOpXBoFPKYCxtN1Mt3BF4/qdirT2HtfDtO0uZ6ZGfskA6l6MRwnwx5sFsRgDOrUd0wHCK0O+y4p/6+XtaU3c4zA1ypwrBPTYXp/SaV8uNX/6eJTU7OUOB+OVs7f9YQSfzzBD8qK3FmjXavG4EHlYXRSXehGOZSfjpS1CKV85OWaG8wIpGJzUuy90EthMBfDML/h+EmYuED8SG+ucgqV0rEWYEwOFcFINTZXJf/XQ5lLpUsWRmCAeaT47US9eDW2fTNBuvprlOMPXwsHdKbaY22G7voKovk4Y+zXxvIQ6KLhulSdR3rjPAFViCVkMQwCDhE0rqF/90z38AcNjFpHLrFo6Ph4B5THyDD2SyryU05Tl+JFg/iFR7e7ofiYwTK+UPCxKZDRte4qGzzoqP/6F+A81wuCD6YHtBs7A1MGzFe92g0ZCVF8iN8i2L9j6az/Gq5RQkTo2pHe2HTALfCpAEb4Z7rCjsloTXoYPtPDUWdQfjr2b76cL3Qfc3GZO2I0JoPKoa4o2qCw18oXGq7gVRO16cyRLA1FEFF5KPjRekFAchRVHvimfBYZXV7d8Tye6OpdVFX6ZPBlGf+T9AUIPvJ14C3FBON9NexjmNg4DfoW7QnE6Fqf3lx7hTS3kk7bbcS+UR/r1KUL8SSPU/gwsRMnP6PBZBCPpjCTtIkEZtxivIBW0eIJDOjIBJOjNaUQDensJjBih3hgGC7tVB14pIRs7KnE488ABbaX+v1C+kgUrsIgW9euVQmLd6aggHqjKwwobDcN63QbEnXi5JnqWLjWUQJ2yl7y0VlZyR81jxUd254mNx9+aIyT4oxo7L/i6luwUY58TDsIjJicOTiaTrm3K/3x/NEu3WAYNLIEBDHelJFbOYaPpQ/djT4Ze8lyX4WaLNE6tBYGKjf6n3eINnXf3+E0BGKQnq1reAKu0XQHVABtpgJKA2zSohVWeaA3q6ToYEA4V/cgxfovUiwtIxcKawbzsWTl4xGGDQuMpLEOYjTOGOp5zsmxRVAQD32d/KB05GJnoTSP2diLV/DFQJk3EYWR6FfBQOWmduwofhOJsnXtOqiI+TPAhh2TgtlTNKU28rEGJM9BeaxzEA9HUCsDY0E5k0H5sXKu3Eni9wQxoxg80nHpBFMjEicjQ+8GhXr1vrrBmE21Bgku5IVrS2HU19Z9Is7Bvq+8S02L6iNe+CxdC40Ao3e3I/StB1AfdND3hdZ6gJSiO4JaHjyBbn32rnVXGb0WvEWU9+BGb2WFx8GRUPVDdxNWobTGY/Lp8BhOrUhGPlsw47kJ4KIrNCrNuzON2OAR6+FlY3+m+OSwHd1HVHi2rl0FnLU6pBSUkZerbwHrtdI/D/KG0YZxlcFoP3SIhcUcyjlZEH/IjAfE/N796CNkBgx0OQOguyl5SOLiendfEQxJd4GKvC0PRrSMlHg2J5Vd9S8dbPuTNp8MwmAR7CcrOn+CVr8cESdb10JPgO0qzgNQGA1qC1yNWx8w8FzxF8FzGKWcmF9S0TnWGuFDfkbjkpfjwB+KCEOAwbPOjhvGnH90G0/v8YjA7FPFLa8e3ZSIk5F0et7bcVqeTy63Y3DZPy3ZY4oWDrOwj6njzGkwqOjhZBCW2brWGAEVQiM2++p6RnGZVx9ZIqWRftAVLoI5RpUGPVOCwSAaN5XQvc/ADOZb64X4QPbkjunl4NCPk9c/H3RvMFN8cJqxljwnKteUFU8wOgifLOyjKyhIKFnQaxs0PlMcTLL+C7PKwgAQwCcq5OqaMwLKTIfH9XXurGcA9/jRSO3koeMkdx7lASjyn20QRjQ4bj2NzHSAABamBC7hDP6gZNGKNiKPGT5n4EfotvhqNgamD7o3A6Di6DgncPmfhKkDnuFo06zVcLvyJTOffR7U8kxx3IvBhSu9Y2GM+b4xG2Qfjnp68nUX1oYzbfMNZwKY0nC367HkWqJDFZNY/HLCc3ZbqIzXnunuusjisqgu9IcO9kSXi+vZzmEk16e8S2AAP60BUeUyIKAPQ1PnMV6tX5lxHaOd9c6mAzB71wPJWgBz+hjLxfQBARvrp/hUYPRsgTWVYYvvhQ/rCDW0EUBhcYNXDcKeerbmcTEg8P2M7j9coR+xE4SxSunQZgTMuK6GqU0HBkf8sZol1K0ujm3yBZTJuS90Kg/6FDDGWKjvtoUACktn2GOgs7NGNuQJfpAIitt9K9FXZn1eLFGoSn7hCEhhWUfC0+uOhhcu+bB4woRdIbyApFOFop/1qbZhjo7f2JrA8ZuaUhFIR8BOUO7VG2ghpo7MgjFufdLURfnIg+fQd0ZHycuGagSWxXPXpUl5mQ7gDn+zayDeC896GWchJqfK77O4mBnRrGl6p6zJx2oEJiGqBIkI/CJ6U+LErJdDro7PtCj3vwuz0E7eImtn1Qhcjt5tRRJGP05F7tYQSHbWRthtS9k1C9uPLXuMSJFQjUARmPdTiRSfVXJGsOb06X6kd0fF6cCfCIdGfsVZGLwXg4Po7Dcss89uxNQHTTUCsUhVuhQEODjDwanUbbGUOjZHK3lZCOQn592FQAzDm0iGycs6AmsrRULdIiwC8/4qkRKzxcWp026HuEgwJCcjPav5fYfsOJJvP8gblF80TKEoA0+iyHoAzFRPABRqWAMBOj+HyPbiDdB5MQS4890rdlQ3L6CYARCvh+oJgEINqyAgA8BvKjiXvwtvYA6Iwsi8gOIHraonMKflat4pBB6JgLUBRsgaxhFgN4DP0sd6DeOlJbytRiABrEqahoAUmsNDN7qKbXelcbgNauHEQirf6ChyOKgrdTUCXUTq86IISLE5LccPzVD0GjoICBemASwcNluKHZLVH6sRWB3iWoFXcBSdrbIaPALCgy1FjOODU4JSjcAp0d9R3VJ4PjbCz8jtK0w7kv5YVOHArskzXQ8UL74OEHL0P+6Kn033potbAAAAAElFTkSuQmCC", - "text/latex": [ - "$\\displaystyle y{\\left(t \\right)} = C_{2} e^{- t} + \\left(C_{1} + \\frac{t}{2}\\right) e^{t}$" - ], - "text/plain": [ - " -t ⎛ t⎞ t\n", - "y(t) = C₂⋅ℯ + ⎜C₁ + ─⎟⋅ℯ \n", - " ⎝ 2⎠ " - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import sympy as sym\n", - "y = sym.Function('y')\n", - "t = sym.symbols('t')\n", - "sym.dsolve(sym.Eq(y(t).diff(t, t) - y(t), sym.exp(t)), y(t))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "On this page, you'll get an introduction of the SymPy-basics. This introduction is derived from the introduction into SymPy from Jason Moore (CC-BY licensed) {cite}`jason_moore` and the SymPy Tutorial (Copyright (c) 2006-2023 SymPy Development Team) {cite}`sympy_why`." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "## Why SymPy?\n", - "... and not Wolfram Alpha, Mathematica, Maple, GeoGebra, your fancy calculator, or ...?\n", - "\n", - "> First off, SymPy is completely free. It is open source, and licensed under the liberal BSD license, so you can modify the source code and even sell it if you want to. This contrasts with popular commercial systems like Maple or Mathematica that cost hundreds of dollars in licenses.\n", - ">\n", - "> Second, SymPy uses Python. Most computer algebra systems invent their own language. Not SymPy. SymPy is written entirely in Python, and is executed entirely in Python. This means that if you already know Python, it is much easier to get started with SymPy, because you already know the syntax (and if you don’t know Python, it is really easy to learn). We already know that Python is a well-designed, battle-tested language. The SymPy developers are confident in their abilities in writing mathematical software, but programming language design is a completely different thing. By reusing an existing language, we are able to focus on those things that matter: the mathematics.\n", - ">\n", - "> Another computer algebra system, Sage also uses Python as its language. But Sage is large, with a download of over a gigabyte. An advantage of SymPy is that it is lightweight. In addition to being relatively small, it has no dependencies other than Python, so it can be used almost anywhere easily. Furthermore, the goals of Sage and the goals of SymPy are different. Sage aims to be a full featured system for mathematics, and aims to do so by compiling all the major open source mathematical systems together into one. When you call some function in Sage, such as integrate, it calls out to one of the open source packages that it includes. In fact, SymPy is included in Sage. SymPy on the other hand aims to be an independent system, with all the features implemented in SymPy itself.\n", - ">\n", - "> A final important feature of SymPy is that it can be used as a library. Many computer algebra systems focus on being usable in interactive environments, but if you wish to automate or extend them, it is difficult to do. With SymPy, you can just as easily use it in an interactive Python environment or import it in your own Python application. SymPy also provides APIs to make it easy to extend it with your own custom functions.\n", - "{cite}`sympy_why`" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## First steps" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let’s take an example. Say we wanted to use the built-in Python functions to compute square roots. We might do something like this:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/latex": [ - "$\\displaystyle 2.82842712474619$" - ], - "text/plain": [ - "2.8284271247461903" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import math\n", - "math.sqrt(8)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Here we got an approximate result, which is not the exact square root of 8. If all we cared about was the decimal form of the square root of 8, we would be done.\n", - "\n", - "But suppose we want to go further. Recall that $\\sqrt{8} = \\sqrt{ 4 \\cdot 2} = 2 \\sqrt{2}$\n", - ". We would have a hard time deducing this from the above result. This is where symbolic computation comes in. With a symbolic computation system like SymPy, square roots of numbers that are not perfect squares are left unevaluated by default" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We'll import SymPy as follows:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [], - "source": [ - "import sympy as sym" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Since SymPy works with mathematical symbols it's nice to view SymPy objects in\n", - "a format that is similar to the math in a textbook. Executing\n", - "`sym.init_printing()` at the beginning\n", - "of your Jupyter Notebook will ensure that SymPy objects render as typeset\n", - "mathematics." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [], - "source": [ - "sym.init_printing() " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can apply SymPy to our simple root problem:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAACYAAAAVCAYAAAAq05ytAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACJ0lEQVRIDbWV4VFbMQzHCccAXEeADWjZIGyQXjeADcr1U/KtRzeAFWAD0hXYAEbosUH6+wX7ne04oBcuutPzky3pL0uyPVmtVgf7psVicQbGD/hnFOsoqvhJvRvsrwnwOurnMKq4q17K1gHj0xgfew+MYH7BZmwU7TUwsnRCNCeMy1FRobzuseQg1/8b8/9ge2JU+jvg+sx+h+UI3mQ+n7urW5QvsiX/pt4TdMH/6N3qB7tjhr+MX5UzIYfwLKVBXGVDR4zd5St8r7wj6fd3xzaEZ2BT+Jlg3GFJZuo47bCc//A/+ZoyPnSUQ3gGZgAvODFDPWoD7um0c++dxBieN3+P6b1nmKV6nbkZPG3nS1nbUo78awOj+obXvfnJnk+ITVqdKOY9EGbjBa6aGnlNSec2y5Gxh2cpe2TTP2DwJy8m4ztk+SzJebkcr0q7cuGd/w28jcBw6m7tue+lI+Qn2D7MJ83MVcT6JRNjs9XFqwJLjr8wDndahYzAmsGZtRn/lrskS+9aiLB3I128ITCUZiidMg6ZEljuoHgXSUMPJnvLv+10v1mkb9LfircODCWb/ZxxAEr2BuvzVBF6Nr/H/pL/fJ1Y2lzmSr8VInj5SXrEWKCWvCRP20ll5r0otXMzBurzVb0gzG0QOlbgQzyvC5VUtt4tbX3EAVjCrpspAxtaoHXSyCG8iRfarkRgljof9WhgIbh1j4U0O0oE5lto1tre7GiPm/oP0h9EhCxiygUAAAAASUVORK5CYII=", - "text/latex": [ - "$\\displaystyle 2 \\sqrt{2}$" - ], - "text/plain": [ - "2⋅√2" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sym.sqrt(8)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "It's not only exact, but also simplified!\n", - "\n", - "## Variables\n", - "The use of computer algebra systems like SymPy is much more powerful, as they're able to compute expressions with variables.\n", - "\n", - "We need to define variable explicitly, so that the correct object is created. For example, let's create two variables `x` and `y` representing $x$ and $y$:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [], - "source": [ - "x, y = sym.symbols('x y')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - ":::{card} Test yourself!\n", - "Review the [SymPy documentation](https://docs.sympy.org/latest/modules/core.html#sympy.core.symbol.var) and create symbols `q1`, `q2`, ... `q10` using `sym.var()` without providing a full list of `q1, q2, q3, q4, q5, q6, q7, q8, q9, q10`. Tip: `sym.var()` is an extension to `sym.symbols`.\n", - "\n", - "Click {fa}`rocket` --> {guilabel}`Live Code` to activate live coding!\n", - ":::" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sym.var( )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "````{admonition} Answer\n", - ":class: tip, dropdown\n", - "```python\n", - "sym.var('q1:11')\n", - "```\n", - "````" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Expressions\n", - "\n", - "Variables alone have little meaning, we need expressions to do some proper math. Let's define a symbolic expression, representing the mathematical expression $x + 2y$. The most basic way to construct expressions is with the standard Python operators `+`, `-`, `*`, `/`, and `**`. For example:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAADoAAAASCAYAAAAKRM1zAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACmElEQVRYCc2W3U1bQRBGDXIBiBKgAxI6MB0EUgGhg0R581tEOgBKgA6gAwIdhA6C3IFzzrKzGjuX6MryNYw03rmzs7vz7fyst+bz+ei90nQ63cO3b9W/j4zPfqN/rLrew9Z7BVpBXjAeBRrkc+Sv8BHyXej7jNt9jFa1wZkJ/GXF9YI6y2vZy+jO4Ous7yMPChQHdir38WXZZoLiN+DcI5OR3EFvWvemoYH2dqTDUEBPADKCXbR8AV02TTcOqd5cpNkh+lPYW/tcbe6xuany4ANnHb9yyIF65ktDYhSwfu/DD3xfMhaqc1eMxzmi5yh+yljdw1ewNWZduJk186aEL4L08qMT68/36vMt8rKPJ+g+aVQiiqE3ko1MFw2MqrQL5/mifIMfm9BNBTZiFLhBkezOPj+Z1JXuHKn7i0VPyeID8iM6Abvha2lUljB/gWDzWCYvyPUL3bMauf9/982b1TOs2bzG73hTjd6PvAZZn4ouIhrGYde1KOb+GTmsC8gIvVmxx2g5rEysN+N2GY1QI74jEAKyvHJ9Gm11JaK5RtGV249FrfGwoe3cRRsnzvWy9hlbJJG9PGs1yLmWgVUpjhl2JYhjBAGY+zYj0RsdDXIqW/C5AWAyPHGmUTnsOFvwLXrIgs7+8llqtkTTD1NX5LL/IQW9UNDonIuCR9wMca7OG4A7ZHtApgm6XA6CLP1AI+YCUyupMXpReztOanQG38Ju/gA/I7c01mZD5HMh2Hjb87HLPcVs8730ZfgD+6ZKLaKD/qnn4LU0oxef+/9WwEbd16PQdggDjTP2lQcjQcFmXiFky88sKM/Ki7b+YYiPdY8c2lJn3Xun/cyaXMP+o7vk7IVyGzR1kzODiQASqI3ISFqb110X/BfFu+8OLJ96AQAAAABJRU5ErkJggg==", - "text/latex": [ - "$\\displaystyle x + 2 y$" - ], - "text/plain": [ - "x + 2⋅y" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "expr = x + 2*y\n", - "expr" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that we wrote `x + 2*y` just as we would if `x` and `y` were ordinary Python variables. But in this case, instead of evaluating to something, the expression remains as just $x + 2y$. Now let us play around with it:" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAF0AAAASCAYAAAA5f9J6AAAACXBIWXMAAA7EAAAOxAGVKw4bAAADFklEQVRYCc2Y7VEbMRCGDeMCGNIBdBBCB04HIVSQUEIm//yPIR0AFTDQgemAQAfQQRh34DyPIt3Ih33AObq7nVnv3upjX61WK8HWYrEYDZWm0+ke2H5EfJ+Qz35jf4i2wQuwfgTkNXyAPhfw2J8hUgz4OfJzwod+hn6vDb5N9qFJsO2A6RI2SUwWk6ei7UoroOB8An9vObUBPsnHMpdZb7aYOUVpE+yMncNHsPiv6kCLBh1n7rjchiYMegR4fbwZvoN9KXvaOHhlzCbYG6cuHfRG5680Gtwngjtf06++GWu6Dc9c1fSYUakUHAL1G2w2HUfYd/S5iXpxga+jNU68mEa0h8sUafDFvQ9b7y+QgWLbJXLdXKlrpzLP9DPA/ZJBcAd7EViTraMuzBrbK4HFgJsI6UUjnp8R8wy9jvErti92GhKFTAe0mZID9kgL1myXduG8PRh7+PECvYlBHiHdBBNE8pXjayEnbYN75aTy8psFPGVoD9AfsBl8F9d4PGk/p5sXX53cLMcvvUJiJ+dvnDefLPqwxudj/E5vdrP6NB+DLqa6balLnLco9iWHfISgZ8BT+6oFpLYXkvGrgjrC7mnZQ1qyWhPjPYm7SDO3Ir5TUhg0S2Bezz0F2hoznTmKYsf/C8premgERFpAdWli84nmAjon/Lpx+8gqw9HdSGt7ItuqkxmNrsP3cjoJqW/vcgwog2mt9CI1K9x5weblxssqv7zoUp7wabYervDtRlRZje4G5Hj5DDW+Mcvt1AdZXswI2f9puAFLlxE229JlhdoN4ddAmgy36N4ZOU2w5SXLgIf7w060pTWtLB35RB3oH6IP8c3Vx7DZYNYIVMAn8Ax2offwM3pVauzTEfkENPDpb4fcbb1keAp9j/vC+gP7Zpd6y3SwmDBSiCvyGpvJMdsq+V9GnPyXi1Tk76EYfE+Dr7BWVBL7ditEbx/kcQpH6u1D3tfTAMOeyEDolkhPx+k/S+vfYtgtL8WIAHRxvD1Nec33L+kLfG9UEktiL1peiu1mNjHBMeheUma4tdza2cVm46od/QUsNB1MpQelkAAAAABJRU5ErkJggg==", - "text/latex": [ - "$\\displaystyle x + 2 y + 1$" - ], - "text/plain": [ - "x + 2⋅y + 1" - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "expr + 1" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABrklEQVQ4EZ2UMVICQRBFF+UAlEeA1MjSnEBvIBxBj0AZQWbhDYDMzILQTAISIwtuADfQ4gb43tTOOixYgl3V9Mzf7j+9v2epbDabrNfr1bMs6+DaJf6Fd8AXAsfYKcmSDShuN5vNV3w4m83OwZ6J7+xXxxCekNzH79MiyO12jY9T/JC1hNf4EpJaqWDKvgbuGxxsElq4otCO9ln5oH05BVZxKPuMA5bgdWLF50SJ7/AGPmc/JAbLn42ILTvcMR5cAPqqcfLmPIA/Ed9wdU+tzeZWYC8huMOY5ARZfsCHBdgN7rVKTUzpdgkpHoCracuE3NxP8rXdmJOag7XzbUKK1OiM6ImFsQ8DI1qolql+yiO23SHJatAgFp2xdihqGc1nC7BwQA56yBosfFVBQzaeckVMh2C+h6R6SV7+cgr9LKhCYpJDmLLe0QbMyUaT7CxueGZ3evGlVdkopqTqV7byn4Nv4H3z2nzi3kkt6BdWXuz/erfb7ePztD5oGJj/+LErfB7TWDtZ3+oxYsaDCcl1QC8W5TYiDiGO9zPAv37LsSpGCiV0IHamdmOwH+0AtG+pm8vq1UVIVQAAAABJRU5ErkJggg==", - "text/latex": [ - "$\\displaystyle 2 y$" - ], - "text/plain": [ - "2⋅y" - ] - }, - "execution_count": 46, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "expr - x" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Notice something in the above example. When we typed `expr - x`, we did not get $x + 2y - x$, but rather just $2y$. The $x$ and the $-x$ automatically canceled one another. This is similar to how $\\sqrt{8}$ automatically turned into $2\\sqrt{2}$ above. This isn’t always the case in SymPy, however; consider this example:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAFgAAAAVCAYAAADCUymGAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAD3klEQVRYCd2Y0VEbMRCGL4wL8FCC6YCECmJ3QEgFCR04kyf8xjgdABVkQgeQCojpwO4gHndA/k8naWRZd8Hn9RCyM3uSVtKvvdXuSnfV09NTZc0XFxcDa8zXgFd674PKmCaTyViQx8awrwVu4N8/6vsGz7AigZ8K60TlFyvMfeJIz4Hwg67vVF/Slvyx67qai4OtVF6DYWZgAfaF91PlW4D/dZKeGPdK5SjoqvpUdQw0Uv0+yLctNXemOe9VrixTBMpdbavMLuP1AkPx544Y6HuezhUW3rwS/0jlHerYAfzK0sBnUtCFRQeFuk4hauAuNNSkuXTO5+O5fcnx8E7k7YA9+iYGFhC5d9FJm5ebhCEX0h2PLVFu+NKYNhn2OOuFEVhb9RBuJ6p/ErOLH8XQg8bc1tWNJ3msMWftiL2xmIVAOn1owHE3IPW7gy7R/UjjZ2rHKPV9NypLWNhjlHrwVAO/wep4EN+IyXHkJYzvcorKEnECz0sdXrYLdgusbZfeFePiVOFmwQJfvU3uVM9tcCYZ0Vsi7DFwHiwAPDedTNgwES+GDsVpvxMmDzaAK84GGWBvYO5RwOF26w1aqcTgOBtElObv2Ba5jK0NrMovgaU5lKvWo2QYmoVKIUBXIDbAjQ2CpNwVm/U5lTmUcmJd+tduA34Q+v9N74jn1yAnp3Nou1ShgXjrZZxQV9Apl4Uh2LMfPDiAhM4SWOjbqkwUDPO2xhZGyYCV5EQZX0+ktc6k+UTwoUo8MpLawcEwJFGa5l+8G1nT2eOcLs3BGuu8IYDFA00LcW0BrIkIh7Z+N08YXbCb1jSRSyc26Uhl9FzV2TRycSD6YkR7Ie/CF1vunGEO9lj2NIAKuYeDiN3AW5iYpgwSfZr4NWSNGJsq5DqNsNcWsmxIP7yw9GmP0aO3qs67pfZQ0+XkJu+lHw9e9PRgJ2C+wZ3VVY8kGX0h0Ud5VmEXTzIZTQvsAuzuIr0XRsOx7lXPv0CHkqVpB+NiMEfeJrxbMXX5Ye4c66nBLrBbTKg0+Vx8J2ZRvqmXqsd0wZgCfZcMZXOywM4xrdpcuzByuPunuHnYE73cd7lJ/RZzJ4baPLjeAKv/rPoXOhcfW+E9B0frnYrHzxlrOUZrTsWzJkz1DcRz+g/qjTB5srttIWOySAayUhveG+G1YiLZkeqkUbz+spYUn3i8+24wM7AWJs3kp29xdSuh1iR/poeRFXSKw4FHCgzEF+611i2mTclJO9jB6UUOtiSuM+Titfuk5QIvgIU3ckceqyT38g+5LfdydsVINvvhLlBHfgdPVaancOj+r0u/CXxqxyvdHwOidMKb8DIVAAAAAElFTkSuQmCC", - "text/latex": [ - "$\\displaystyle x \\left(x + 2 y\\right)$" - ], - "text/plain": [ - "x⋅(x + 2⋅y)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "x*expr" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Aside from obvious simplifications like $x - x = 0$ and $\\sqrt{8} = 2\\sqrt{2}$, most simplifications are not performed automatically. A general formula to simplify formulas is `sym.simplify`, which attempts to apply all of these functions in an intelligent way to arrive at the simplest form of an expression:" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/latex": [ - "$\\displaystyle \\sin^{2}{\\left(x \\right)} + \\cos^{2}{\\left(x \\right)}$" - ], - "text/plain": [ - " 2 2 \n", - "sin (x) + cos (x)" - ] - }, - "execution_count": 54, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "expr2 = sym.sin(x)**2+sym.cos(x)**2\n", - "expr2" - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAOCAYAAAASVl2WAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAZElEQVQYGWP8//8/Aww0NDQYAdmrgdgYyP4AEmcBMgSA9GwgfgfEJkCsBMRwAFIAUhkKEgGyy4AUyBQ4YIKzcDBGFUACBj0chKHhJQQLN0ZQZAGDGBRBIOACxKC4OQfE94B4NwDm+hiAOyllRAAAAABJRU5ErkJggg==", - "text/latex": [ - "$\\displaystyle 1$" - ], - "text/plain": [ - "1" - ] - }, - "execution_count": 55, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sym.simplify(expr2)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Only attempt simplification on expressions that are several lines of text. Larger expressions become increasingly computationally intensive to simplify and there is generally no need to do so." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In many cases, our expressions include a left- and right-hand-side. We cannot use `==` for that (`==` checks the similarity of the python-object), but we can use the `sym.Eq` function to create the symbolic equality $x + 2y = 3$:" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAGAAAAASCAYAAACkctvyAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADhUlEQVRYCdWY21EbQRBFBUUAQAiQAYYMRAbGjsCQgV388UfhDIAQIAPIgEcGJgOryACfM0wP49ViS8i7rLtqNL09r9vP2dXS09PTaKh0dHS0AbZvGd82/cRn5PdZNvgu63CQga7Sq9MJ8mtlS0N1QAZ+Sr8rUAn+hO4rbRc+KaB8qARGDa6xwwEj+I/ILmh78JfLXYLngDFt/41naOwC3D3Yy2x4pKnA/0Dqvg9ujR4UgXOooFMHsL8RYHsLjVn0A/DN9SqwitxUHjpZKg0YWyJwF17ByrN4kL8aeqsJuELadEw1NAwW7OqwVqNBFtlwqrw4gAEVinKxA/+FZpR9pkk3zLl8Zrv/5ay9V07ZUs54uojpA/cm4juez2JdHjunf22vmNpLDw6zOpXWwFkc4ADCVHPpvejOaRrdtw695cLeHMBZUwQOjW9QxJuRcw4zRiNLzMUB8J9oEXGw7ZT10zjz0D3rZnJsxu3+BraBcxsHJQcwwcjXwEHWKYGbBdI6rR5Pwnf48fK9BO93z86K3WQcvi1NMh+dsrj0QjbVs89vl/3UhAUF7K/RI2O1q5ma3oIiA24RPFTnfHABMh0xcnI1NsUyboa0RZCOc32bgjNHUN7DMx4aWHxOijFmtB87tyIxNWXVcP8seA0g7XpBvxYZEEoEojZlYmyqZ6M2A4+Q6+0N+hSxUwtnFLDeDF2nN6IL8RwBoqFXaaX8MGa5UvbXDGBOJ5QxjOib9rUEiXmcHFCfzuRQptR7ZCoyok8K1/O75jlTJ27SlyyET6+g9JG1jpWMzZjU45E5TeXz8EvHnNcy+GXSNDdLBt+5jP3XaK22W2FA41pb4/PYaBZ4KMfj80Un0yeBwSjeoa8vXSHolBLt8DqkxsvjaKb670T2b81gxxYkjX7N/k3jb+d9r80AI8Xm247OmNAKIXMsLroi75rhXI1qYKiAEVrTGFld1jR+um+cxFjo1JVhayx/4puBIzaDRzsfwD+uwFgjjSZBO8GBK5pKm0IT+FKOnNMTXXGOTohvk/rYZllRUd/3fVP7SfObQHq3+u/h4DmjGSx1AKlT+S+r0z/jOFhvL3wJq8w8xLk6QsV9mxs0LXeMztrXrH//9EiNTUuXnRvDm95mzbHPQydLUGeEMfooAWZZneLpa5iz36Nszm3LTkvQ3GjesABD6wAvYCPf2u8HTh+O56jF6RcKaFOdt/5iVQAAAABJRU5ErkJggg==", - "text/latex": [ - "$\\displaystyle x + 2 y = 3$" - ], - "text/plain": [ - "x + 2⋅y = 3" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sym.Eq(expr,3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "When setting up these expressions, watch out! Be careful with numbers, as SymPy may not intepret them as expected. For example:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAACUAAAAPCAYAAABjqQZTAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACGElEQVRIDb2V7TEEQRCGlxKAIoOTgY8MyMBHBMiA8uvun1oZOBH4yAARHDIgA+oyOM8ztq92p9ZZCm/Ve9Pd09vT09MzV0wmk+I32O/3V/M42BZhL7d/pS8UNQwGg7JSXxlXYIntpeYyS7zHdxGHp8pJWax9DN1/58OVgI/II8ZjeIZ8DG+Re+HzxfjG/BiuQhO6gWt8r+17sJSU+AA+52XFVsLb3N6m43fdZv+JLSq1w1ai7PVdjVA22W0cRX3uz+RIapMVLH+O6Cfn/w0LHauw1CUjYh3gZ1WXob14iq1xAtV6+okNuA/13YNiZKViwVkN2eX49Lli0TPoJZGPyHmVvdH6eJlsjwtoi+hvjNKkusCdzwRBt+B0Y8ge/R08jw+xWaF4djTrvw2HKsAClb5Tbb2kg4gq+m79BCZmFXpVkg/VGLF8w56wpc0weuGK+TAgW7ocYYuGz+eTTgzfM9+5z5Di4NPoL5x34WX+kZUSlrmXpOZPVMr5WVhnsq3i6fuWZAps9prJ+sgmYEvJR09dYzVwjkZ588maPiSgf0s5XDhtyAWhFdUmDuEYvX4KJ+jjlBSCjfbGaNMlIJu15fXKJmiDE5gf1Tm2aUPrjH708VWR+gTZZKTrGLtRWWzOeRuLOf8GROXozRhDG9s3pO2decZ+h787nQLd4/daC4/NRf0fNV7BaCLG93t1nwWLsAXdpMmmo3wHBAKNiPr+/bAAAAAASUVORK5CYII=", - "text/latex": [ - "$\\displaystyle 0.5 x$" - ], - "text/plain": [ - "0.5⋅x" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "1/2*x" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Python does the division before it is multiplied by `x`, thus a floating point value is created. To fix this you can use the `sym.S()` function to “sympify” numbers:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAlCAYAAAB21ggZAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABtElEQVQ4Ee2VO1ICQRCGF+UASGgIN0DJCeAGPk6ghmZSRJDiDShPYMkNMCCn9AYQGlLcAL9v2FkWliqKWLvqp5/T89juprRerxNpMBhUYI9BSZIm/AHUwH1qmxEzPksV2RDDq0CegTfQRu/CTTYESdkfjGYOBnVoBW6Au0hVsPF7pH6/35BHoI/AV9TzPByJHb5Dnu3PHeL7Vt1K+TsEK4vbCJ55HMOwVYR6ORU+kL30J/wJrJAX8Eg9dC+fuIMZxTJdvETOCJs+Xy3QeavV+kHyFS7AFQG96XQ6B8/gEtsaW3a8ki9wChUufWzx/4JjL6S/RFWe9CH+5Icr55+SMq6hh0aBXwN7o4s9a+HsldLgEbxDUCBkJ8UL6CDbjaHj5JJO2zMjgtzNkWMLB8qXt604Jyg0e+qXmdkh4HF3dtCxwGHGQ7RJlB9Sh2RKZ275RF/+SIWs7NbAmH+5nSMVFmDwsmMWOqA3FLfa5xzD+TrZtx88Ehmd5lV49k3iBoUFBDnm6/DbGIRcE+o7CzB6ySY8lkdcY5IwQvdLY4IjlECMTLn/RHXlfPEZ7Lbxf05/pKz4fgFvfO5bFh09iAAAAABJRU5ErkJggg==", - "text/latex": [ - "$\\displaystyle \\frac{x}{2}$" - ], - "text/plain": [ - "x\n", - "─\n", - "2" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sym.S(1)/2*x" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Or you can ensure the symbol comes first in the division operation:" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAlCAYAAAB21ggZAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABtElEQVQ4Ee2VO1ICQRCGF+UASGgIN0DJCeAGPk6ghmZSRJDiDShPYMkNMCCn9AYQGlLcAL9v2FkWliqKWLvqp5/T89juprRerxNpMBhUYI9BSZIm/AHUwH1qmxEzPksV2RDDq0CegTfQRu/CTTYESdkfjGYOBnVoBW6Au0hVsPF7pH6/35BHoI/AV9TzPByJHb5Dnu3PHeL7Vt1K+TsEK4vbCJ55HMOwVYR6ORU+kL30J/wJrJAX8Eg9dC+fuIMZxTJdvETOCJs+Xy3QeavV+kHyFS7AFQG96XQ6B8/gEtsaW3a8ki9wChUufWzx/4JjL6S/RFWe9CH+5Icr55+SMq6hh0aBXwN7o4s9a+HsldLgEbxDUCBkJ8UL6CDbjaHj5JJO2zMjgtzNkWMLB8qXt604Jyg0e+qXmdkh4HF3dtCxwGHGQ7RJlB9Sh2RKZ275RF/+SIWs7NbAmH+5nSMVFmDwsmMWOqA3FLfa5xzD+TrZtx88Ehmd5lV49k3iBoUFBDnm6/DbGIRcE+o7CzB6ySY8lkdcY5IwQvdLY4IjlECMTLn/RHXlfPEZ7Lbxf05/pKz4fgFvfO5bFh09iAAAAABJRU5ErkJggg==", - "text/latex": [ - "$\\displaystyle \\frac{x}{2}$" - ], - "text/plain": [ - "x\n", - "─\n", - "2" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x/2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - ":::{card} Test yourself!\n", - "Create an expression for the normal distribution function:\n", - "\n", - "$$\\frac{1}{\\sqrt{2\\pi\\sigma}}e^{\\frac{(x-\\mu)^2}{2\\sigma^2}}$$\n", - "\n", - "All variables have been defined with:\n", - "\n", - "```python\n", - "sym.var('x, sigma, mu')\n", - "```\n", - "\n", - "Click {fa}`rocket` --> {guilabel}`Live Code` to activate live coding!\n", - ":::" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "tags": [ - "thebe-remove-input-init" - ] - }, - "outputs": [], - "source": [ - "sym.var('x, sigma, mu')\n", - "expr_correct = sym.exp((x-mu)**2/2/sigma**2)/sym.sqrt(2*sym.pi*sigma)\n", - "expr = 0" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "expr = " - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "tags": [ - "thebe-remove-input-init" - ] - }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "4f6e6e54013747078a38a8b8828be565", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Button(description='Check answer', style=ButtonStyle())" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "82d1fa7e41ba4c188826a698baa8e76c", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "check_answer(\"expr\",expr_correct, check_equation)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Functions" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You will also work with undefined mathematical functions in addition to variables.\n", - "These will play an important role in setting up differential equations, where\n", - "you typically don't know the function, but only its derivative(s). You can\n", - "create arbitrary functions of variables. In this case, you make a function of\n", - "$x$. First create the function name:" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [], - "source": [ - "f = sym.Function('f')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now you can create functions of one or more variables like so:" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAACUAAAAVCAYAAADB5CeuAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACf0lEQVRIDa2W7VHbQBCGFSYFmHQQlUBCB9ABIRUk7sCZ/LL/MdCBoQKGdEA6gNABLsFxB87zHCflJOuEBnlnVvf17qu93b2Tiu12W4zV+XxevpWjy/agGCmLxWIGxdEImjJy1BTv3GFOAC9Z28T1C8ZVP0wxPqNzTPsjYt7UYO/GNrTXEmQjBeCS9Q/oLfodPUFrYX3C4CftKIckhOOKZho5804B0hEd0rFH9Deaik4byX2JXHIWnenDY6Nyjx7Sb6RMI4X5v+jhy2g/Tzlh+phL3ymLK0A5h6yl1X5cabDIef4+ncIJU6ZDRmrN+C62U9pUxLTTWa9jZ73JpRyj39AS/YoqD2B+vXQbTzlPG5ECeI1+YUHSpX207ZAsn9FnOxm5xO5KZf0BvUFPGHso5A61Q9sWOctGpERg6I6UbCRYk3gtqC3YG6H0pRvGpttoKR6cdD1Mxoecu04xGS5CyJ9SdKsvsS/rkkds03r7BOiJuYCnNRM50W7SSF9EWgMpaY6gc75jM+cAbzvBu5Nhs11OGam+KEllmE1hr+CgB0ZcXdTMTdSMofPrnZpi0iK+yBhV00ayqr1qrogv88Ra6Nakh8TPRxr5vq+AkVo1IoWxL9Lb1yLlumlui5FRvU7CrlMAc655GnMS6q8dKVNXYNx38oRYI0akLdr5UfXl8vg9u0f9hPxBdbZOpZiWaDdt/Evxb7NE74b8G4F7Ro+GYIdg4CrlFHuA52dotWvraehJ8a7pulhbmx889GKVM/wl2KlPxCvh1SYIONPkD9pOwUfI4CZyyBX+p6yp4FRs+y62rpeIN8p+C8eINfc/6kPy3YeJtTDrw/StYT+TI8X8A8ObApWBYhW/AAAAAElFTkSuQmCC", - "text/latex": [ - "$\\displaystyle f{\\left(x \\right)}$" - ], - "text/plain": [ - "f(x)" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "f(x)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The same `UndefinedFunction` can be used to create multivariate functions:" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAADkAAAAVCAYAAAD8dkbIAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADW0lEQVRYCc2X7VEbMRCGHYYCDB3E6YCEDqADh1QAdOBMftn/GNOBQwUM6YB0wEcH0EGIOyDPI+suurNk7NiZ8c7sSVrt7r2rXel0ndfX1866PBwOe+v62JR9DstOZ00ajUYDXBys6WaT5r2Iqfb5zhUsEcoT5qZx/oJx1Q8ixn06h7Rfo85WNOBx4ae03wVUzCQKY+b34Wv4DD6Ca2K+y+Ab7VYFKEAwXdKcR4zlIFEyMAM00Hv4J5ySi2Cmt5XEJsZOtlxZAbN2C+/Rb5SoRhLy3/DebLSdTzGC7H2pXI+ZfEapFKB78Xk7Q2ugEuPJbioiKEvUAM3kC+Ob2J7TpqROu3zreezcr/qSDuFTuAd/gaU7dH7Muss9E58fsHhgHA4VrePcFe3nljcxHjcyqWFUFOTEPtwOUD+f4Cc7BRpjdykzfwdfwUeMPaT0HfYK7SrkIac/t1Hb/gSZ1dUmMfYamVQDR664VMwUcwJ9UalN2JvBFMSUsQDMpuRBls4H4aIHPv0Ou1iSVdR+d6my1JsPEqEODfbRtkACFXyO7rFN9+tHlB6RBX3adknlfLRlng8VHrN20VJwe7Vlqoij2yhXpZB7KAUZhMs+EjCViaCuq8G/tMkCGYxVlO5Hk6IsV3khGbkgNapWjW6WLAMdLyTAVaDqQwZZV15oWJ60CuqqiGq+w9tNDrPveckF6aFS1X/0M9eY6Wrv1pMxgFtaXyx5aAkgrQwPkGmYjQ/t0vGCvu9Mfala2o/OmcnnRpC8TCe+MLcqiGty3rJuk8HJfn7CKqYKyJxrLGDU82LxkOoW+o0Aoz99euLmKJwHjSDRslQ7GOfqO3XiHgu6qZC+du4XX3yGHzN5SuvnyFPXUq1Ll3GHsVkV/DJlHO7J2PiJ8hJeHWIlvLMFSP/j+BebwDeprNRH7wk+KM2vKsdXH+6uYof+GH7I2SDvwU/O7bAiffiGVZHcj8uehH7rzNSmyF82s5ol5sxeXdL03Q5WR+7ToQ+zLsbwF2KnLhWMG+WkUo7Qsyz9QXUfr0UR8K83nHihSBPgLcob2hzeiEls4VOzi2IIMrZVjTNcitS3Cjzh1iH3r1e2RWRm9tFzL3p/dZ+X9qK/WX+rLFfPq8hi7Q9WsfmfuuAZiCl9xx8E4gWsmkncfAAAAABJRU5ErkJggg==", - "text/latex": [ - "$\\displaystyle f{\\left(x,y \\right)}$" - ], - "text/plain": [ - "f(x, y)" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "f(x,y)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - ":::{card} Test yourself!\n", - "Create a function $H(x,y,z)$\n", - "\n", - "All variables have been defined with:\n", - "\n", - "```python\n", - "x, y, z = sym.symbols('x, y, z')\n", - "```\n", - "\n", - "Click {fa}`rocket` --> {guilabel}`Live Code` to activate live coding!\n", - ":::" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": { - "tags": [ - "thebe-remove-input-init" - ] - }, - "outputs": [], - "source": [ - "x, y, z = sym.symbols('x, y, z')\n", - "H = sym.Function('H')\n", - "function_correct = H(x,y,z)\n", - "function_answer = 0\n", - "H = None" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "function = " - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": { - "tags": [ - "thebe-remove-input-init" - ] - }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "bf9cdc4356624837a034f353336aeb2a", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Button(description='Check answer', style=ButtonStyle())" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "8052642635a74e9b966db4bbc3ee54ac", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "check_answer(\"function\",function_correct, check_equation)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Evaluating expressions" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "SymPy expressions can be evaluated numerically in several ways. Let's say you have an expression defined as follows:" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/latex": [ - "$\\displaystyle a \\sin{\\left(\\omega \\right)} + \\frac{\\left|{f{\\left(t \\right)}}\\right|}{\\sqrt{b}}$" - ], - "text/plain": [ - " │f(t)│\n", - "a⋅sin(ω) + ──────\n", - " √b " - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a, omega, b, t = sym.symbols('a, omega, b, t')\n", - "f = sym.Function('f')\n", - "expr3 = a*sym.sin(omega) + sym.Abs(f(t))/sym.sqrt(b)\n", - "expr3" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And you have some values for which you want to evaluate of the expression:" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [], - "source": [ - "values = {omega: sym.pi/4, a: 2, f(t): -12, b: 25}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can evalute the expression using `sym.subs`:" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAEwAAAArCAYAAADSZm7JAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEL0lEQVRoBe2a7VHcMBCGj0wKYEgH0AEkHVw6gBagg2Tyj39M6ABSQQIdQDoIdAAlEDogz2Mk4Q/Z+O5gcj6jGbHSamVr31utdmXWHh4eJmMph4eH2+h6Rt2hfV/XG94mvK+B/xF6Zx/+deBN3sfGqlKUXUe3H1SVFwRBaZQA1gn0cxyk/Z32lTzqpfx3cXBVKYreU/eoB+j4s0NPwVEmFeZobVqiVlmUlQcsKtqDTpG5ASQtsly0rHX4hWW+AfYEjcDcAkzDtwWRAsiV92FPeHS3AGqvRcKDYsJ44fjfLKwFpQCSYLkV48m5+k6/A48+Qzr7c6zrOAq/WVhEokYB6QSWPq2yVRfyYTxMk72qvau1i/xa6+ASDbDOfZazAU0xWVzeQoDxEGMXo+YUCccHD5Wiyy5r34Imy6KtH5tAb+fekkyunB5DBai87qDTJ2hy8mFcEM0UFkqNvjFfCxtS+RAWuwGtxFuApBXp5C9p67/KZQqvcPxzbcnw8E1okV+Vn7yMbdYZU5tpWN8ZvFvaF9DTwLuACpr+q16Sy1mb57aCl/gL+NIEGG1fFk05m+nXVzHE/syAAYwpwm/oTlQ4gJXL9L8gkzL9KD9kOo/T128d1ZTulenX5nR2+RH0G7nt0TnvtQdnAgwFtC4VOa8tTN/wbKZfm/Nc13dZl6rMBBgrbzsZe2X6S6X5nItJpyRWY6zhZVty5Jln7jK+VefDS0FebWzlYrUCMBTWOWs9HrXJmZeVDzL1+KQsUmkjL1ib1HhyVsaH2nkXFDMWsW6Hfk6fA8ZS1p4TqPEamX5tfJDdFFYAhg72L9XrjMoWo+9p5TVtL8CQ0xINbBvJK/xKCbIxoCyPGY1bipTksZn+XjOvssY08sqNBJjvCYsXHJNPt2dRaN/QyH6aCiKJIOt8Y6+FFGK+PlXQe/1IaQGlBnNf/BticvrhPcZTKqzfKb6ghIVrdfdBppUE2dZMv3XiKw2wnhe/TqqEFbxAq/KU3KcdYyAPg3qg2lAReZ18Z6bfmDRARt3CVEEr06cImgD+gXZaF+Oehs9m+sgMvjQAQ3mvN8zOY5jRxxf1yvQHjxYKNAALSrkFtRjvtJPzD2MNgkwjmG0ILRmDNRtCpWsbl0dfN+TVdKvOWcCYoJP3Yf8z6NQNdLoCxhcp3rgIUATNtiUbuD8OTSaVsCIyx0ABy1DJWE+gtCgvFI7gd/5IWQtj4hjKXMFvJawYA0qL6vgG2IwIjnlLTvBXRY4MZn5NMpbUh8VDIAvlmC1MZ/8LgI6pRgNW/9twmkUqMEd7SuZAAawiAIe2xpVjtrAcZoYX3pC4PbNllIBpSdSuf6KJQWwDtFECBgp+aM6BUlxaAmar4x8rYKeAkvNTOvyuj0Cj/Q9Ev9JXPujQ90OQpfN2ZrSnJADp2OPlglvxzj78zlzyH4sLenMo1kg5AAAAAElFTkSuQmCC", - "text/latex": [ - "$\\displaystyle \\sqrt{2} + \\frac{12}{5}$" - ], - "text/plain": [ - "√2 + 12/5" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "expr3.subs(values)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Notice how the square root and fraction do not automatically reduce to their decimal equivalents. To do so, you must use the `evalf()` method:" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/latex": [ - "$\\displaystyle 3.8142135623731$" - ], - "text/plain": [ - "3.81421356237310" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "expr3.subs(values).evalf()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To obtain machine precision floating point numbers directly and with more flexibility, it is better to use the `sym.lambdify()` function to convert the expression to a Python function. When using `sym.lambdify()`, all symbols and functions should be converted to numbers, so first identify what symbols and functions make up the expression." - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [], - "source": [ - "eval_expr3 = sym.lambdify((omega, a, f(t), b), expr3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`sym.lambdify()` generates a Python function and, in this case, we store that function in the variable `eval_expr3`. You can see what the inputs and outputs of the function are with `help()`:" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Help on function _lambdifygenerated:\n", - "\n", - "_lambdifygenerated(omega, a, _Dummy_38, b)\n", - " Created with lambdify. Signature:\n", - " \n", - " func(omega, a, f, b)\n", - " \n", - " Expression:\n", - " \n", - " a*sin(omega) + Abs(f(t))/sqrt(b)\n", - " \n", - " Source code:\n", - " \n", - " def _lambdifygenerated(omega, a, _Dummy_38, b):\n", - " return a*sin(omega) + abs(_Dummy_38)/sqrt(b)\n", - " \n", - " \n", - " Imported modules:\n", - "\n" - ] - } - ], - "source": [ - "help(eval_expr3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This function operates on and returns floating point values. However, it also support arrays of floats. For example:" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "array([3.81365036, 3.76704398, 3.72305144])" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "eval_expr3(3.14/4, 2, -12, [25, 26, 27])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - ":::{card} Test yourself!\n", - "\n", - "Create a symbolic expression representing [Newton's Law of Universal Gravitation](https://en.wikipedia.org/wiki/Newton's_law_of_universal_gravitation). Use `sym.lambdify()` to evaluate the expression for two mass of 5.972E24 kg and 80 kg at a distance of 6371 km apart to find the gravitational force in Newtons. $G$ equals $6.67430\\cdot 10 ^{-11}$\n", - "\n", - "All variables have been defined with:\n", - "```python\n", - "G, m_1, m_2, r = sym.symbols('G, m_1, m_2, r')\n", - "```\n", - "\n", - "Click {fa}`rocket` --> {guilabel}`Live Code` to activate live coding!\n", - ":::\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": { - "tags": [ - "thebe-remove-input-init" - ] - }, - "outputs": [], - "source": [ - "from math import isclose\n", - "G, m_1, m_2, r = sym.symbols('G, m_1, m_2, r')\n", - "F = G*m_1*m_2/r**2\n", - "eval_F = sym.lambdify((G, m_1, m_2, r), F)\n", - "answer_correct = eval_F(6.67430E-11, 5.972E24, 80, 6371E3)\n", - "answer = 0\n", - "\n", - "tolerance = 0.001\n", - "check_float = lambda a, b: isclose(a, b, rel_tol=0, abs_tol=tolerance)" - ] - }, - { - "cell_type": "code", - "execution_count": 104, - "metadata": {}, - "outputs": [], - "source": [ - "answer = " - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": { - "tags": [ - "thebe-remove-input-init" - ] - }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "040de5c97c9c4ee6a710f9315e5f3c43", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Button(description='Check answer', style=ButtonStyle())" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "86269cba2b8947e6a04c4a452678f51a", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "check_answer(\"answer\",answer_correct, check_float)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Some examples\n", - "\n", - "SymPy has many possibilities. Check out the [documentation](https://docs.sympy.org/latest/index.html) if you're curious. Some examples are shown below." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Take the derivative of $\\sin\\left({x}\\right) e ^ x$" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/latex": [ - "$\\displaystyle e^{x} \\sin{\\left(x \\right)} + e^{x} \\cos{\\left(x \\right)}$" - ], - "text/plain": [ - " x x \n", - "ℯ ⋅sin(x) + ℯ ⋅cos(x)" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sym.diff(sym.sin(x)*sym.exp(x),x)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Compute $\\int(e^x\\sin{(x)} + e^x\\cos{(x)})dx$." - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAE8AAAAVCAYAAAAHIbMXAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAD6ElEQVRYCeWY61EcMQyA95gUQKADrgMgHUAHPCoAOgjDP/5loANIB0AH0AGPDkIHgeuAfJ9j7/g2u8vt7sEwRDM6+SHJsiTL3hu9vLwUXeD4+Ph75B9DT8AtMLSZe4xzH5Jg30pfG+tkF7rsEgU67gp6Cl0Cz2J7nfYq+GEh2j7ERh2fEifss5PzkJigIGXXIv3r6K09xq9iuzNBVsOewf3OwjMIoNfTsQwdYuONS+U2dnIegueZrRu0gzGMP2TjfZorCBmMtT7CbTLYpt4j6GEb3yxz6PDEHUSdRSfnpQUQNv3LLKTv5nsD8kb1K/Sgt5JmQevyWfN05xl1qXN25+kg8DkutQtNx9eheUR1EnXPm+xgd35iBumPutS5+GVWTTA/ghegRTPUuthWxWDnzWpHFz7ss9blQe4i3sarzp0p57FYqA9M/I6SPkEOGQ9ZAc2PVSigka+VIOcxt0aqxzWEXcbXQI/8JSi9ob8NLaDK/AQdvwDTs4hm8Q28hcca1AabTDbaiby2pEtKnXug63myBNeou2TUuVk6DyY353neph0uAKgbOAJ7ZxY6NPAE6kZKoB8CATWKOvG+nKRBXxsc/wVdAldpB2dBtese6rOpLbN8QrXVO+1KdniiDJYOM2FSbatznjZtLPBTwKi3PYoqy29OHRqOKLQvuIF19KaMS3qqm3pKExWqczaQLzeR2ah9beCatXrRYcaFwh8VTKAe81QfDVg+H9kCUedKyry0kUWUpofgMgzX9BvTPtfW1FYedDHfceoyGOmh3SRWHb+rDsR+NSBVNh2gU+rgDnvyrPWZ9MBY4IeG8lEnyJhy5YVhBLtuqEFv7bCGHYFG1mia4edgXkMZfj9g7YfKajv0f1TGmrohKOHYRo7bJs4h4xhpSSig1pExOKKr0/ZpW7veEsz417KzwA6TR768NHgKm2Qdf0rOMw09pv8ACsyWIaCD0o0W9KDTuqKh1sO3BPcVgpcvolNAS1KqmQazfPRHXr9KJrlc1jbzHpPzPEpJUeCJC1gLq+kd5jv+aEg1ivar9bTK4zIa2he03SdIFdyr+BTtMkNLYMy5tpMY6uMo/SWFgBeF2ec1LBid195RfzlbfqMhPlPS21Fu1wmXEfNmpvUwBU+HpvdWqpNmgOPWJDPJTJE/jKOjtrhH3ZdQ36sl0DdIJkzYK/1T0BOmnT6ZdGp5hOlPAXPKHZTOm5r9RJ240fLtOnRr6DN4Bn6cju1QnR9Z3gwzU+cFfjCoc/Y/Bua18nvrIUO8nPxTw4wZBFGHusJD+n/IPB1mTfTyGwrqKLP409e85K2YNVvQXpcgcl6oU9/SfwDp3X1UGYYoPQAAAABJRU5ErkJggg==", - "text/latex": [ - "$\\displaystyle e^{x} \\sin{\\left(x \\right)}$" - ], - "text/plain": [ - " x \n", - "ℯ ⋅sin(x)" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sym.integrate(sym.exp(x)*sym.sin(x) + sym.exp(x)*sym.cos(x), x)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Compute $\\int_{-\\infty}^\\infty \\sin{(x^2)}dx$." - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAADoAAAAuCAYAAAB5/AqlAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAER0lEQVRoBe2a7VHcMBCG7zIpgKSEowM+KgjpACYdcB2EyS/4l0k6ACpIQgehgwQ6gBIydEDeRyd5ZEu2JVs2zIBmhKTVandf7WrPtlg+Pj4uxpSzs7Mdrf+k+jlVjtYsU3lL8b0tIOibZJzI+JMCsiYTMQqo9eZC7e1kFjYEW503DXLvcBRQSf+iikfnLOjbzd3cwUClaCWFK7XXPkpLd2G8p7l/qoT2aK9LBvlgMUTWYKAYbyu6TZEBgD9X+9GSMAoP3EBTrW2K48loB0fQmwwlFasM3tJgL2I4oNYVozriYUMeVH/59Ny+5EQjKFXOIKASDqCvESUHot3JKDbCL3hyyxrr03P6QQTlLM4GakEcqL2KKALQvebwYKw0NyDGE9CszlgEBbxthCFntPWcyKCjFkWDk4iVF40g6YN+rNq1gRfiW9eAinCoRQ9qu5LGoea3rQG9jXgByflymbh3jc+g9YAggppnH5AUNheefdUfqmR6xgaD1plsXwEVgUc4vHWvuqsaFMtzHkx0E0hCV1r7vZutdTaIIMli8/6oNcfH2aWWY0OeuFZb+zkzZ1REFl7YumPHGgZlrblkg8XLpqA8GtKiEx0Y1lXgwbaqaHyr6ucIfrpwEAXPur4h8McBZeGDxi6Tsou1onnOQrI3Lf97tdVvqi9QdCLoUtWFoD9t+panU6d4cBK2u4Kj/LGhG6COwzKwe+ziytFtyxmr7WxjvhpqLWd9W23lSeQ5mWpLRhBn93elfJMPvOGmWwNqZ90OV8lDhmE45yzYqaZEC2JfbbXe8iCDx8GF5opEkORsSRyR9hO5rogeHIcAqJiIbzLWsRXEekLZhTXjaBE/UUDy4eGAR8Gqisb5rm2UHY+JIEDGfreD41JlXS3wC15lVwAL8L9NI31mr08IARYDmqWWBb1JdMFPBJifEOlKjSAANSPHT1Ka3pRl2xcGKeOdD6MBemQBb1YV/ivZbBAb+059fsfR/YF+KVVB6HqCCVXOAKERpGuPr0TX5QUiCG+mRlCy7lagUkgIEG7N0EgWnsooXeQEdJELqA64umVK2xk10mVA9AmpjOpAChFEIpskglo9GpgxMWHqCGpNRhPjml38s/Ho1MhfDNDl6enpuE/1U7uikPzXM1poI5+NmBdzRl+BPpuYK2RI5yNgIR1GjJ58Vuq45+Y99XkJL3InYxT0/Jkl61qQsTsZvhuVuJPpgWk/jvVyjWfgbcS8VDtRAo93ed8cdSfj5PW1cyUjXqqnupPpw2jm5wLK+2bs244zkhf8ScssZ7QNgcL3TnN8Bp38nzfm8miAVeD4tutn4oCnJOHJgArE2DuZrH14ktCVN7lmIGSD769Z1mcwz+5RgeMbbuudTIbtWayzAhVIPmW23slkWZ7JPBtQgST5dN7JZNqexT7LGRXIlazia7y5hW5YyG128g16Y23ycK6H+iF3MskgUhj/A8zGmJ7B12wmAAAAAElFTkSuQmCC", - "text/latex": [ - "$\\displaystyle \\frac{\\sqrt{2} \\sqrt{\\pi}}{2}$" - ], - "text/plain": [ - "√2⋅√π\n", - "─────\n", - " 2 " - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sym.integrate(sym.sin(x**2), (x, -sym.oo, sym.oo))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Find $\\lim_{x\\to 0}\\frac{\\sin{(x)}}{x}$." - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAOCAYAAAASVl2WAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAZElEQVQYGWP8//8/Aww0NDQYAdmrgdgYyP4AEmcBMgSA9GwgfgfEJkCsBMRwAFIAUhkKEgGyy4AUyBQ4YIKzcDBGFUACBj0chKHhJQQLN0ZQZAGDGBRBIOACxKC4OQfE94B4NwDm+hiAOyllRAAAAABJRU5ErkJggg==", - "text/latex": [ - "$\\displaystyle 1$" - ], - "text/plain": [ - "1" - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sym.limit(sym.sin(x)/x, x, 0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Solve $x^2 - 2 = 0$." - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAGMAAAAlCAYAAABWOlfkAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADa0lEQVRoBe2b4VEbMRCF7UwKIOkg0AGQDpwOYOgAOgiTX/a/TNKB0wJ0ENIB0EHoIIEOkvcxuoss3110trR3ZrQzGsnSWrv3nnb37gzT+Xx+MplMrtR8uVgsFt/8iTJOh4CwXWq382DHN1NHxpkUToPF8tEIAWH/KFPvXhnZK2YiEChkRIBkpVLIsEI6ws7rCJ1BVJRHD2X4Lta49Kexujn0Uvg7WjIE2Be1I13kfQ7wMuy5tb+jTFPulE12hYhU/o6SDJ3aT2qctF2RJP6Ojgydsn0xsK/+ZheYSOnvGGvGpUig1eIuuJo71sJvtUvNj6GeJPN3VGQI3D2BfKz+omLCEbFU/8GbI4XdMac2WATJdlJ/x5amAPlzBbrrmavJYU4gcBqf1MJ3aixbSlJ/R0OGO2Uz9dcBmjN9/unW/SUiYk/z1BhzyeHvaMgQmm13JID+oIsnEpqEVDGEJPfXpGYISF7TP6nvyu8nWj8IUdVc29tkntAnWk9exLXnIP5mJ0MX9lGYcYoe1I7U1sTpLNcWWiakDxGkp+oOq0Wz//SQ/mZNUw40fqSiHbrPTQjxY9bXpoWWOQr3dc/vtGz1b3pofzsjQ86Rj3+o9cnLp/rec+rweu6QqghZSTvS4RevPlGBLjVkZR/NbS1D+/s/Miiajamlz5XrIqkXRMe5ep6uSVmVkGqibOh7EPdWff3MUW2Sstf+g/ibNU0FAHFPjtR5XhdNoSTdQHqnON0D9XVEaAyx1I4cYu6vGRkCjWjgboroqNIehT18yFsDVvoU7PfqayKdEmTyaqQWb+96bpOB9jHx1/etM035ionGnLaZGoRwsbfqO6NC65x8CvaNxmFt4SGxLvwaQ/Kj+nu1qNQn/S7J6m9o2CwyMCyAiAyKOxFBq1KBhq3yXSsQQr0I2wqR2p/PkMyTOcRsJbn9DZ2zjgzsk5Y46dwRAVynSGftQbDrC+irkb5SSVZ/fSdNIwPDAop3T0RHmP9ZTiXUl5Wo2XRjI3+f3RsiMiAkRT5vxFd7k55+NS5uOJnTX98l88jwjWcac3NQF/VMNrJs++LI2FUiYPfFkZHlyBptWsgwAjrGTCEjBiUjnUKGEdAxZgoZMSgZ6RQyjICOMVPIiEHJSKd6AuePAf54Nsv/9HlgpB4Ka94+89JzRf4COMGPgdTQUmMAAAAASUVORK5CYII=", - "text/latex": [ - "$\\displaystyle \\left[ - \\sqrt{2}, \\ \\sqrt{2}\\right]$" - ], - "text/plain": [ - "[-√2, √2]" - ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sym.solve(sym.Eq(x**2 - 2,0), x)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Find the eigenvalues of $\\left[\\begin{smallmatrix}1 & 2\\\\2 & 2\\end{smallmatrix}\\right]$." - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/latex": [ - "$\\displaystyle \\left\\{ \\frac{3}{2} - \\frac{\\sqrt{17}}{2} : 1, \\ \\frac{3}{2} + \\frac{\\sqrt{17}}{2} : 1\\right\\}$" - ], - "text/plain": [ - "⎧3 √17 3 √17 ⎫\n", - "⎨─ - ───: 1, ─ + ───: 1⎬\n", - "⎩2 2 2 2 ⎭" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sym.Matrix([[1, 2], [2, 2]]).eigenvals()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Print $\\int_{0}^{\\pi} \\cos^{2}{\\left (x \\right )} dx$ using $\\mathrm{LaTeX}$." - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": { - "tags": [ - "disable-execution-cell" - ] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'\\\\int\\\\limits_{0}^{\\\\pi} \\\\cos^{2}{\\\\left(x \\\\right)}\\\\, dx'" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sym.latex(sym.Integral(sym.cos(x)**2, (x, 0, sym.pi)))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Gotchas\n", - "Trial and error is an approach for many programmers, but you may want to prevent frequently made mistakes. Take a look at SymPy's documentation on [gotchas](https://docs.sympy.org/latest/tutorials/intro-tutorial/gotchas.html) to accelerate your learning!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## References\n", - "```{bibliography}" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "mude", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.4" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/book/Python_Toolbox.md b/book/Python_Toolbox.md index 1154aeb..93b438f 100644 --- a/book/Python_Toolbox.md +++ b/book/Python_Toolbox.md @@ -1,41 +1,7 @@ -(toolbox)= # Python Toolbox -This page describes several ways to write and execute Python code, some of which don't require any installation on your computer and work entirely in a web browser! These approaches are described in the sections below, and are based on the tools IPython and Jupyter Notebooks. +% This page is a placeholder to ensure that links from previous years don't break. +% This works as long as `only_build_toc_files: false` (default) -**IPython** is an interactive Python interpreter that adds features that are useful for engineering, such as command history or inline display of figures. As you will see below, you can enter multiple lines of text and evaluate them at once; this is often referred to as a *cell* of code. In a nutshell, if you string many of these cells together into a single digital document, you more or less end up with a **Jupyter Notebook**; this leverages the power of IPython by allowing you to type, run and save the cells in any order, as well as type formatted text in between. Together, these two tools make up our toolbox for this course, and, as you will see, both of them can run in your internet browser, so there is no need to install special software! - -## Interactive Pages - -This course is powered by a special software (the [Sphinx-Thebe](https://github.com/executablebooks/sphinx-thebe) that allows you to run Python code in your browser and gives you an experience that is more or less identical the the "standard" Jupyter Notebook experience you would have on your own computer if you installed the dedicated software. You can access this tool by clicking on the rocket icon ({fa}`rocket`) at the top right of a page where this is enabled. - -(calculator)= -## IPython: Your Primary Python Calculator - -Below is an example of an IPython interpreter embedded in this webpage, which we refer to as our **Python Calculator**. Note that the square brackets with numbers (e.g, `[1]: ...`) are a feature of IPython that keeps track of the cells you have run: the first (pre-loaded) command is a print statement that executes once the interpreter is ready for use. You can try entering code yourself (for example, type `x=2`) and executing it using `Shift+Enter`. You just defined a variable! Note that typing `Enter` in the interpreter adds extra lines, it does not execute the cell. Try entering multiple lines, for example, `3*x`, `Enter` and `print(x)`, then execute. Can you tell what happened? - - - -The simple exercise above should be all you need to get started with this course. Throughout this course we encourage you to the Python Calculator in a new browser tab, which will allow you to read the exercise and run code side by side. You can test it here in a new tab. When the console is critical for completing the exercises in a certain chapter, a drop-down note will be added that includes a special link inside, just like this: - -`````{admonition} Open the Python Calculator for this page -:class: tip, dropdown -Click this link and wait until the message "You may begin!" is printed to start evaluating code. More information about this tool can be found [here](calculator). - -Remember that most pages in this course can also be run interactively using the {fa}rocket icon above (read more about it [here](toolbox)). -````` - -All exercises in this course can be completed using only the Python Calculator. We hope you find it to be a simple but useful way to practice and learn the Python programming language. - -```{note} -A special instance of the Python Calculator is set up for each page which pre-loads a few packages needed to complete the exercise. Make sure you use link that is on the page of the exercises you are working on. -``` - -## Anaconda: Python on Your Computer - -If you want to explore Python programming and Jupyter ecosystems beyond the exercises covered in this course, it might be worthwhile to install a Python distribution on your own computer. The most common and easiest way to do this is with [Anaconda](https://www.anaconda.com/download). Installation instructions are not included in this course, but you can find plenty of website of videos that cover this, as well as using the Anaconda Navigator to open a Jupyter Lab or Jupyter Notebook environment. Most of the pages in this online textbook can be downloaded in the form of a Jupyter Notebook file (a file ending with `.ipynb`): open it via one of the Jupyter environments and you are ready to go! \ No newline at end of file +```{include} ./toolbox.md +``` \ No newline at end of file diff --git a/book/Python_intro.md b/book/Python_intro.md index 20af2fa..3d88009 100644 --- a/book/Python_intro.md +++ b/book/Python_intro.md @@ -1,60 +1,7 @@ -# Introduction to Programming and Python +# Programming and Python -## Why do you need Python? - -Python is a computer programming language that is widely used in both academia and industries related to Civil Engineering, Environmental Engineering and Applied Earth Sciences. Being skilled in Python will help you on multiple occasions, including in your master courses. - -## What can computers do for us? -As an engineer or scientist, you will deal with units of information which are called data. The most important tasks that a computer can do for us are: - -1. Reading data -2. Processing data -3. Visualizing data - -These are tasks that require many repetitions and high precision. - -_1. Reading data_ -Reading data means the computer acquires data from a source and places it into its volatile memory for processing. Volatile memory keeps the data stored until the power supply is interrupted. The way data is stored in a computer determines how the computer will be able to use it. - -_2. Processing data_ -Data processing is the manipulation of the stored data in a system. After processing data by performing transformations, calculations, and more, you get an output; results. - -_3. Visualizing data_ -We map data (original or found) to graphic elements to communicate clearly and efficiently the information contained in the data. A graphic element is an element of a chart, such as a line or a point in the chart. - -## What is programming? - -Programming is giving your computer a list of instructions for computations in a language it can understand. In your case, this language is Python. A computation is a series of arithmetical ("math") and non-arithmetical ("non-math") steps that transform input to output (result). -There are five different kinds of instructions for computations you use. By ordering and combining them, the computer can achieve results that fulfill the three tasks described earlier. The five kinds of instructions are: - -input: - Insert data from a file, the network, other devices, or simply by typing it in. - -output: - Display data on the screen, save them in a file, send it over the network, etc. - -math: - Perform basic mathematical operations like addition and multiplication. - -conditional execution: - Check for certain conditions before further instruction. - -repetition: - Perform instructions repeatedly, usually with some variation. - - -## Introduction to Python - -The features of Python are what make it so popular. From the definition available on the corresponding Wiki page: "Python is an interpreted high-level general-purpose programming language. Its design philosophy emphasizes code readability with its use of significant indentation. Its language constructs, as well as its object-oriented approach aim to help programmers write clear, logical code for small and large-scale projects.". Quite a simple, yet concise description due to the meaning hidden behind each buzzword: - -
    -
  • Interpreted means that there is an interpreter, a software tool, which reads and performs instructions written in Python. If your laptop, phone, or refrigerator has the interpreter, it can run most of the Python scripts! -
  • High-level means that the programming language operates with abstract and more easily understandable concepts. In other words, you don't have to write or understand, code related to the hardware part of your machine (like binary code or assembly). -
  • General-purpose means that the amount of Python application fields are endless. You can write Python scripts to manage and automate some primitive tasks for yourself, you can use it for data science, create your own machine / deep learning project, write your personal web application or even develop a game. -
  • Programming language means a set of specific predefined semantics, instructions, and syntax rules, which are used for writing necessary instructions. It is strictly defined, meaning that 99.99% of all errors in the code are made by the coder, not by the computer. -
- -Python scripts run with the help of a Python interpreter, but they can be written by using different software tools. Just like as you write your essay (you can type it in Word, Google Docs, Overleaf, or even on plain paper) you can write your Python code with different editors. You could use the default notepad, notepad++, find a proper website with an inbuilt code editor & interpreter (IDEone, for example), or use specialized Python code editors (Spyder, PyCharm, Visual Studio, etc). In all cases you will produce a set of instructions, which are stored in a file with the *.py extension and the interpreter will run it completely (from top to bottom). - -For this course we will use a slightly different approach to developing a Python script: IPython and Jupyter Notebooks. Think of these as two freely-available tools that add extra functionality to the basic Python programming language. As an example, imagine the camera built into your phone: on it's own it can take pictures, but there are many apps that add filters or sharing via social media that make the impact of your photos much more powerful. This is exactly what IPython and Jupyter Notebooks do for Python, and why they are such important tools in the toolbox of modern engineers. The next Chapter will introduce you to your Python Toolbox for this course! +% This page is a placeholder to ensure that links from previous years don't break. +% This works as long as `only_build_toc_files: false` (default) +```{include} ./python.md +``` \ No newline at end of file diff --git a/book/_config.yml b/book/_config.yml index 7ccc258..52d9415 100644 --- a/book/_config.yml +++ b/book/_config.yml @@ -35,6 +35,7 @@ html: use_issues_button: true use_repository_button: true use_edit_page_button: true + use_multitoc_numbering: false # announcement: "⚠️ This is not the final version of the book! The new version will be ready by July 1.⚠️" extra_navbar: |
diff --git a/book/_toc.yml b/book/_toc.yml index bc82162..4bf4596 100644 --- a/book/_toc.yml +++ b/book/_toc.yml @@ -5,55 +5,171 @@ format: jb-book root: introduction.md parts: - caption: Introduction + numbered: false chapters: - file: intro.md title: Course Overview - - file: Python_intro.md + - file: python.md title: Programming and Python - - file: Python_Toolbox.md - - caption: Course Contents + - file: toolbox.md + - caption: "Part 1: Python Standard Library " + numbered: true chapters: - - file: 01/Theory/01.ipynb + - file: basics/intro.md + title: Basics sections: - - file: 01/Exercises/01.ipynb - - file: 02/Theory/01.ipynb + - file: basics/hello.ipynb + title: Your First Script + - file: basics/variables.ipynb + title: Variables + - file: basics/operators.ipynb + - file: basics/functions.ipynb + - file: basics/Exercises/01.ipynb + - file: flow/intro.md + title: Flow sections: - - file: 02/Exercises/01.ipynb - - file: 03/Theory/01.ipynb + - file: flow/conditions.ipynb + title: "Conditions: `if`" + - file: flow/structures.ipynb + - file: flow/loops.ipynb + - file: flow/Exercises/01.ipynb + - file: beyond/intro.md + title: Beyond the Basics sections: - - file: 03/Exercises/01.ipynb - - file: 04/Theory/01.ipynb + - file: beyond/strings.ipynb + title: Strings + - file: beyond/functions.ipynb + title: Functions + - file: beyond/files.ipynb + title: Files + - file: beyond/Exercises/01.ipynb + - file: objects/intro.md + title: Objects and References sections: - - file: 04/Exercises/01.ipynb - - file: 05/Theory/01.ipynb + - file: objects/object.ipynb + title: Objects and References + - file: objects/Exercises/01.ipynb + - file: modules/intro.md + title: Modules sections: - - file: 05/Exercises/01.ipynb - - file: 05/Exercises/02.ipynb - - file: 06/Theory/01.ipynb + - file: modules/modules.ipynb + title: Modules + - file: modules/Exercises/01.ipynb + - file: errors/intro.md + title: Errors sections: - - file: 06/Exercises/01.ipynb - - file: 07/Theory/01.ipynb + - file: errors/error_types.ipynb + - file: errors/traceback.ipynb + - file: errors/raise_errors.ipynb + - file: errors/handling_errors.ipynb + - file: errors/asserts.ipynb + - caption: "Part 2: Other Libraries" + numbered: true + chapters: + - file: numpy/intro.md + title: Numpy sections: - - file: 07/Exercises/01.ipynb - - file: 08/sympy - title: 8. SymPy - - file: 09/intro.md - title: 9. Errors + - file: numpy/introduction.ipynb + - file: numpy/1d.ipynb + - file: numpy/2d.ipynb + title: "Two-Dimensional arrays and matrices" + - file: numpy/Exercises/01.ipynb + title: "Exercise 1: Airplane velocity" + - file: numpy/Exercises/02.ipynb + title: "Exercise 2: Bending Moment on Bridge" + - file: pandas/intro.md + title: Pandas sections: - - file: 09/error_types.ipynb - - file: 09/traceback.ipynb - - file: 09/raise_errors.ipynb - - file: 09/handling_errors.ipynb - - file: 09/asserts.ipynb + - file: pandas/introduction.ipynb + title: "Introduction" + - file: pandas/series.ipynb + title: "Pandas Series" + - file: pandas/frame.ipynb + title: "Panda DataFrame" + - file: pandas/attributes.ipynb + title: "Data Importing and Attributes" + - file: pandas/statistics.ipynb + title: "Panda Statistics" + - file: pandas/Exercises/01.ipynb + - file: matplotlib/intro.md + title: Matplotlib + sections: + - file: matplotlib/introduction.ipynb + title: "Introduction" + - file: matplotlib/simple-plot.ipynb + title: "Simple Plot" + - file: matplotlib/customize.ipynb + title: "Customizing Plot" + - file: matplotlib/scatter.ipynb + title: "Scatter Plot" + - file: matplotlib/histograms.ipynb + title: "Histograms" + - file: matplotlib/subplots.ipynb + title: "Subplots" + - file: matplotlib/Exercises/01.ipynb + - file: sympy/intro.md + title: SymPy + sections: + - file: sympy/introduction.ipynb + title: "Introduction" + - file: sympy/variables.ipynb + title: "Variables, Expressions and Functions" + - file: sympy/expressions.ipynb + title: "Evaluating Expressions" + - caption: End of course survey + numbered: false chapters: - file: End-of-course-survey.md + - caption: In a Nutshell + numbered: 2 chapters: - - file: 01/In_a_Nutshell/01.ipynb - - file: 02/In_a_Nutshell/01.ipynb - - file: 03/In_a_Nutshell/01.ipynb - - file: 04/In_a_Nutshell/01.ipynb - - file: 05/In_a_Nutshell/01.ipynb - - file: 06/In_a_Nutshell/01.ipynb - - file: 07/In_a_Nutshell/01.ipynb + - file: basics/nutshell.md + title: Basics + sections: + - file: basics/nutshell/hello.ipynb + - file: basics/nutshell/variables.ipynb + - file: basics/nutshell/operators.ipynb + - file: basics/nutshell/functions.ipynb + - file: flow/nutshell.md + title: Flow + sections: + - file: flow/nutshell/conditions.ipynb + - file: flow/nutshell/structures.ipynb + - file: beyond/nutshell.md + title: Beyond the Basics + sections: + - file: beyond/nutshell/strings.ipynb + title: Strings + - file: beyond/nutshell/functions.ipynb + title: Functions + - file: beyond/nutshell/files.ipynb + title: Files + - file: objects/nutshell.md + title: Objects and References + sections: + - file: objects/nutshell/object.ipynb + title: Objects and References + - file: modules/nutshell.md + title: Modules + sections: + - file: modules/nutshell/modules.ipynb + title: Modules + - file: numpy/nutshell.md + title: Numpy + sections: + - file: numpy/nutshell/numpy.ipynb + title: Numpy + - file: pandas/nutshell.md + title: Pandas + sections: + - file: pandas/nutshell/introduction.ipynb + - file: pandas/nutshell/series.ipynb + - file: pandas/nutshell/frame.ipynb + - file: pandas/nutshell/attributes.ipynb + - file: matplotlib/nutshell.md + title: Matplotlib + sections: + - file: matplotlib/nutshell/object.ipynb + title: Matplotlib diff --git a/book/01/Exercises/01.ipynb b/book/basics/Exercises/01.ipynb similarity index 84% rename from book/01/Exercises/01.ipynb rename to book/basics/Exercises/01.ipynb index b6a14d2..3b3f700 100644 --- a/book/01/Exercises/01.ipynb +++ b/book/basics/Exercises/01.ipynb @@ -47,23 +47,6 @@ "#questions = [[q] for q in questions]" ] }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "Pq9kETciS3VO", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## Exercise 1.2.2\n", - "\n", - "\n" - ] - }, { "cell_type": "code", "execution_count": null, @@ -79,23 +62,6 @@ "# display_quiz(questions[0])" ] }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "cc546f8c", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## Exercise 1.2.3\n", - "\n", - "" - ] - }, { "cell_type": "code", "execution_count": null, @@ -122,7 +88,9 @@ } }, "source": [ - "## (Fixing) Exercise 1.2.4\n", + "\n", + "\n", + "## (Fixing) Exercise\n", "In the following exercise you will be using a piece of code, which was written by other people. It can contain concepts you haven't encountered yet but you need to practice with using code you don't understand completely. This is because you want to be able to use programs written by other people. Just like with calculators — if you add two numbers you get the result you expect to get. But you don't know exactly how that piece of plastics with electronic components performs that calculation.\n", "\n", "In order to approach the problem, start from the point of error. If your error cannot be solved there, work your way backwards through the code. Only try to understand the parts that are necessary to fix your problem, and avoid changing parts you know that work.\n", @@ -200,7 +168,8 @@ } }, "source": [ - "## (Searching) Exercise 1.2.5\n", + "\n", + "## (Searching) Exercise\n", "There are also other data types in Python, which were not mentioned in this part (in case they are not as useful or will be introduced later). For instance, Complex is one of them. The sad truth is that every software developer Googles a lot. It's not because she/he is lazy or incompetent. It is because programming languages are constantly updated and some tools are limited to a narrow field of applications. It is impractical to learn everything at once, therefore every coder has learned how to look up the functionality their task requires. Therefore, it is crucial for you to learn how to Google as well. Complex type is used in Python to represent complex numbers. If you haven't heard about them — a complex number is a number, which has a real and an imaginary part. For example, $x = 17 + 5i$. Here, $x$ is a complex number with a real part of $17$ and an imaginary part of $5$.\n", "\n", "Your task is to create a variable my_complex_number of Complex type and assign a $3 + 2i$ value to it. For that you will have to Google a bit. Try to look for something like \"Python complex variables\". Python is very popular and you will be able to find everything you need. Make sure to filter the information you need — not everything you will find will be useful for this simple exercise.\n" @@ -241,7 +210,8 @@ } }, "source": [ - "## Exercise 1.3.1\n", + "\n", + "## Exercise\n", "\n", "Given that we have a rectangle with a height of $3$ cm, width of $5$ cm and a cutout circle of radius $0.6$ cm, as shown below. \n", "\n", @@ -307,29 +277,6 @@ "#display_quiz(questions[4]+questions[5])" ] }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "rax0w6q5S3WF", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## Exercise 1.3.2\n" - ] - }, - { - "cell_type": "markdown", - "id": "0b0d21d9", - "metadata": {}, - "source": [ - "" - ] - }, { "cell_type": "code", "execution_count": null, diff --git a/book/01/Exercises/01.json b/book/basics/Exercises/01.json similarity index 100% rename from book/01/Exercises/01.json rename to book/basics/Exercises/01.json diff --git a/book/01/Exercises/01.png b/book/basics/Exercises/01.png similarity index 100% rename from book/01/Exercises/01.png rename to book/basics/Exercises/01.png diff --git a/book/basics/functions.ipynb b/book/basics/functions.ipynb new file mode 100644 index 0000000..1937843 --- /dev/null +++ b/book/basics/functions.ipynb @@ -0,0 +1,617 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "id": "116647f2", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "# Functions\n", + "\n", + "A function is a collection of code that is assigned to a specific name. You have already seen some built-in Python functions, such as print(). Using functions is useful because it allows you to run the same code again without having to type it a second time.\n", + "\n", + "Below are some examples of common built-in Python functions and what they do:\n", + "\n", + "\n", + "* ``print()``: Prints input to screen\n", + "* ``type()``: Returns the type of the input\n", + "* ``abs()``: Returns the absolute value of the input\n", + "* ``min()``: Returns the minimum value of the input. (input could be a list, tuple, etc.)\n", + "* ``max()``: Same as above, but returns the maximum value\n", + "* ``sum()``: Returns the sum of the input (input could be a list, tuple, etc.)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "But the story doesn't end at built-in functions. You can also write your own functions!\n", + "\n", + "### How to write a function\n", + "\n", + "To write a function, you must first define it. This is done by using the def statement. Then, you name the function and add, in the parentheses, which variables this function takes as an input, followed by a colon. The colon tells Python you are going to define the function body next (the part of the function that actually does the computation). As shown below:

\n", + "\n", + "
def function_name(input1, input2,...):
function_body
...
...
\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "242bb5c2", + "metadata": {}, + "source": [ + "\n", + "The calculate_circle_area(r) function below defines pi as a variable and then computes the area of a circle, which is stored in the variable area. Finally, it uses the return statement to output the area back to you. Once you have defined the function, you can then call it by typing the function name, and the inputs in the parenthesis. For example, calling: print(\"Hello World!\"), prints the string \"Hello World!\".\n", + "\n", + "Indentation
\n", + "\n", + "It is worth noting that the function body should be indented. This is how Python sees what piece of code is inside another code. An indented line of code is a line that starts with whitespace. You can do this by using the tab key on your keyboard." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "::: {note}\n", + "Inputs of functions are more often called arguments.\n", + ":::" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### indentation of code within functions\n", + "\n", + "Let's say you'd want to compute the area of a circle, but you don't want to calculate $\\pi r^2$ the entire time. Then you can write a couple lines of code to do it for you, and wrap it up into a function, like the one below:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [], + "source": [ + "def calculate_circle_area(r):\n", + " pi = 3.141592653589793\n", + " area = pi*(r**2)\n", + " return area" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "This function is called calculate_circle_area(r), and takes the value r as an argument." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Functions can have multiple arguments, for example:" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Area of my rectangle is 24 cm^2\n" + ] + } + ], + "source": [ + "def calculate_rectangle_area(a, b):\n", + " area = a * b\n", + " return area\n", + "\n", + "print('Area of my rectangle is', calculate_rectangle_area(4, 6), 'cm^2')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "In the cell above, the **`calculate_rectangle_area(a, b)`** function takes $2$ arguments, $a$ and $b$. \n", + "\n", + "The built-in function **`print()`** takes $3$ arguments:
\n", + "the string 'Area of my rectangle is', the output of calculate_rectangle_area(a, b), and another string 'cm^2'.\n", + "\n", + "There are better ways to use the built-in print() function when writing long sentences that have variables in between. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Area of my rectangle is 24 cm^2 and the area of my circle is 50.26548245743669 cm^2\n" + ] + } + ], + "source": [ + "print('Area of my rectangle is {} cm^2 and the area of my circle is {} cm^2'. \\\n", + " format(calculate_rectangle_area(4,6), calculate_circle_area(4)))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "If a line in your code extends the width of your page, you can use a **\\\\** at the point where you want to break the line, as shown above.\n", + "\n", + "Note that the variables (separated by commas) called inside the .format() will appear, in order, where the { } are located.\n", + "\n", + "Furthermore, you can also format how you want the numbers to appear, as shown below:" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Area of my rectangle is 24.00000 cm^2 and the area of my circle is 50.27 cm^2\n" + ] + } + ], + "source": [ + "print('Area of my rectangle is {:.5f} cm^2 and the area of my circle is {:.2f} cm^2'. \\\n", + " format(calculate_rectangle_area(4,6), calculate_circle_area(4)))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Where the :.5f states that you want to print that variable with $5$ decimal numbers. Similarly, :.2f rounds the number to $2$ decimal numbers. More information on this in Section 3.1, in Notebook 3." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### Documenting functions\n", + "We have now successfully created a function that computes the area of a circle and the area of a rectangle. You could send this code to fellow students, but maybe they wouldn't know how to use them. This is where a docstring comes in handy. This is a string specified in the beginning of the function body which states information about the function. A lot of built-in Python functions also have docstrings, which is really useful when you're trying to understand how to use a function." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Add a description to the calculate_circle_area(r) function below, as a docstring.
" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": false, + "solution": false + } + }, + "outputs": [], + "source": [ + "def calculate_circle_area(r):\n", + " '''This function calculate the area of a circle with radius r '''\n", + " pi_circle = 3.141592653589793\n", + " area = pi_circle*(r**2)\n", + " return area" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "As you can see, nothing happened. But, if we now call the function like this:\n", + "```\n", + "calculate_circle_area?\n", + "```\n", + "or:\n", + "```\n", + "help(calculate_circle_area)\n", + "```\n", + "we should see the description (docstring) of the function. Try yourself below:" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "collapsed": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on function calculate_circle_area in module __main__:\n", + "\n", + "calculate_circle_area(r)\n", + " This function calculate the area of a circle with radius r\n", + "\n" + ] + } + ], + "source": [ + "help(calculate_circle_area)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Now this isn't of much use when you work on your own code, unless you are very forgetful or have to write large programs.\n", + "But if you work using other people's code, this is really useful, as it helps you figure out how to use each function." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "#### When to write or use a function?\n", + "\n", + "You can use functions in your code when you have a specific piece of code that you need to use multiple times (e.g.: plotting something).

Often you will find you want to use an output from a function later on. To do this, you can assign a function to a variable. Let's say I want to use the area of a circle in a later calculation. Then you can store it in a variable like this:\n", + "\n", + "We stored the area of a circle that has a radius 4 in the variable ``Circle_Area``" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [], + "source": [ + "Circle_Area = calculate_circle_area(4)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Nothing happens, but the value of calculate_circle_area(4) is now stored in the variable Circle_Area. See below:" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "50.26548245743669\n" + ] + } + ], + "source": [ + "print(Circle_Area)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "We can see that the value was indeed stored.\n", + "\n", + "::: {warning}\n", + "Variables that are defined inside a function body can NOT be called from outside of the function. These variables are called local variables.\n", + ":::" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Take the variable **`pi_circle`** that we defined in the function **`calculate_circle_area()`**. If we try to print it:" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'pi_circle' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[52], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[39mprint\u001b[39m(pi_circle)\n", + "\u001b[1;31mNameError\u001b[0m: name 'pi_circle' is not defined" + ] + } + ], + "source": [ + "print(pi_circle)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "See, it doesn't work!\n", + "The error you get: NameError: name 'pi_circle' is not defined, means that you tried to call a variable that does not exist." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "93d877b3", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "## Additional study material:\n", + "\n", + "* Official Python Documentation - https://docs.python.org/3/tutorial/introduction.html\n", + "* https://realpython.com/python-variables/\n", + "* Think Python (2nd ed.) - Section 2\n", + "\n", + "* Official Python Documentation - https://docs.python.org/3/library/operator.html\n", + "* https://realpython.com/python-operators-expressions/\n", + "* Think Python (2nd ed.) - Sections 2 and 5\n", + "\n", + "* Official Python Documentation - https://docs.python.org/3/tutorial/controlflow.html#defining-functions\n", + "* https://realpython.com/defining-your-own-python-function/\n", + "* Think Python (2nd ed.) - Sections 3, 6 and 16" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### After this Notebook you should be able to:\n", + "\n", + "- understand why you need to learn Python\n", + "- create and re-assign new variables\n", + "- determine the type of a variable using `type()`\n", + "- slice strings\n", + "- perform simple math using arithmetic operators\n", + "- compare two or more variables\n", + "- check if a value, or element, exists in an object\n", + "- define a function, including its docstring" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "merged.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/book/basics/hello.ipynb b/book/basics/hello.ipynb new file mode 100644 index 0000000..f488772 --- /dev/null +++ b/book/basics/hello.ipynb @@ -0,0 +1,122 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "c0279304", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "## Your First Python Script\n", + "\n", + "So, it is time for your first Python script. It is located beneath.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "3d1f70cf", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "ee5c28c1-473e-4c2d-9a33-b15b51fffc5f" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello world!\n" + ] + } + ], + "source": [ + "# My First Python Script\n", + "message = 'Hello world!'\n", + "print(message)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "7a16f396", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "\n", + "`````{admonition} Let's break it down\n", + "\n", + "First line: # My First Python Script is a comment, which is used just to explain and/or put useful information about the code next to it. If you need to create a comment — just type a # symbol and write your text after it. The interpreter does nothing with it — the comments are there just as useful information for you or another reader.\n", + "\n", + "Second line: message = 'Hello world!' creates a variable called message and assigns the text literal (string) Hello world! to it, by using the operator = (equal sign). Variables are used to store all data you use in your code.\n", + "\n", + "Third line: print(message) calls the functionprint() and passes the variable message to it. A function is just a set of encapsulated code, which is tailored to perform a certain action. This specific function outputs the content of everything you pass to it. Since the variable message had a small line of text in it, the function print() outputs that message.\n", + "\n", + "This script is quite primitive and simple but it represents the main idea of programming in Python. You have data (which is stored in variables) and you perform an operation on it: by using the inbuilt print() function. In addition, you could create your own functions. \n", + "\n", + "`````" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "merged.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/book/basics/intro.md b/book/basics/intro.md new file mode 100644 index 0000000..6bfb436 --- /dev/null +++ b/book/basics/intro.md @@ -0,0 +1,6 @@ +# Basics + +This chapter is all about getting some of the basics under your belt! + +% a short overview for this chapter + diff --git a/book/basics/nutshell.md b/book/basics/nutshell.md new file mode 100644 index 0000000..62853e5 --- /dev/null +++ b/book/basics/nutshell.md @@ -0,0 +1,3 @@ +# Basics: in a Nutshell + +Nutshell. \ No newline at end of file diff --git a/book/basics/nutshell/functions.ipynb b/book/basics/nutshell/functions.ipynb new file mode 100644 index 0000000..1481425 --- /dev/null +++ b/book/basics/nutshell/functions.ipynb @@ -0,0 +1,182 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Functions " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In Python, a function is a block of code that can be reused multiple times throughout a program. Functions are useful for organizing and structuring code, and for breaking down complex tasks into smaller, more manageable pieces. " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Below are some examples of common built-in Python functions and what they do:\n", + "\n", + "\n", + "* ``print()`` Prints input to screen\n", + "* ``type()`` Returns the type of the input\n", + "* ``abs()`` Returns the absolute value of the input\n", + "* ``min()`` Returns the minimum value of the input. \n", + " (input could be a list, tuple, etc.)\n", + "* ``max()`` Same as above, but returns the maximum value\n", + "* ``sum()`` Returns the sum of the input \n", + " (input could be a list, tuple, etc.)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is a step-by-step guide on how to create any function in Python:\n", + "\n", + "**Step 1:** Define the function using the def keyword, followed by the function name, and a set of parentheses.\n", + "\n", + "**Step 2:** Define the code block that will be executed when the function is called. This code block should be indented underneath the function definition. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "def greet():\n", + " print(\"Hello, World!\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Step 3:** (Optional) Add parameters to the function, which are values that can be passed into the function when it is called. These parameters are defined within the parentheses of the function definition. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "def greet(name):\n", + " print(\"Hello, \" + name + \"!\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Step 4:** (Optional) Add a return statement to the function, which is used to return a value or an expression from the function. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "def add(x, y):\n", + " return x + y" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Step 5:** Call the function by using the function name, followed by a set of parentheses. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello, John Weller!\n" + ] + } + ], + "source": [ + "greet(\"John Weller\")\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Thus, to create and use the function we write it all in one cell as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello, John!\n", + "Hello, Mary Jane!\n" + ] + } + ], + "source": [ + "def greet(name):\n", + " print(\"Hello, \" + name + \"!\")\n", + "\n", + "greet(\"John\")\n", + "greet(\"Mary Jane\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this example, the function **greet()** is defined with one parameter **name**, the function is called twice, first with \"John\" as an **argument**, then with \"Mary\" as an **argument**, the function will print out a greeting message each time it's called --> the **input** of the created function is the argument and the **output** is the greeting message.\n", + "\n", + "Functions are essential to programming, they allow you to organize, structure and reuse your code in an efficient and readable way." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/basics/nutshell/hello.ipynb b/book/basics/nutshell/hello.ipynb new file mode 100644 index 0000000..c9f3dc5 --- /dev/null +++ b/book/basics/nutshell/hello.ipynb @@ -0,0 +1,117 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Your First Python Script\n", + "\n", + "```{tip}\n", + "This is an \"In a Nutshell\" page. For additional explanation, see the full page {doc}`here <../hello>`.\n", + "```" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Excuting a cell in python" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The print() function in Python is used to output or display text or other information on the screen. It can be used to display a string of text, the value of a variable, or the result of a calculation. The text or information that you want to display is passed as an argument inside the parenthesis of the print() function.\n", + "\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Print () command" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To execute a cell in Python, you can use the run command in Jupyter Notebook or press the \"Run\" button in the toolbar. You can also use the keyboard shortcut **Shift + Enter** to execute the cell. \n", + "\n", + "Lets start by excecuting our first code by printing the words 'Hello world'. Press **Shift+Enter** to run the cell below. You should see the output \"Hello, World!\" displayed below the cell. Notice that we have to write the sentence inside the quotation marks to indicate that the data is of string type. \n", + "\n", + "Alternatively, You can also execute the code by clicking on the Run button in the toolbar or by using the run command in the Jupyter Notebook." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello, world!\n" + ] + } + ], + "source": [ + "print ('Hello, world!')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, try to fill in your name and print the following sentence in the next cell: \n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "My name is _____\n" + ] + } + ], + "source": [ + "print ('My name is _____')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/basics/nutshell/operators.ipynb b/book/basics/nutshell/operators.ipynb new file mode 100644 index 0000000..dc96c89 --- /dev/null +++ b/book/basics/nutshell/operators.ipynb @@ -0,0 +1,387 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Operators \n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Arithmetic Operators\n", + "\n", + "| Math sign | Python sign | name |\n", + "| :-: | :-: |:-:|\n", + "| + | + | addition |\n", + "| - | - | subtraction |\n", + "| * | * | multiplication |\n", + "| / | / | division |\n", + "| ^ | ** | exponentiation |\n", + "| mod | % | modulus |\n", + "| | // | floor division |" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Arithmetic operators: These operators perform mathematical operations, such as addition, subtraction, multiplication, and division. Examples:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n", + "3\n", + "10\n", + "2.5\n", + "25\n" + ] + } + ], + "source": [ + "x = 5\n", + "y = 2\n", + "\n", + "print(x + y) # Output: 7 \n", + "print(x - y) # Output: 3\n", + "print(x * y) # Output: 10\n", + "print(x / y) # Output: 2.5\n", + "print(x**y) # output: 25\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Error codes in python" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When you run a Python script or code in a cell, the code is executed line by line, starting from the first line and moving down the code.\n", + "\n", + "If an error occurs, Python will stop executing the code at the line where the error occurs and will display an error message. The first line of the error will indicating the line number where the error occurred. This is often the most informative as it tells you where in your code the problem is. The last line in the error message will tell you what the problem in this line is." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The code results in a TypeError because you are trying to add a variable of type integer (a) to a variable of type string (b). In python, you can only add two variables of the same type. You can't add an int to a string.\n", + "If you want to concatenate the string and the int you can convert the int to string before adding them together. " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is an example:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0hello\n" + ] + } + ], + "source": [ + "a = 0\n", + "b = \"hello\"\n", + "c = str(a) + b\n", + "\n", + "print (c)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or you can use the format() method to insert the value of a into the string b." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "hello 5\n" + ] + } + ], + "source": [ + "a = 5\n", + "b = \"hello {}\"\n", + "c = b.format(a)\n", + "\n", + "print (c)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or you can use f-strings (formatted string literals) that are available from python 3.6 and above. You can show a nummerical output with any string you want using f-strings. The code you need to type for f-strings: **f ' text {output} '**. The output has to be inside the curly brackets --> { } " + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "hello 5\n" + ] + } + ], + "source": [ + "a = 5\n", + "b = \"hello\"\n", + "c = f\"{b} {a}\"\n", + "\n", + "print (c)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Comparison Operators
\n", + "\n", + "In Python, you often want to compare a value with another. For that, you use comparison operators.\n", + "\n", + "| Math sign | Python sign | Meaning |\n", + "| :-: | :-: | :-: |\n", + "| $=$ | $==$ | Equal to |\n", + "| $>$ | $>$ | Greater than |\n", + "| $<$ | $<$ | Less than |\n", + "| $\\geqslant$ | $>=$ | Greater than or equal to |\n", + "| $\\leqslant$ | $<=$ | Less than or equal to |\n", + "| $\\neq$ | $!=$ | Not equal to |" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Comparison operators: These operators compare two values and return a Boolean value (True or False). Examples:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n", + "True\n", + "False\n", + "True\n", + "False\n" + ] + } + ], + "source": [ + "x = 5\n", + "y = 2\n", + "print(x == y) # Output: False\n", + "print(x != y) # Output: True\n", + "print(x > y) # Output: True\n", + "print(x < y) # Output: False\n", + "print(x >= y) # Output: True\n", + "print(x <= y) # Output: False\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Control flow statements in Python" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are several control flow statements in Python that are used to control the flow of execution of a program. The most important ones are:" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**if** statement: The if statement is used to check a certain condition, and if the condition is true, the code within the if block will be executed. If the condition is false, the code within the if block will be skipped. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x is positive\n" + ] + } + ], + "source": [ + "x = 5\n", + "if x > 0:\n", + " print(\"x is positive\")\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**if-else** statement: The if-else statement is an extension of the if statement, which allows you to specify a block of code to be executed if the condition is true, and a different block of code to be executed if the condition is false. Example:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x is non-positive\n" + ] + } + ], + "source": [ + "x = -2\n", + "if x > 0:\n", + " print(\"x is positive\")\n", + "else:\n", + " print(\"x is non-positive\")\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**if-elif-else** statement: The if-elif-else statement is an extension of the if-else statement, which allows you to check multiple conditions and execute different code blocks based on the first condition that is true. This is how you use them: " + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x is zero\n", + "x2 is negative\n" + ] + } + ], + "source": [ + "x = 0\n", + "if x > 0:\n", + " print(\"x is positive\")\n", + "elif x == 0:\n", + " print(\"x is zero\")\n", + "else:\n", + " print(\"x is negative\")\n", + " \n", + "\n", + "x2 = -2\n", + "if x2 > 0:\n", + " print(\"x2 is positive\")\n", + "elif x2 == 0:\n", + " print(\"x2 is zero\")\n", + "else:\n", + " print(\"x2 is negative\")\n", + "\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Indexing" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Indexing is a method in Python to access individual elements in a list by their position. This is a fundamental feature of Python's list data structure, allowing you to retrieve specific elements from the list. Elements are stored in a sequential manner and can be accessed using their index (integer value indicating their position)." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/basics/nutshell/variables.ipynb b/book/basics/nutshell/variables.ipynb new file mode 100644 index 0000000..191c455 --- /dev/null +++ b/book/basics/nutshell/variables.ipynb @@ -0,0 +1,310 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python Variables" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Value\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In Python, a **value** is any data that can be stored in a variable. It can be a number (such as an integer or a float), a string (a sequence of characters), a Boolean (True or False), or other types of data. For example" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "x = 5 # x is a variable that holds an integer value of 5\n", + "y = \"Hello World\" # y is a variable that holds a string value of \"Hello World\"\n", + "z = True # z is a variable that holds a Boolean value of True" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Variable " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A **variable** is a container that holds a value, which is like a label or a name given to the value that is stored inside it. You can use variables to store values and then use them later in your code. You can also change the value of a variable at any time. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "x = 5 # x is a variable that holds an integer value of 5\n", + "x = x + 2 # x now holds the value of 7" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### String" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A string is a sequence of characters, enclosed in quotation marks. You can use strings to store text, such as words and sentences. You can also use them to display messages to the user or to create strings that hold specific data, like a name or an address. Strings are a very important data type in python and you will use it very frequently. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Hello World'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"Hello World\"" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### List" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A list in Python is a collection of values stored in a single object, similar to arrays in other programming languages. Lists can contain elements of any type, including numbers, strings, and other objects. \n", + "\n", + "To create a list in Python, you can use square bracket [ ] notation and include the values you want to store in the list, separated by commas.\n", + "\n", + "For a beginner, it's important to remember the following when creating lists in Python:\n", + "\n", + "* Lists start with a square bracket [ ]\n", + "* Values in the list are separated by commas\n", + "* Lists can contain elements of any type, including numbers, strings, and other objects." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3.14, 'Hello', True]\n" + ] + } + ], + "source": [ + "# create a list\n", + "my_list = [1, 2, 3.14, \"Hello\", True]\n", + "\n", + "# print the list\n", + "print(my_list)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Indexing in Python is a way to access specific elements in a list or array. Think of a list as a row of boxes, where each box contains a value. The index is the number assigned to each box [ ] and it allows us to locate a specific value or object. Lists in Python are zero-indexed, meaning that the first element in the list is stored at index 0, the second element is stored at index 1, and so on. For example, we an print any element in out created list by specifying the index releated:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "Hello\n", + "3.14\n" + ] + } + ], + "source": [ + "# access elements by index\n", + "print(my_list[0]) # prints the integer 1\n", + "print(my_list[3]) # prints the string \"Hello\"\n", + "print (my_list[2]) # prints the float 3.14" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## type () of data in python " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In Python, you can use the built-in type() function to determine the type of an object. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "\n" + ] + } + ], + "source": [ + "x = 5\n", + "print(type(x)) # Output: \n", + "\n", + "y = \"hello\"\n", + "print(type(y)) # Output: \n", + "\n", + "z = [1, 2, 3]\n", + "print(type(z)) # Output: " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also check an object's type very simply by:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "int" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x2 = 5\n", + "type(x2) # Output: int" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "str" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y2 = 'hello'\n", + "type(y2) # Output: str" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "list" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z2 = [1, 2, 3]\n", + "type(z2) # Output: list" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/basics/operators.ipynb b/book/basics/operators.ipynb new file mode 100644 index 0000000..b20b03d --- /dev/null +++ b/book/basics/operators.ipynb @@ -0,0 +1,603 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "Tpeh8gLqS3V4", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "# Operators\n", + "\n", + "Python operators are used to perform operations on variables and values. They are symbols that represent a form of computation; think of addition or multiplication. The value to which this computation is applied to is called the 'operand'. Most of the common operators you will recognize from mathematics." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "1yHso5KtS3WC", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "

Arithmetic Operators

\n", + "\n", + "| Math sign | Python sign | name |\n", + "| :-: | :-: |:-:|\n", + "| + | + | addition |\n", + "| - | - | subtraction |\n", + "| * | * | multiplication |\n", + "| / | / | division |\n", + "| ^ | ** | exponentiation |\n", + "| mod | % | modulus |\n", + "| | // | floor division |\n", + "\n", + "\n", + "
Most of the mathematical symbols stay the same when transforming a piece of mathematics to Python. Note that the exponentiation sign is a double multiplication sign!

\n", + "The last two operators, modulus and floor division, can be defined as the following:
\n", + "- modulus: return the remainder of a division
\n", + "- floor division: returns the integer/whole part of the division\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "Ijx03oCKS3WD", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Now we will provide some small examples\n", + "\n", + "a. multiply 4 by 3 and then add 2\n", + "\n", + "b. 2 to the power of 4 plus 1\n", + "\n", + "c. take the modulus of 352 over 23\n", + "\n", + "d. the floor division of 352 over 23\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "wOPRR9oLS3WD", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "d888e6de-7185-453a-a33e-dc2f38817e9f" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "14\n" + ] + } + ], + "source": [ + "a = 2 + 4 * 3\n", + "print(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "V50AuE4US3WD", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "d7518f7e-535f-4ea2-a233-06e71de779be" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "17\n" + ] + } + ], + "source": [ + "b = 2**4 + 1\n", + "print(b)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "a674y2ZoS3WE", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "2b8bfe90-f5db-40b7-beac-119d63142e3f" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n" + ] + } + ], + "source": [ + "c = 352 % 23\n", + "print(c)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Explanation: $352 = 15 \\times 23 + 7$, therefore the **modulus operator** returns the value $7$." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "15\n" + ] + } + ], + "source": [ + "d = 352 // 23\n", + "print(d)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Explanation: $352 = 15 \\times 23 + 7$, therefore the **floor division operator** returns the value $15$." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "w3HQ3fRHS3WE", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Besides making sure that you use the right operators when writing mathematical functions, it is also important that you pay attention to the order of operators. When not done right, this can cause huge changes in the outcome. Therefore, when writing out large equations it is easier to use parentheses or split it into multiple variables. e.g.:\n", + "\n", + "$$y = x\\tan\\theta - \\frac{1}{2v_0^2}\\frac{g x^2}{\\cos^2\\theta} + y_0$$\n", + "\n", + "You could split this equation into four distinct variables:\n", + "\n", + "1. var_1 $ = x\\tan\\theta$\n", + "2. var_2 $= \\frac{1}{2v_0^2}$\n", + "3. var_3 $= \\frac{g x^2}{\\cos^2\\theta}$\n", + "4. var_4 $= y_0$\n", + "\n", + "And then re-write it as ``y = var_1 - (var_2 * var_3) + var_4``" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "With parenthesis before = 18\n", + "With parenthesis after = 14\n" + ] + } + ], + "source": [ + "parenthesis_before = (2 + 4) * 3\n", + "print('With parenthesis before =',parenthesis_before)\n", + "parenthesis_after = 2 + (4 * 3)\n", + "print('With parenthesis after =',parenthesis_after)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "6vVTBKf2S3WF", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### Comparison Operators\n", + "\n", + "In Python, you often want to compare a value with another. For that, you use comparison operators.\n", + "\n", + "| Math sign | Python sign | Meaning |\n", + "| :-: | :-: | :-: |\n", + "| $=$ | ``==`` | Equal to |\n", + "| $>$ | ``>`` | Greater than |\n", + "| $>$ | ``<`` | Less than |\n", + "| $\\geqslant$ | ``>=`` | Greater than or equal to |\n", + "| $\\leqslant$ | ``<=`` | Less than or equal to |\n", + "| $\\neq$ | ``!=`` | Not equal to |" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "tYgJkAjkS3WF", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "#### Checking if a value corresponds to the set conditions\n", + "\n", + "Check if the the variable **`num`** satisfies the set condition." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "cwI6HOvCS3WF", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "8b6f1e68-f812-4758-b66c-8c1ece6e9885" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "num = 6\n", + "print(num > 2)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "rahfXQevS3WG", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "If the value does not satisfy the condition the system will return False" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "collapsed": true, + "id": "n3-STHSWS3WG", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "6796f022-fc31-4a4c-cb2e-9242d0be0761" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n" + ] + } + ], + "source": [ + "print(num > 7)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "k1fHyoR_S3WH", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "\n", + "### Logical & Identity Operators\n", + " \n", + " |sign|description|\n", + " |:-:|:-:|\n", + " |and|returns True if both statements are true|\n", + " |or|return True if at least 1 statements is true|\n", + " |not|reverse of the results; returns False if the statement is True|\n", + " |is|returns True if both variables are the same object|\n", + " |is not|returns True if both variables are not the same object|\n", + " |in|returns True if a sequence with the specified value is present in the object|\n", + " |in not|returns True if a sequence with the specified value is not present in the object|" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "z-vMNiI9S3WH", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "#### and statement\n", + "\n", + "By using the and statement you can set multiple conditions for the system to return. This can be seen as setting a boundary condition for a mathematical function." + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "collapsed": true, + "id": "C2nBS6w6S3WH", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "5ec763aa-a8d9-4a76-9442-c7d98a084b0e" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "num = 5\n", + "print(num > 4 and num < 8)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "jFLv4WxVS3WH", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "#### checking if a value appears in an object\n", + "\n", + "Suppose we have a string \"sandstone\", we can check if a value is present within the string through the following lines of code." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true, + "id": "y3hzxJlPS3WH", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "847bb1bc-e366-4e2d-e18a-7e08b54826b8" + }, + "outputs": [], + "source": [ + "rock_type = \"sandstone\"\n", + "print(\"sand\" in rock_type)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### is and == operators\n", + "\n", + "The is operator deserves a little more explanation since it can be easily confused with the == operator. The is statement does not compare the value of a variable but simply checks if two variables are the same object. On the other hand, == checks if the values of different variables are the same. In the underneath piece of code this is shown quite clearly. Although the values of the variables are the same, their type is not. Therefore, when compared using the is operator, it returns False." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " False\n", + "True\n" + ] + } + ], + "source": [ + "x = 2.0\n", + "y = 2\n", + "\n", + "print(type(x),type(y),x is y)\n", + "print(x == y)" + ] + }, + { + "cell_type": "markdown", + "id": "ccb91cbe", + "metadata": {}, + "source": [ + "
\n", + "\n", + "\n", + "**Exercise**\n", + "\n", + "\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "4eab3963", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "merged.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/book/01/Theory/01.ipynb b/book/basics/variables.ipynb similarity index 51% rename from book/01/Theory/01.ipynb rename to book/basics/variables.ipynb index c9fa375..5175a86 100644 --- a/book/01/Theory/01.ipynb +++ b/book/basics/variables.ipynb @@ -3,95 +3,7 @@ { "attachments": {}, "cell_type": "markdown", - "metadata": { - "id": "7vcVhbkFS81g", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "# 1. Variables, operators and functions. \n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "c0279304", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## 1.1 First Python Script\n", - "\n", - "So, it is time for your first Python script. It is located beneath.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "3d1f70cf", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "ee5c28c1-473e-4c2d-9a33-b15b51fffc5f" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Hello world!\n" - ] - } - ], - "source": [ - "# My First Python Script\n", - "message = 'Hello world!'\n", - "print(message)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "7a16f396", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "\n", - "`````{admonition} Let's break it down\n", - "\n", - "First line: # My First Python Script is a comment, which is used just to explain and/or put useful information about the code next to it. If you need to create a comment — just type a # symbol and write your text after it. The interpreter does nothing with it — the comments are there just as useful information for you or another reader.\n", - "\n", - "Second line: message = 'Hello world!' creates a variable called message and assigns the text literal (string) Hello world! to it, by using the operator = (equal sign). Variables are used to store all data you use in your code.\n", - "\n", - "Third line: print(message) calls the functionprint() and passes the variable message to it. A function is just a set of encapsulated code, which is tailored to perform a certain action. This specific function outputs the content of everything you pass to it. Since the variable message had a small line of text in it, the function print() outputs that message.\n", - "\n", - "This script is quite primitive and simple but it represents the main idea of programming in Python. You have data (which is stored in variables) and you perform an operation on it: by using the inbuilt print() function. In addition, you could create your own functions. \n", - "\n", - "`````" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", + "id": "d3bda27b", "metadata": { "id": "TcDyxZ7AS3Uz", "nbgrader": { @@ -101,7 +13,7 @@ } }, "source": [ - "## 1.2 Python Variables \n", + "# Python Variables \n", "\n", "One of the most powerful features of a programming language is the ability to create and manipulate\n", "variables. A variable is a labeled storage that refers to a value. They are usually used in a way to make the code more readable, allowing reusability of your code.

As it was mentioned previously, Python is a high-level programming language. For that, it uses concepts of Class and Object. In short, a Class is a defined model or a data structure, it describes how the data of that class can be described and how it can be manipulated, and an Object or Instance is its realization. In other words, think about your favorite meal: the recipe is the Class of your meal and when you decide to use the recipe and cook it — you create an Object of that Class. Variables are the way how objects are stored and processed.\n", @@ -123,6 +35,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "c96c7d6f", "metadata": { "id": "OLzFLmBnS3Uz", "nbgrader": { @@ -149,6 +62,7 @@ { "cell_type": "code", "execution_count": 2, + "id": "c92cf9b5", "metadata": { "collapsed": true, "id": "-oXjFB0TS3U0", @@ -166,6 +80,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "91acc4a0", "metadata": { "id": "loj_CSZ3S3U0", "nbgrader": { @@ -183,6 +98,7 @@ { "cell_type": "code", "execution_count": 3, + "id": "fbe8892d", "metadata": { "collapsed": true, "id": "-NydcpOmS3U0", @@ -212,6 +128,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "b46805d5", "metadata": { "id": "xPQ0wjwUS3U0", "nbgrader": { @@ -227,6 +144,7 @@ { "cell_type": "code", "execution_count": 2, + "id": "06b56dc7", "metadata": { "collapsed": true, "id": "q-fGZ0wMS3U0", @@ -253,6 +171,7 @@ { "cell_type": "code", "execution_count": 5, + "id": "bf1cbb92", "metadata": { "collapsed": true, "id": "d-6rzYcpS3U1", @@ -279,6 +198,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "69fb82fe", "metadata": { "id": "8CcorXSqS3U1", "nbgrader": { @@ -294,6 +214,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "8dd533b3", "metadata": { "id": "uqCmRVkbS3U1", "nbgrader": { @@ -309,6 +230,7 @@ { "cell_type": "code", "execution_count": 6, + "id": "e4eec9a4", "metadata": { "collapsed": true, "id": "QMktLeFOS3U2", @@ -338,6 +260,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "776cfb16", "metadata": { "id": "AjrlLAw7S3U2", "nbgrader": { @@ -353,6 +276,7 @@ { "cell_type": "code", "execution_count": 7, + "id": "30cae5d5", "metadata": { "collapsed": true, "id": "ho172OFAS3U2", @@ -370,6 +294,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "28a452f0", "metadata": { "id": "de87302a", "nbgrader": { @@ -388,6 +313,7 @@ { "cell_type": "code", "execution_count": 8, + "id": "48acc61b", "metadata": { "collapsed": true, "id": "tzz54psQS3U4", @@ -414,6 +340,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "b41ec95a", "metadata": { "id": "df4c695a", "nbgrader": { @@ -429,6 +356,7 @@ { "cell_type": "code", "execution_count": 9, + "id": "6808ada8", "metadata": { "collapsed": true, "id": "Sv2xzyhVS3U9", @@ -455,6 +383,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "925da5d8", "metadata": { "id": "gH1ebT4sS3VB", "nbgrader": { @@ -487,6 +416,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "abb0b8b6", "metadata": { "id": "87e243a7", "nbgrader": { @@ -502,6 +432,7 @@ { "cell_type": "code", "execution_count": 10, + "id": "5eb87d24", "metadata": { "collapsed": true, "id": "-DASPgHDS3VC", @@ -531,6 +462,7 @@ { "cell_type": "code", "execution_count": 11, + "id": "3d72cc72", "metadata": { "collapsed": true, "id": "151cff3a", @@ -561,6 +493,7 @@ { "cell_type": "code", "execution_count": 12, + "id": "20f7701a", "metadata": { "collapsed": true, "nbgrader": { @@ -588,6 +521,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "86ea9877", "metadata": { "nbgrader": { "grade": false, @@ -602,6 +536,7 @@ { "cell_type": "code", "execution_count": 13, + "id": "062d504b", "metadata": { "collapsed": true, "id": "ced9ae02", @@ -631,6 +566,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "2e0f2a7c", "metadata": { "id": "cbabd161", "nbgrader": { @@ -646,6 +582,7 @@ { "cell_type": "code", "execution_count": 14, + "id": "299ad533", "metadata": { "collapsed": true, "id": "6e138f75", @@ -684,6 +621,7 @@ { "cell_type": "code", "execution_count": 15, + "id": "f45bd312", "metadata": { "collapsed": true, "id": "4036bc6d", @@ -713,6 +651,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "0d9382ab", "metadata": { "id": "b358494d", "nbgrader": { @@ -728,6 +667,7 @@ { "cell_type": "code", "execution_count": 16, + "id": "5b5a621d", "metadata": { "collapsed": true, "id": "493e9703", @@ -757,6 +697,7 @@ { "cell_type": "code", "execution_count": 17, + "id": "31337e0d", "metadata": { "collapsed": true, "id": "9509e9ae", @@ -786,6 +727,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "f9e009e9", "metadata": { "id": "d378e554", "nbgrader": { @@ -801,6 +743,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "e68a979c", "metadata": { "id": "52be9a23", "nbgrader": { @@ -820,6 +763,7 @@ { "cell_type": "code", "execution_count": 18, + "id": "8996a258", "metadata": { "collapsed": true, "id": "00bd0987", @@ -849,6 +793,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "22086a55", "metadata": { "id": "7cc759c9", "nbgrader": { @@ -864,6 +809,7 @@ { "cell_type": "code", "execution_count": 19, + "id": "77741bfa", "metadata": { "collapsed": true, "id": "6f9dbc4a", @@ -893,6 +839,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "9223b088", "metadata": { "id": "27920277", "nbgrader": { @@ -908,6 +855,7 @@ { "cell_type": "code", "execution_count": 20, + "id": "4a4d5c55", "metadata": { "collapsed": true, "id": "11579009", @@ -938,6 +886,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "e2cd7ec3", "metadata": { "id": "5777fe12", "nbgrader": { @@ -953,6 +902,7 @@ { "cell_type": "code", "execution_count": 21, + "id": "07d03148", "metadata": { "collapsed": true, "id": "5a8eab89", @@ -982,6 +932,7 @@ { "cell_type": "code", "execution_count": 22, + "id": "0d7db87f", "metadata": { "collapsed": true, "id": "a2164ca2", @@ -1011,6 +962,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "1b859b5e", "metadata": { "id": "88633538", "nbgrader": { @@ -1032,6 +984,7 @@ { "cell_type": "code", "execution_count": 23, + "id": "cf2144a1", "metadata": { "collapsed": true, "id": "c65d21c0", @@ -1061,6 +1014,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "0a6fdb49", "metadata": { "id": "ac154077", "nbgrader": { @@ -1076,6 +1030,7 @@ { "cell_type": "code", "execution_count": 25, + "id": "3773b5db", "metadata": { "collapsed": true, "nbgrader": { @@ -1103,6 +1058,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "95ad1554", "metadata": { "id": "b5eea88c", "nbgrader": { @@ -1118,9 +1074,40 @@ "::: " ] }, + { + "cell_type": "markdown", + "id": "dcbb6e49", + "metadata": {}, + "source": [ + "
\n", + "\n", + "\n", + "**Exercise**\n", + "\n", + "\n", + "\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "8cf0a611", + "metadata": {}, + "source": [ + "
\n", + "\n", + "\n", + "**Exercise**\n", + "\n", + "\n", + "\n", + "
" + ] + }, { "attachments": {}, "cell_type": "markdown", + "id": "fd31c2ab", "metadata": { "nbgrader": { "grade": false, @@ -1137,6 +1124,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "e091e555", "metadata": { "nbgrader": { "grade": false, @@ -1158,6 +1146,7 @@ { "cell_type": "code", "execution_count": 26, + "id": "16b74e70", "metadata": { "collapsed": true, "nbgrader": { @@ -1186,6 +1175,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "26d6b482", "metadata": { "nbgrader": { "grade": false, @@ -1200,6 +1190,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "58d5a940", "metadata": { "nbgrader": { "grade": false, @@ -1219,6 +1210,7 @@ { "cell_type": "code", "execution_count": 27, + "id": "aba28f0a", "metadata": { "collapsed": true, "nbgrader": { @@ -1248,6 +1240,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "840f08d9", "metadata": { "nbgrader": { "grade": false, @@ -1262,6 +1255,7 @@ { "cell_type": "code", "execution_count": 28, + "id": "8bff7ddd", "metadata": { "collapsed": true, "nbgrader": { @@ -1290,6 +1284,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "3aa8df9b", "metadata": { "nbgrader": { "grade": false, @@ -1304,6 +1299,7 @@ { "cell_type": "code", "execution_count": 29, + "id": "e4ad06cb", "metadata": { "collapsed": true, "nbgrader": { @@ -1331,6 +1327,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "be585912", "metadata": { "nbgrader": { "grade": false, @@ -1347,6 +1344,7 @@ { "cell_type": "code", "execution_count": 30, + "id": "8a21987c", "metadata": { "collapsed": true, "nbgrader": { @@ -1374,6 +1372,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "4dc22754", "metadata": { "nbgrader": { "grade": false, @@ -1388,6 +1387,7 @@ { "cell_type": "code", "execution_count": 31, + "id": "f3ad92dc", "metadata": { "collapsed": true, "nbgrader": { @@ -1415,6 +1415,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "68a02c78", "metadata": { "nbgrader": { "grade": false, @@ -1429,6 +1430,7 @@ { "attachments": {}, "cell_type": "markdown", + "id": "6a14cb55", "metadata": { "nbgrader": { "grade": false, @@ -1446,1108 +1448,6 @@ "Searching exercises are exercises that purposefully incorporate subjects that were not covered yet, in an attempt to encourage you to try and solve issues you haven't learned about yet.\n", ":::" ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "Tpeh8gLqS3V4", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## 1.3 Python Operators\n", - "\n", - "Python operators are used to perform operations on variables and values. They are symbols that represent a form of computation; think of addition or multiplication. The value to which this computation is applied to is called the 'operand'. Most of the common operators you will recognize from mathematics." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "1yHso5KtS3WC", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "

Arithmetic Operators

\n", - "\n", - "| Math sign | Python sign | name |\n", - "| :-: | :-: |:-:|\n", - "| + | + | addition |\n", - "| - | - | subtraction |\n", - "| * | * | multiplication |\n", - "| / | / | division |\n", - "| ^ | ** | exponentiation |\n", - "| mod | % | modulus |\n", - "| | // | floor division |\n", - "\n", - "\n", - "
Most of the mathematical symbols stay the same when transforming a piece of mathematics to Python. Note that the exponentiation sign is a double multiplication sign!

\n", - "The last two operators, modulus and floor division, can be defined as the following:
\n", - "- modulus: return the remainder of a division
\n", - "- floor division: returns the integer/whole part of the division\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "Ijx03oCKS3WD", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Now we will provide some small examples\n", - "\n", - "a. multiply 4 by 3 and then add 2\n", - "\n", - "b. 2 to the power of 4 plus 1\n", - "\n", - "c. take the modulus of 352 over 23\n", - "\n", - "d. the floor division of 352 over 23\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "wOPRR9oLS3WD", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "d888e6de-7185-453a-a33e-dc2f38817e9f" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14\n" - ] - } - ], - "source": [ - "a = 2 + 4 * 3\n", - "print(a)" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "V50AuE4US3WD", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "d7518f7e-535f-4ea2-a233-06e71de779be" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "17\n" - ] - } - ], - "source": [ - "b = 2**4 + 1\n", - "print(b)" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "a674y2ZoS3WE", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "2b8bfe90-f5db-40b7-beac-119d63142e3f" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "7\n" - ] - } - ], - "source": [ - "c = 352 % 23\n", - "print(c)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Explanation: $352 = 15 \\times 23 + 7$, therefore the **modulus operator** returns the value $7$." - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "15\n" - ] - } - ], - "source": [ - "d = 352 // 23\n", - "print(d)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Explanation: $352 = 15 \\times 23 + 7$, therefore the **floor division operator** returns the value $15$." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "w3HQ3fRHS3WE", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Besides making sure that you use the right operators when writing mathematical functions, it is also important that you pay attention to the order of operators. When not done right, this can cause huge changes in the outcome. Therefore, when writing out large equations it is easier to use parentheses or split it into multiple variables. e.g.:\n", - "\n", - "$$y = x\\tan\\theta - \\frac{1}{2v_0^2}\\frac{g x^2}{\\cos^2\\theta} + y_0$$\n", - "\n", - "You could split this equation into four distinct variables:\n", - "\n", - "1. var_1 $ = x\\tan\\theta$\n", - "2. var_2 $= \\frac{1}{2v_0^2}$\n", - "3. var_3 $= \\frac{g x^2}{\\cos^2\\theta}$\n", - "4. var_4 $= y_0$\n", - "\n", - "And then re-write it as ``y = var_1 - (var_2 * var_3) + var_4``" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "With parenthesis before = 18\n", - "With parenthesis after = 14\n" - ] - } - ], - "source": [ - "parenthesis_before = (2 + 4) * 3\n", - "print('With parenthesis before =',parenthesis_before)\n", - "parenthesis_after = 2 + (4 * 3)\n", - "print('With parenthesis after =',parenthesis_after)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "6vVTBKf2S3WF", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### Comparison Operators\n", - "\n", - "In Python, you often want to compare a value with another. For that, you use comparison operators.\n", - "\n", - "| Math sign | Python sign | Meaning |\n", - "| :-: | :-: | :-: |\n", - "| $=$ | ``==`` | Equal to |\n", - "| $>$ | ``>`` | Greater than |\n", - "| $>$ | ``<`` | Less than |\n", - "| $\\geqslant$ | ``>=`` | Greater than or equal to |\n", - "| $\\leqslant$ | ``<=`` | Less than or equal to |\n", - "| $\\neq$ | ``!=`` | Not equal to |" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "tYgJkAjkS3WF", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "#### Checking if a value corresponds to the set conditions\n", - "\n", - "Check if the the variable **`num`** satisfies the set condition." - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "cwI6HOvCS3WF", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "8b6f1e68-f812-4758-b66c-8c1ece6e9885" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "True\n" - ] - } - ], - "source": [ - "num = 6\n", - "print(num > 2)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "rahfXQevS3WG", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "If the value does not satisfy the condition the system will return False" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": { - "collapsed": true, - "id": "n3-STHSWS3WG", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "6796f022-fc31-4a4c-cb2e-9242d0be0761" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "False\n" - ] - } - ], - "source": [ - "print(num > 7)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "k1fHyoR_S3WH", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "\n", - "### Logical & Identity Operators\n", - " \n", - " |sign|description|\n", - " |:-:|:-:|\n", - " |and|returns True if both statements are true|\n", - " |or|return True if at least 1 statements is true|\n", - " |not|reverse of the results; returns False if the statement is True|\n", - " |is|returns True if both variables are the same object|\n", - " |is not|returns True if both variables are not the same object|\n", - " |in|returns True if a sequence with the specified value is present in the object|\n", - " |in not|returns True if a sequence with the specified value is not present in the object|" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "z-vMNiI9S3WH", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "#### and statement\n", - "\n", - "By using the and statement you can set multiple conditions for the system to return. This can be seen as setting a boundary condition for a mathematical function." - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": { - "collapsed": true, - "id": "C2nBS6w6S3WH", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "5ec763aa-a8d9-4a76-9442-c7d98a084b0e" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "True\n" - ] - } - ], - "source": [ - "num = 5\n", - "print(num > 4 and num < 8)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "jFLv4WxVS3WH", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "#### checking if a value appears in an object\n", - "\n", - "Suppose we have a string \"sandstone\", we can check if a value is present within the string through the following lines of code." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true, - "id": "y3hzxJlPS3WH", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "outputId": "847bb1bc-e366-4e2d-e18a-7e08b54826b8" - }, - "outputs": [], - "source": [ - "rock_type = \"sandstone\"\n", - "print(\"sand\" in rock_type)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### is and == operators\n", - "\n", - "The is operator deserves a little more explanation since it can be easily confused with the == operator. The is statement does not compare the value of a variable but simply checks if two variables are the same object. On the other hand, == checks if the values of different variables are the same. In the underneath piece of code this is shown quite clearly. Although the values of the variables are the same, their type is not. Therefore, when compared using the is operator, it returns False." - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " False\n", - "True\n" - ] - } - ], - "source": [ - "x = 2.0\n", - "y = 2\n", - "\n", - "print(type(x),type(y),x is y)\n", - "print(x == y)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## 1.4 Python Functions\n", - "\n", - "A function is a collection of code that is assigned to a specific name. You have already seen some built-in Python functions, such as print(). Using functions is useful because it allows you to run the same code again without having to type it a second time.\n", - "\n", - "Below are some examples of common built-in Python functions and what they do:\n", - "\n", - "\n", - "* ``print()``: Prints input to screen\n", - "* ``type()``: Returns the type of the input\n", - "* ``abs()``: Returns the absolute value of the input\n", - "* ``min()``: Returns the minimum value of the input. (input could be a list, tuple, etc.)\n", - "* ``max()``: Same as above, but returns the maximum value\n", - "* ``sum()``: Returns the sum of the input (input could be a list, tuple, etc.)\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "But the story doesn't end at built-in functions. You can also write your own functions!\n", - "\n", - "### How to write a function\n", - "\n", - "To write a function, you must first define it. This is done by using the def statement. Then, you name the function and add, in the parentheses, which variables this function takes as an input, followed by a colon. The colon tells Python you are going to define the function body next (the part of the function that actually does the computation). As shown below:

\n", - "\n", - "
def function_name(input1, input2,...):
function_body
...
...
\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "242bb5c2", - "metadata": {}, - "source": [ - "\n", - "The calculate_circle_area(r) function below defines pi as a variable and then computes the area of a circle, which is stored in the variable area. Finally, it uses the return statement to output the area back to you. Once you have defined the function, you can then call it by typing the function name, and the inputs in the parenthesis. For example, calling: print(\"Hello World!\"), prints the string \"Hello World!\".\n", - "\n", - "Indentation
\n", - "\n", - "It is worth noting that the function body should be indented. This is how Python sees what piece of code is inside another code. An indented line of code is a line that starts with whitespace. You can do this by using the tab key on your keyboard." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "::: {note}\n", - "Inputs of functions are more often called arguments.\n", - ":::" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### indentation of code within functions\n", - "\n", - "Let's say you'd want to compute the area of a circle, but you don't want to calculate $\\pi r^2$ the entire time. Then you can write a couple lines of code to do it for you, and wrap it up into a function, like the one below:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [], - "source": [ - "def calculate_circle_area(r):\n", - " pi = 3.141592653589793\n", - " area = pi*(r**2)\n", - " return area" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "This function is called calculate_circle_area(r), and takes the value r as an argument." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Functions can have multiple arguments, for example:" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Area of my rectangle is 24 cm^2\n" - ] - } - ], - "source": [ - "def calculate_rectangle_area(a, b):\n", - " area = a * b\n", - " return area\n", - "\n", - "print('Area of my rectangle is', calculate_rectangle_area(4, 6), 'cm^2')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "In the cell above, the **`calculate_rectangle_area(a, b)`** function takes $2$ arguments, $a$ and $b$. \n", - "\n", - "The built-in function **`print()`** takes $3$ arguments:
\n", - "the string 'Area of my rectangle is', the output of calculate_rectangle_area(a, b), and another string 'cm^2'.\n", - "\n", - "There are better ways to use the built-in print() function when writing long sentences that have variables in between. For example:" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Area of my rectangle is 24 cm^2 and the area of my circle is 50.26548245743669 cm^2\n" - ] - } - ], - "source": [ - "print('Area of my rectangle is {} cm^2 and the area of my circle is {} cm^2'. \\\n", - " format(calculate_rectangle_area(4,6), calculate_circle_area(4)))" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "If a line in your code extends the width of your page, you can use a **\\\\** at the point where you want to break the line, as shown above.\n", - "\n", - "Note that the variables (separated by commas) called inside the .format() will appear, in order, where the { } are located.\n", - "\n", - "Furthermore, you can also format how you want the numbers to appear, as shown below:" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Area of my rectangle is 24.00000 cm^2 and the area of my circle is 50.27 cm^2\n" - ] - } - ], - "source": [ - "print('Area of my rectangle is {:.5f} cm^2 and the area of my circle is {:.2f} cm^2'. \\\n", - " format(calculate_rectangle_area(4,6), calculate_circle_area(4)))" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Where the :.5f states that you want to print that variable with $5$ decimal numbers. Similarly, :.2f rounds the number to $2$ decimal numbers. More information on this in Section 3.1, in Notebook 3." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### Documenting functions\n", - "We have now successfully created a function that computes the area of a circle and the area of a rectangle. You could send this code to fellow students, but maybe they wouldn't know how to use them. This is where a docstring comes in handy. This is a string specified in the beginning of the function body which states information about the function. A lot of built-in Python functions also have docstrings, which is really useful when you're trying to understand how to use a function." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Add a description to the calculate_circle_area(r) function below, as a docstring.
" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": false, - "solution": false - } - }, - "outputs": [], - "source": [ - "def calculate_circle_area(r):\n", - " '''This function calculate the area of a circle with radius r '''\n", - " pi_circle = 3.141592653589793\n", - " area = pi_circle*(r**2)\n", - " return area" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "As you can see, nothing happened. But, if we now call the function like this:\n", - "```\n", - "calculate_circle_area?\n", - "```\n", - "or:\n", - "```\n", - "help(calculate_circle_area)\n", - "```\n", - "we should see the description (docstring) of the function. Try yourself below:" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": { - "collapsed": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Help on function calculate_circle_area in module __main__:\n", - "\n", - "calculate_circle_area(r)\n", - " This function calculate the area of a circle with radius r\n", - "\n" - ] - } - ], - "source": [ - "help(calculate_circle_area)\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Now this isn't of much use when you work on your own code, unless you are very forgetful or have to write large programs.\n", - "But if you work using other people's code, this is really useful, as it helps you figure out how to use each function." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "#### When to write or use a function?\n", - "\n", - "You can use functions in your code when you have a specific piece of code that you need to use multiple times (e.g.: plotting something).

Often you will find you want to use an output from a function later on. To do this, you can assign a function to a variable. Let's say I want to use the area of a circle in a later calculation. Then you can store it in a variable like this:\n", - "\n", - "We stored the area of a circle that has a radius 4 in the variable ``Circle_Area``" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [], - "source": [ - "Circle_Area = calculate_circle_area(4)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Nothing happens, but the value of calculate_circle_area(4) is now stored in the variable Circle_Area. See below:" - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "50.26548245743669\n" - ] - } - ], - "source": [ - "print(Circle_Area)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "We can see that the value was indeed stored.\n", - "\n", - "::: {warning}\n", - "Variables that are defined inside a function body can NOT be called from outside of the function. These variables are called local variables.\n", - ":::" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Take the variable **`pi_circle`** that we defined in the function **`calculate_circle_area()`**. If we try to print it:" - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'pi_circle' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[52], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[39mprint\u001b[39m(pi_circle)\n", - "\u001b[1;31mNameError\u001b[0m: name 'pi_circle' is not defined" - ] - } - ], - "source": [ - "print(pi_circle)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "See, it doesn't work!\n", - "The error you get: NameError: name 'pi_circle' is not defined, means that you tried to call a variable that does not exist." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## Additional study material:\n", - "\n", - "* Official Python Documentation - https://docs.python.org/3/tutorial/introduction.html\n", - "* https://realpython.com/python-variables/\n", - "* Think Python (2nd ed.) - Section 2\n", - "\n", - "* Official Python Documentation - https://docs.python.org/3/library/operator.html\n", - "* https://realpython.com/python-operators-expressions/\n", - "* Think Python (2nd ed.) - Sections 2 and 5\n", - "\n", - "* Official Python Documentation - https://docs.python.org/3/tutorial/controlflow.html#defining-functions\n", - "* https://realpython.com/defining-your-own-python-function/\n", - "* Think Python (2nd ed.) - Sections 3, 6 and 16" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### After this Notebook you should be able to:\n", - "\n", - "- understand why you need to learn Python\n", - "- create and re-assign new variables\n", - "- determine the type of a variable using `type()`\n", - "- slice strings\n", - "- perform simple math using arithmetic operators\n", - "- compare two or more variables\n", - "- check if a value, or element, exists in an object\n", - "- define a function, including its docstring" - ] } ], "metadata": { diff --git a/book/03/Exercises/01.ipynb b/book/beyond/Exercises/01.ipynb similarity index 100% rename from book/03/Exercises/01.ipynb rename to book/beyond/Exercises/01.ipynb diff --git a/book/beyond/files.ipynb b/book/beyond/files.ipynb new file mode 100644 index 0000000..779bad2 --- /dev/null +++ b/book/beyond/files.ipynb @@ -0,0 +1,321 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Beyond the Basics: Working with Files\n", + "\n", + "A lot of the work you'll do in Python will have the following structure:\n", + "1. Read data from a file\n", + "2. Perform computations on the data\n", + "3. Visualize the results and/or save the results to a file\n", + "\n", + "So far, we have only learned about computations. So let's learn a bit about how to manage files. Actually, opening or saving files is usually done with the help of modules which you will learn in more detail in Notebook 4 and 6. What we'll discuss here is how to manage file paths.\n", + "\n", + "### File paths\n", + "\n", + "To learn how to use files we need to learn how file paths in computers work. If you are tech-savvy and know how file paths work you can skip this part.\n", + "\n", + "File paths in computers work like a tree. They start at the root directory, which is often the C: drive (in Windows). This is the name of the hard drive that stores your Operating System. From the C: drive you can navigate into other directories. This is done using the **``\\``** character, however in other Operating Systems often the / delimiter is used.\n", + "\n", + "If a file is in the folder Users, which is stored in the C: directory, the file path would be C:\\Users. These types of file paths are called absolute paths. This file path is valid for most computers that run Windows, but some other Operating Systems may have different folder setups. This is why it is useful to use relative paths. Relative paths do not start from the root directory. Instead, they start from the directory you are currently in. By default, Jupyter Notebooks are stored in C:\\Users\\CurrentUser (where CurrentUser is your Windows username). To move into a directory using a relative path, for example, to the desktop folder, you would just write .\\Desktop. To move back a directory, using a relative path, you would type ..\n", + "\n", + "`os.listdir()` or `os.listdir('./')` list all the entries in your current directory `os.listdir('../')` list all entries if we go back one level. \n", + "\n", + ":::{note}\n", + "We use the `/` as delimiter, since a `\\` won't work on macOS\n", + ":::" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['01.ipynb']\n", + "['01.ipynb']\n", + "['Exercises', 'In_a_Nutshell', 'Theory']\n" + ] + } + ], + "source": [ + "import os\n", + "\n", + "print(os.listdir())\n", + "print(os.listdir('./'))\n", + "\n", + "print(os.listdir('../'))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + ":::{warning}\n", + "Keep in mind that, in Python, all file paths must be strings!\n", + ":::" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### ``pathlib`` and os modules\n", + "\n", + "These modules are very useful in managing and navigating your file paths. The function path.expanduser('~'), from the os module, allows you to find your root directory, independent of your Operating System. Try the below cell to see it." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "C:\\Users\\mmendozalugo\n" + ] + } + ], + "source": [ + "from pathlib import Path\n", + "import os\n", + "\n", + "root_path = os.path.expanduser('~')\n", + "print(root_path)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "The path shown above is thus the absolute path to your current directory.\n", + "\n", + "This can come in handy when you write a code that needs to create directories in the user's computer to save data files and/or plots. As an example, the code below checks if a directory exists and, if it doesn't, it creates one.\n", + "\n", + "The `os.path.join` is used to concatenate two strings to form a path string with the appropriate delimiter.\n", + "\n", + "The code will check if a directory named `plots` exists in your current directory if not, it will create one." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print('Contents of current directory (before):')\n", + "print(os.listdir(root_path))\n", + "\n", + "imdir = os.path.join(root_path,'plots') \n", + "print(f'\\nimdir = {imdir}')\n", + "\n", + "Path(imdir).mkdir(parents=True, exist_ok=True)\n", + "\n", + "print('\\nContents of current directory (after creating the new directory):')\n", + "print(os.listdir(root_path))\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "tags": [ + "remove-input" + ] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Contents of current directory (before):\n", + "['Exercises', 'In_a_Nutshell', 'Theory']\n", + "imdir = C:\\Users\\mmendozalugo\\plots\n", + "\n", + "Contents of current directory (after creating the new directory):\n", + "['Exercises', 'In_a_Nutshell', 'plots', 'Theory']\n" + ] + } + ], + "source": [ + "root_path = r'C:\\Users\\mmendozalugo\\OneDrive\\PhD\\Work\\Python_MOOC\\PM\\learn-python\\book\\03'\n", + "\n", + "print('Contents of current directory (before):')\n", + "print(os.listdir(root_path))\n", + "\n", + "imdir = os.path.join(root_path,'plots') \n", + "print('imdir = ',r'C:\\Users\\mmendozalugo\\plots')\n", + "\n", + "Path(imdir).mkdir(parents=True, exist_ok=True)\n", + "\n", + "print('\\nContents of current directory (after creating the new directory):')\n", + "print(os.listdir(root_path))\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To delete the folder that was just created we run the code bellow." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " os.rmdir(imdir)\n", + " print(f'Directory {imdir} has been deleted.')\n", + "except:\n", + " print('You already deleted the folder. :)')" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "tags": [ + "remove-input" + ] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Directory C:\\Users\\mmendozalugo\\plots has been deleted.\n" + ] + } + ], + "source": [ + "print('Directory', r'C:\\Users\\mmendozalugo\\plots','has been deleted.')\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Now you are, hopefully, a bit more used to working with file paths. For the next test, we are going to try to open a file. We can use some built-in Python functions to open a *.txt file and print its contents." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Additional study material\n", + "\n", + "* Official Python Documentation - https://docs.python.org/3/tutorial/inputoutput.html\n", + "* https://realpython.com/python-f-strings/\n", + "* Official Python Documentation - https://docs.python.org/3/reference/expressions.html\n", + "* https://realpython.com/python-lambda/\n", + "* Official Python Documentation - https://docs.python.org/3/library/filesys.html\n", + "* https://realpython.com/working-with-files-in-python/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "After this Notebook you should be able to:\n", + "\n", + "- print a variable, formatting it in an appropriate manner\n", + "- know the existence of escape characters\n", + "- know how to use lambda functions\n", + "- understand how file paths work\n", + "- create and delete new directories \n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/beyond/functions.ipynb b/book/beyond/functions.ipynb new file mode 100644 index 0000000..85ed334 --- /dev/null +++ b/book/beyond/functions.ipynb @@ -0,0 +1,106 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "# Beyond the Basics: Functions\n", + "\n", + "Sometimes you want to use the same code multiple times, so you could embed this code into a function. However, sometimes the code you want to use is so short that putting it into a function feels a bit over the top. This is where lambda functions are useful.

Lambda functions are functions that can take any number of arguments but can only have one expression in their function body. To demonstrate, see the code below. Here we have two functions that do exactly the same, but one is a lambda function and the other one is a normal function. " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The square root of 16 is equal to 4\n", + "The square root of 16 is equal to 4\n" + ] + } + ], + "source": [ + "sqrt_lambda = lambda x : x**0.5\n", + "\n", + "def sqrt(x):\n", + " sqrt = x**0.5\n", + " return sqrt\n", + "\n", + "print(f\"The square root of 16 is equal to {sqrt_lambda(16):.0f}\")\n", + "print(f\"The square root of 16 is equal to {sqrt(16):.0f}\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "
\n", + "As you can see, the lambda version is much more concise. It automatically returns the computed value for you as well." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/beyond/intro.md b/book/beyond/intro.md new file mode 100644 index 0000000..0e8304f --- /dev/null +++ b/book/beyond/intro.md @@ -0,0 +1,6 @@ +# Beyond the Basics + +This chapter extends some of the topics we have covered in previous chapters, for example: strings, functions, while adding a new topic about working with files. + +% a short overview for this chapter + diff --git a/book/beyond/nutshell.md b/book/beyond/nutshell.md new file mode 100644 index 0000000..faeb78a --- /dev/null +++ b/book/beyond/nutshell.md @@ -0,0 +1,3 @@ +# Advanced Techniques: in a Nutshell + +Nutshell. \ No newline at end of file diff --git a/book/beyond/nutshell/files.ipynb b/book/beyond/nutshell/files.ipynb new file mode 100644 index 0000000..9066e50 --- /dev/null +++ b/book/beyond/nutshell/files.ipynb @@ -0,0 +1,134 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Beyond the Basics: Working with Files\n", + "\n", + "A lot of the work you'll do in Python will have the following structure:\n", + "1. Read data from a file\n", + "2. Perform computations on the data\n", + "3. Visualize the results and/or save the results to a file" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### File paths\n", + "File paths on computers work based on a hierarchical structure, often represented as a tree. The root directory serves as the starting point, typically represented by a drive letter (e.g., C: on Windows). From the root directory, you can navigate to other directories using a delimiter character (\\ on Windows or / on Unix-based systems). Each directory can contain files and subdirectories, forming a hierarchical structure.\n", + "\n", + "Absolute paths specify the complete path from the root directory, while relative paths are relative to the current working directory. By understanding and manipulating file paths, you can effectively locate and access files and directories on a computer's file system." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ``pathlib`` and os modules\n", + "\n", + "The os module in Python provides functions for interacting with the operating system, offering operations related to file management, directory handling, process management, and environment variables. It allows you to perform tasks such as creating, deleting, and modifying files and directories, launching external processes, accessing and modifying environment variables, and writing platform-independent code.\n", + "\n", + "On the other hand, the pathlib module introduced in Python 3.4 offers an object-oriented approach to working with file paths and directories. It provides the Path class, which represents paths as objects, allowing for more intuitive and expressive manipulation of paths compared to the traditional string-based operations in os. With pathlib, you can perform operations like joining paths, checking file existence, accessing file attributes, and creating directories in a more convenient and readable manner.\n", + "\n", + "The table below summuraizes some codes you can use for creating and adjusting your own file paths:" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| Code | Result | Description |\n", + "|------|--------|-------------|\n", + "| `os.path.join(path, *paths)` | Path string | Joins one or more path components intelligently. It concatenates the arguments using the appropriate path delimiter for the operating system. |\n", + "| `os.path.abspath(path)` | Absolute path string | Returns the absolute path of the specified path. It resolves any symbolic links and references to parent directories. |\n", + "| `os.path.exists(path)` | Boolean | Checks if the specified path exists in the file system. Returns `True` if the path exists, and `False` otherwise. |\n", + "| `os.path.isdir(path)` | Boolean | Checks if the specified path is a directory. Returns `True` if the path is a directory, and `False` otherwise. |\n", + "| `os.path.isfile(path)` | Boolean | Checks if the specified path is a regular file. Returns `True` if the path is a file, and `False` otherwise. |\n", + "| `os.path.splitext(path)` | Tuple (base, ext) | Splits the specified path into its base name and extension. Returns a tuple where the first element is the base name and the second element is the extension (including the dot). |\n", + "| `os.path.basename(path)` | Base name string | Returns the base name (the file or directory name) from the specified path. |\n", + "| `os.path.dirname(path)` | Directory name string | Returns the directory name from the specified path. |\n", + "\n", + "Here are some examples of how to use these codes: " + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Path: folder\\subfolder\\file.txt\n", + "Absolute Path: c:\\Users\\ahmed\\Documents\\GitHub\\learn-python\\book\\03\\In_a_Nutshell\\folder\\subfolder\\file.txt\n", + "Exists: False\n", + "Is Directory: False\n", + "Is File: False\n", + "Base Name: file.txt\n", + "Directory Name: folder\\subfolder\n", + "Extension: .txt\n" + ] + } + ], + "source": [ + "import os\n", + "\n", + "path = os.path.join('folder', 'subfolder', 'file.txt') # Joining path components intelligently using appropriate delimiter.\n", + "absolute_path = os.path.abspath(path) # Getting the absolute path of the specified path.\n", + "exists = os.path.exists(path) # Checking if the specified path exists.\n", + "is_directory = os.path.isdir(path) # Checking if the specified path is a directory.\n", + "is_file = os.path.isfile(path) # Checking if the specified path is a file.\n", + "base_name, extension = os.path.splitext(path) # Splitting the path into base name and extension.\n", + "basename = os.path.basename(path) # Getting the base name (file or directory name) from the path.\n", + "dirname = os.path.dirname(path) # Getting the directory name from the path.\n", + "\n", + "# Printing the information\n", + "print(\"Path:\", path) # Path string\n", + "print(\"Absolute Path:\", absolute_path) # Absolute path string\n", + "print(\"Exists:\", exists) # Boolean indicating if path exists\n", + "print(\"Is Directory:\", is_directory) # Boolean indicating if path is a directory\n", + "print(\"Is File:\", is_file) # Boolean indicating if path is a file\n", + "print(\"Base Name:\", basename) # Base name of the file or directory\n", + "print(\"Directory Name:\", dirname) # Directory name of the path\n", + "print(\"Extension:\", extension) # File extension with the dot\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This code demonstrates the usage of various os.path functions to perform operations on file paths, such as joining paths, obtaining absolute paths, checking existence, identifying directories or files, splitting paths into base names and extensions, and retrieving the base name and directory name from a path. The corresponding outputs are displayed to provide the relevant information." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/beyond/nutshell/functions.ipynb b/book/beyond/nutshell/functions.ipynb new file mode 100644 index 0000000..f126b2d --- /dev/null +++ b/book/beyond/nutshell/functions.ipynb @@ -0,0 +1,87 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Beyond the Basics: Functions\n", + "\n", + "An example of an advanced fuction can be the lambda function. It is an anonymous function in Python that can be defined in a single line using the lambda keyword. It is typically used for simple and concise operations without the need for a formal function definition.\n", + "\n", + "Here's an example that showcases the difference between lambda functions and normal functions:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from math import pi \n", + "import os " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "12\n", + "12\n" + ] + } + ], + "source": [ + "# Normal function\n", + "def multiply(x, y):\n", + " return x * y\n", + "\n", + "result = multiply(3, 4)\n", + "print(result) # Output: 12\n", + "\n", + "# Lambda function\n", + "multiply_lambda = lambda x, y: x * y\n", + "\n", + "result_lambda = multiply_lambda(3, 4)\n", + "print(result_lambda) # Output: 12\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Both the normal function and the lambda function are used to multiply 3 and 4. The results obtained from both approaches are identical (12). The key difference is that the normal function is defined with the def keyword, whereas the lambda function is defined using the lambda keyword without a formal function name.\n", + "\n", + "lambda functions are particularly useful in scenarios where a small, one-time function is needed without the need for a full function definition and name." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/beyond/nutshell/strings.ipynb b/book/beyond/nutshell/strings.ipynb new file mode 100644 index 0000000..467e354 --- /dev/null +++ b/book/beyond/nutshell/strings.ipynb @@ -0,0 +1,167 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Beyond the Basics: Strings\n", + "In Python, strings are created using quotes ('' or \"\") and are immutable, while f-strings are formatted strings that allow embedding expressions inside curly braces { } for dynamic value substitution during runtime. Here is a couple of examples for strings:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from math import pi \n", + "import os " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Alice 25 engineer\n" + ] + } + ], + "source": [ + "name = \"Alice\"\n", + "age = 25\n", + "profession = \"engineer\"\n", + "\n", + "print (name,age,profession)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is the same example made as a complete sentence using f-strings. " + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "My name is Alice, I'm 25 years old, and I work as an engineer.\n" + ] + } + ], + "source": [ + "intro = f\"My name is {name}, I'm {age} years old, and I work as an {profession}.\"\n", + "\n", + "print (intro)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Formatting numbers\n", + "Python's f-strings provide a convenient way to format numbers by using the colon character and specifying the desired format. The following table demonstrates a couple of examples with the number $1$ using f-strings:

\n", + "\n", + "| Code | Result|\n", + "|------|------|\n", + "| 1:.2f | 1.00|\n", + "| 1:.0f| 1|\n", + "| 1:.10f| 1.0000000000 | \n", + "| 1:%| 100.000000%|\n", + "| 1:.1%| 100.0% |\n", + "| 1:e| 1.000000e+00 |" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the example below, the sleep() function from the time module is used to simulate the passage of time and provide a simple demonstration of a progress bar implementation. We define a function simulate_long_running_algorithm() that performs a loop with a sleep of 0.5 seconds between iterations. Within each iteration, the progress of the algorithm is calculated and used to construct a progress bar string. The progress bar consists of a series of equal signs (=) that visually represent the progress, followed by the percentage completion formatted to one decimal defined inside an f-strings." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[====================] 100.0%\n", + "Algorithm complete!\n" + ] + } + ], + "source": [ + "import time\n", + "\n", + "def simulate_long_running_algorithm():\n", + " total_iterations = 10\n", + " for i in range(total_iterations):\n", + " time.sleep(0.5) # Simulating processing time\n", + " progress = (i + 1) / total_iterations\n", + " progress_bar = f\"[{'=' * int(progress * 20):20s}] {progress * 100:.1f}%\"\n", + " print(progress_bar, end='\\r') # Print on the same line\n", + " print(\"\\nAlgorithm complete!\")\n", + "\n", + "simulate_long_running_algorithm()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "

Escape characters

\n", + "\n", + "Escape characters in programming are special characters that are used to represent certain non-printable or special characters within strings. They are typically represented by a backslash (' \\ ') followed by a specific character or sequence. We used two escape characters in the previous example, can you identify them?\n", + "\n", + "| Code | Result| Description |\n", + "|------|------|------ |\n", + "| \\\\' | ' | represents the escape sequence for a single quote (').|\n", + "| \\\\\\ | \\\\ | represents the escape sequence for a backslash (' \\ ').|\n", + "| \\\\n | new line| represents the escape sequence for a new line character, which moves the cursor to the beginning of the next line. | \n", + "| \\\\r | carriage return | represents the escape sequence for a carriage return character, which moves the cursor to the beginning of the current line.|\n", + "| \\\\t | tab |represents the escape sequence for a tab character, which adds horizontal spacing. |\n", + "| \\\\b | backspace | represents the escape sequence for a backspace character, which moves the cursor one position back. |" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/beyond/strings.ipynb b/book/beyond/strings.ipynb new file mode 100644 index 0000000..2bba6e1 --- /dev/null +++ b/book/beyond/strings.ipynb @@ -0,0 +1,355 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "# Beyond the Basics: Strings\n", + "\n", + "Welcome to the third Notebook. In this Notebook we are going to learn some advanced Python. Let's first start with strings. Run the code below and see what it prints out." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from math import pi \n", + "import os " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is an F-String\n", + "This is a string\n" + ] + } + ], + "source": [ + "MyFString = f\"This is an F-String\"\n", + "MyString = \"This is a string\"\n", + "print(MyFString)\n", + "print(MyString)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "\n", + "Now let's try inserting some data into our print() function. We'll use the list of integers [1,2,3,4]. " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Data1: 1, Data2: 2, Data3: 3, Data4: 4\n", + "Data1: 1 ,Data2: 2 ,Data3: 3 ,Data4: 4\n" + ] + } + ], + "source": [ + "Data = [1,2,3,4]\n", + "\n", + "MyFString = f\"Data1: {Data[0]}, Data2: {Data[1]}, Data3: {Data[2]}, Data4: {Data[3]}\"\n", + "\n", + "print(MyFString)\n", + "print(\"Data1:\",Data[0],\",Data2:\",Data[1],\",Data3:\",Data[2],\",Data4:\",Data[3])" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "As you can see from the above code, it is much easier to insert variables in a string by using an f-string (formatted string)." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### Formatting numbers\n", + "\n", + "Using f-strings makes formatting numbers really easy. Just add a colon character after a number value and specify how you want to format the number. The following table demonstrates a couple of examples with the number $1$:

\n", + "\n", + "| Code | Result|\n", + "|------|------|\n", + "| 1:.2f | 1.00|\n", + "| 1:.0f| 1|\n", + "| 1:.10f| 1.0000000000 | \n", + "| 1:%| 100.000000%|\n", + "| 1:.1%| 100.0% |\n", + "| 1:e| 1.000000e+00 |\n", + "\n", + "As you can see the default number of decimal places is six. Furthermore, the % formatting operator assumes that $1$ is equal to $100$%, which is usual when working with fractions, and the formatting operator e formats using scientific notation." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Now let's use our newfound knowledge of strings to make a simple progress bar. During other courses, you'll sometimes have to write algorithms that take a long time to run. In this case, it is useful to have a progress bar. Our example of a progress bar makes use of the sleep() function, from the time module, to simulate elapsed time." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loading: 0%\n", + "Loading: 10%\n", + "Loading: 20%\n", + "Loading: 30%\n", + "Loading: 40%\n", + "Loading: 50%\n", + "Loading: 60%\n", + "Loading: 70%\n", + "Loading: 80%\n", + "Loading: 90%\n", + "Loading: 100%\n" + ] + } + ], + "source": [ + "import time\n", + "\n", + "for i in range(11):\n", + " print(f\"Loading: {i*10}%\", )\n", + " time.sleep(0.5) " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "This works! Though it is not that pretty to look at. It would look nicer to not have it print a new line each time. This is where escape characters come in. These characters can do some special things in strings. Below an example of some escape characters:\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "

Escape characters

\n", + "\n", + "| Code | Result|\n", + "|------|------|\n", + "| \\\\' | ' |\n", + "| \\\\\\ | \\\\ |\n", + "| \\\\n | new line| \n", + "| \\\\r | carriage return |\n", + "| \\\\t | tab |\n", + "| \\\\b | backspace |\n", + "\n", + "We can use some of these characters in our code. Let's use the carriage return character to make our progress bar not print out a new line every time. We can do this by adding end=\"\\r\" into our print function. The end keyword specifies a string that gets printed at the end. The string we print at the end here is the carriage return character. This carriage resets the print function to the start of the line; thus making the next print function overwrite the current printed line. Try it and see what happens:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is a very important message\n" + ] + } + ], + "source": [ + "print(\"Will I get overwritten?\", end=\"\\r\")\n", + "print(\"This is a very important message\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Now let's add this to our progress bar... " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loading complete!\n" + ] + } + ], + "source": [ + "import time\n", + "for i in range(11):\n", + " print(f\"Loading: {i*10}%\", end=\"\\r\")\n", + " time.sleep(0.5) \n", + "print(\"Loading complete!\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "As you can see, it works beautifully!" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/09/asserts.ipynb b/book/errors/asserts.ipynb similarity index 100% rename from book/09/asserts.ipynb rename to book/errors/asserts.ipynb diff --git a/book/09/error_types.ipynb b/book/errors/error_types.ipynb similarity index 100% rename from book/09/error_types.ipynb rename to book/errors/error_types.ipynb diff --git a/book/09/handling_errors.ipynb b/book/errors/handling_errors.ipynb similarity index 100% rename from book/09/handling_errors.ipynb rename to book/errors/handling_errors.ipynb diff --git a/book/09/intro.md b/book/errors/intro.md similarity index 100% rename from book/09/intro.md rename to book/errors/intro.md diff --git a/book/09/raise_errors.ipynb b/book/errors/raise_errors.ipynb similarity index 100% rename from book/09/raise_errors.ipynb rename to book/errors/raise_errors.ipynb diff --git a/book/09/traceback.ipynb b/book/errors/traceback.ipynb similarity index 100% rename from book/09/traceback.ipynb rename to book/errors/traceback.ipynb diff --git a/book/02/Exercises/01.ipynb b/book/flow/Exercises/01.ipynb similarity index 68% rename from book/02/Exercises/01.ipynb rename to book/flow/Exercises/01.ipynb index 5084e97..ea30d50 100644 --- a/book/02/Exercises/01.ipynb +++ b/book/flow/Exercises/01.ipynb @@ -56,225 +56,8 @@ } }, "source": [ - "## Exercise 2.1.1\n", - "\n", - "In the code cell bellow you can see a function that finds the greatest common divisor of any two numbers using the math module. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "collapsed": true, - "id": "YjB37kkNGsr9", - "outputId": "36e77aac-9e26-4c63-fbf5-e030e5539ab1" - }, - "outputs": [], - "source": [ - "import math\n", - "\n", - "def find_greatest_common_divisor(a, b):\n", - " greatest_common_divisor = math.gcds(a, b)\n", - " return greatest_common_divisor\n", - "\n", - "print('The greatest common divisor is:', find_greatest_common_divisor(2, 4))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-input" - ] - }, - "outputs": [], - "source": [ - "# jupyterquiz-exercise-2-1-1\n", - "#display_quiz(questions[0])" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "aaxayx2RH9IM", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## (Searching) Exercise 2.1.2\n", - "\n", - "We can only take and store measurements at a limited number of locations and/or times. But what if we are interested in a value in between, i.e., at a location/time where we do not have a measurement? Then we can use interpolation to estimate that value. A popular, and simple, interpolation technique is linear interpolation. \n", - "Your task is to use the module scipy to perform a 1D linear interpolation between a set of known points, where x_known and y_known are arrays with the measured $x$ and $y$ values. Use Google to look up the 1D interpolation function in scipy.

In the code below there is something missing after `return` (look the three dots). What should be the correct missing code for the function to give us the desired result?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true, - "id": "ZazhpxxTIzxE" - }, - "outputs": [], - "source": [ - "from scipy import interpolate\n", - "\n", - "def interpolate_inbetween(x_known, y_known, x_predict):\n", - " f = interpolate.interp1d(x_known, y_known)\n", - " return ...\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-input" - ] - }, - "outputs": [], - "source": [ - "# jupyterquiz-exercise-2-1-2\n", - "#display_quiz(questions[1])" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "Ue4CKV8PKnBG", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## (Searching) Exercise 2.1.3\n", - "\n", - "Now, let's try to measure the running time of a function, for that we will need the time module. Use it to measure the working time of the cool_function() below." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true, - "id": "C1aOizjOK7sl", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [], - "source": [ - "# you do not need to change anything in this cell\n", - "def cool_function():\n", - " x = 0\n", - " for i in range(100000000):\n", - " x += 1\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Which of the following functions will give us the working time of the cool_function()?" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "
\n", - "\n", - "* **Option A**\n", - "```python\n", - "def measure_time(func):\n", - " t0 = time.time()\n", - " t1 = time.time()\n", - " return t1 - t0\n", - "```\n", - "\n", - "* **Option B**\n", - "```python\n", - "def measure_time(func):\n", - " t0 = time.time()\n", - " func()\n", - " t1 = time.time()\n", - " return t1 - t0\n", - "```\n", - "* **Option C**\n", - "```python\n", - "def measure_time(func,t0,t1):\n", - " t0 = time.time()\n", - " func()\n", - " t1 = time.time()\n", - " return func\n", - "```\n", - "\n", - "
\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-input" - ] - }, - "outputs": [], - "source": [ - "# jupyterquiz-exercise-2-1-3\n", - "#display_quiz(questions[2])" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "id": "su7ODKnqB7tv", - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## Exercise 2.2.1\n", + "## Exercise\n", + "% was exercise 2.2.1\n", "\n", "One of the most crucial applications of if statements is filtering the data from errors and checking whether an error is within a certain limit.\n", "\n", @@ -384,7 +167,8 @@ } }, "source": [ - "## (Searching) Exercise 2.2.4\n", + "## (Searching) Exercise\n", + "% was exercise 2.2.4\n", "\n", "Conditional expression is a way how one can compress an if statement to a more compact (and logical) statement. Your task is to rewrite the below if statement by using the 'conditional expression' technique." ] @@ -507,7 +291,8 @@ } }, "source": [ - "## Exercise 2.4.3\n", + "## Exercise\n", + "% was exercise 2.4.3\n", "\n", "Here you need to write a function that is able to sort any list consisting only of real numbers, in the descending order. For example, the list $[19, 5, 144, 6]$ becomes $[144, 19, 6, 5]$. However there are three possible options to complete correctly the code where the dots `...` are placed.\n", "\n", @@ -550,7 +335,7 @@ } }, "source": [ - "## Exercise 2.4.5\n", + "## Exercise\n", "\n", "In this exercise you will perform downsampling of a provided 'regular' 2D list. Downsampling is a procedure where only a subset of the data is sampled (to reduce its size, for example). Below a visual aid of what downsampling of a 2D list is. Instead of using all the data available, your task is to downsample the 2D list to keep only the data of every $a$-th row and every $b$-th column, including the first element $(a_{0,0})$.

$$A = \\left[\\begin{array}{ccccc}\n", "a_{0,0} & \\dots & a_{0,b} & \\dots & a_{0,2b} & \\dots & \\dots & a_{0,nb}\t& \\dots\\\\\n", diff --git a/book/02/Exercises/01.json b/book/flow/Exercises/01.json similarity index 100% rename from book/02/Exercises/01.json rename to book/flow/Exercises/01.json diff --git a/book/flow/conditions.ipynb b/book/flow/conditions.ipynb new file mode 100644 index 0000000..881eb18 --- /dev/null +++ b/book/flow/conditions.ipynb @@ -0,0 +1,767 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "fHmKWsUSKuj4", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "# Conditions and if statements\n", + "\n", + "In previous Sections you have learned how to create variables, alter them with the help of operators and access the code of professional software developers/scientists. With this, you can already do plenty of stuff in Python. However, it still lacks versatility. If you want to apply other processing techniques for other data — you would need to manually rewrite your code and then change it back once the data changes again. Not that handy, right?

In this Section you will learn how to steer the flow of your code — process data differently based on some conditions. For that you will learn a construction called the if statement.\n", + "\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "oyr90lgAQGtD", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "## if keyword\n", + "\n", + "The if statement in Python is similar to how we use it in English. \"If I have apples, I can make an apple pie\" — clearly states that an apple pie will exist under the condition of you having apples. Otherwise, no pie.

\n", + "Well, it is the same in Python:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "QGXlz9tvM56U", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "63cc3e01-7c4c-4829-d4b2-9ae08b587791" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "End of the cell block...\n" + ] + } + ], + "source": [ + "amount_of_apples = 0\n", + "\n", + "if amount_of_apples > 0:\n", + " print(\"You have apples!\\nLet's make a pie!\")\n", + "\n", + "print('End of the cell block...')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "qiElV_BSNYgl", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "As you can see - nothing is printed besides 'End of the cell block...'.

But we can clearly see that there is another print statement! Why it is not printed? Because we have no apples... thus no pie for you.

Let's acquire some fruit and see whether something will change...\n", + "\n", + "Adding 5 apples to our supply:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "ja5Tz_GLNoUH", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "6bd36f78-2958-4bb6-ffcc-420951b3f8ba" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "You have apples!\n", + "Let's make a pie!\n", + "End of the cell block...\n" + ] + } + ], + "source": [ + "amount_of_apples += 5\n", + "\n", + "if amount_of_apples > 0:\n", + " print(\"You have apples!\\nLet's make a pie!\") \n", + "\n", + "print('End of the cell block...')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "UYZHMFlmNyyA", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Now you can see that the same if statement prints text. It happened because our statement amount_of_apples > 0 is now True.

That's how an if statement works — you type the if keyword, a statement and a colon. Beneath it, with an indentation of 4 spaces (1 tab), you place any code you want to run in case that if statement is True. This indentation is the same as described in Notebook 1 when defining a function.

If the result of the conditional expression is False, then the code inside of the if statement block will not run. Here's another example:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "b1eW-x-3QMbZ", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "5d7df045-b19f-432d-e620-30d7cb34f605" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I'm an adult, I have to work right now :(\n", + "End of the cell block...\n" + ] + } + ], + "source": [ + "my_age = 25\n", + "\n", + "if my_age >= 18 and my_age <= 65:\n", + " print(\"I'm an adult, I have to work right now :(\")\n", + "\n", + "print('End of the cell block...')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "7dhdkRKERIz_", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Slightly different setting but still the same construction. As you can see in this case, the condition of the if statement is more complicated than the previous one. It combines two smaller conditions by using the keyword and. Only if both conditions are True the final result is True (otherwise it would be False).Thus, the condition can be as long and as complicated as you want it to be, just make sure that it is readable." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "h3uicp2sTA5x", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "

elif keyword


Now, let's add a bit more logic to our last example:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "cZQHBzWcSdn8", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "0fdc9367-527d-4c1c-d4a2-b15d230a0f79" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I'm an adult, I have to work right now :(\n", + "End of the cell block...\n" + ] + } + ], + "source": [ + "my_age = 25\n", + "\n", + "if my_age >= 18 and my_age <= 65:\n", + " print(\"I'm an adult, I have to work right now :(\")\n", + "elif my_age > 65:\n", + " print(\"I can finally retire!\")\n", + "\n", + "print('End of the cell block...')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "_6NOt61ZSufk", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Still the same output, but what if we change our age..." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "QZ-AGXaJSy7j", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "9208a2bb-328b-4fe0-d1fd-65c443c8902f" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I can finally retire!\n", + "End of the cell block...\n" + ] + } + ], + "source": [ + "my_age = 66\n", + "\n", + "if my_age >= 18 and my_age <= 65:\n", + " print(\"I'm an adult, I have to work right now :(\") # msg #1\n", + "elif my_age > 65:\n", + " print(\"I can finally retire!\") # msg #2\n", + "\n", + "print('End of the cell block...')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "u8RcnX-sTm4G", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "See.. we have a different output. Changing the value of our variable my_age changed the output of the if statement. Furthermore, the elif keyword helped us to add more logic to our code. Now, we have three different output scenarios:
\n", + "- print message #$1$ if my_age is within the $[18, 65]$ range;
\n", + "- print message #$2$ if my_age is bigger than $65$; and,
\n", + "- print none of them if my_age doesn't comply with none of the conditions (as shown below)." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "9r9Mx2gkVyS7", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "4a513321-cca9-4c5e-ee7d-da2157e039d5" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "End of the cell block...\n" + ] + } + ], + "source": [ + "my_age = 15\n", + "\n", + "if my_age >= 18 and my_age <= 65:\n", + " print(\"I'm an adult, I have to work right now :(\") # msg #1\n", + "elif my_age > 65:\n", + " print(\"I can finally retire!\") # msg #2\n", + "\n", + "print('End of the cell block...')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "1lfzBWNfVwN0", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "One can also substitute an elif block by a different if block, however it is preferred to use elif instead to \"keep the condition together\" and to reduce code size.
\n", + "\n", + ":::{warning}\n", + "It is important to know that there should be only one if block and any number of elif blocks within it.\n", + ":::\n", + "\n", + "A last example below setting ``my_age = 88`` to run the first ``elif`` block and setting ``my_age = 7 `` to run the second ``elif`` block.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "0krMMx5DYpeO", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "19ac187f-b814-4aa5-ef91-9db6691ded6c" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I can finally retire!\n", + "I'm really really young\n", + "End of the cell block...\n" + ] + } + ], + "source": [ + "my_age = 88\n", + "\n", + "if my_age >= 18 and my_age <= 65:\n", + " print(\"I'm an adult, I have to work right now :(\")\n", + "elif my_age > 65:\n", + " print(\"I can finally retire!\")\n", + "elif my_age < 10:\n", + " print(\"I'm really, really young\")\n", + "\n", + "\n", + "my_age = 7\n", + "\n", + "if my_age >= 18 and my_age <= 65:\n", + " print(\"I'm an adult, I have to work right now :(\")\n", + "elif my_age > 65:\n", + " print(\"I can finally retire!\")\n", + "elif my_age < 10:\n", + " print(\"I'm really really young\")\n", + "\n", + "print('End of the cell block...')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "WGUFngFNV6ys", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "## else keyword\n", + "\n", + "We can go even further and add an additional scenario to our if statement with the else keyword. It runs the code inside of it only when none of the if and elif conditions are True:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "ieXD271nW903", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "ff7edbd8-33b5-4b6e-c7e7-657ec1d4e8a0" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I'm just young\n", + "End of the cell block...\n" + ] + } + ], + "source": [ + "my_age = 13\n", + "\n", + "if my_age >= 18 and my_age <= 65:\n", + " print(\"I'm an adult, I have to work right now :(\")\n", + "elif my_age > 65:\n", + " print(\"I can finally retire!\")\n", + "elif my_age < 10:\n", + " print(\"I'm really really young\")\n", + "else:\n", + " print(\"I'm just young\")\n", + "\n", + "print('End of the cell block...')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "5_e10m98XJIn", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "\n", + "On the previous example, since my_age is not between $[18,65]$, nor bigger than $65$, nor smaller than $10$, the else block is run.\n", + "\n", + "Below, a final example setting ``my_age = 27`` to run the ``if`` block, then setting ``my_age = 71 `` to run the first ``elif`` block. To run the second ``elif`` block we set ``my_age = 9 ``. Finally, setting ``my_age = 13 `` to run the ``else`` block." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "Qc9WVQTxX76r", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "e4a5e6aa-6ebc-43c0-f7f2-eab350c66a8f" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I'm an adult, I have to work right now :(\n", + "End of the cell block...\n", + "------------------------\n", + "I can finally retire!\n", + "End of the cell block...\n", + "------------------------\n", + "I'm really really young\n", + "End of the cell block...\n", + "------------------------\n", + "I'm just young\n", + "End of the cell block...\n", + "------------------------\n" + ] + } + ], + "source": [ + "my_age = 27\n", + "\n", + "if my_age >= 18 and my_age <= 65:\n", + " print(\"I'm an adult, I have to work right now :(\")\n", + "elif my_age > 65:\n", + " print(\"I can finally retire!\")\n", + "elif my_age < 10:\n", + " print(\"I'm really really young\")\n", + "else:\n", + " print(\"I'm just young\")\n", + "\n", + "print('End of the cell block...')\n", + "print('------------------------')\n", + "\n", + "my_age = 71\n", + "\n", + "if my_age >= 18 and my_age <= 65:\n", + " print(\"I'm an adult, I have to work right now :(\")\n", + "elif my_age > 65: # first elif block\n", + " print(\"I can finally retire!\")\n", + "elif my_age < 10:\n", + " print(\"I'm really really young\")\n", + "else:\n", + " print(\"I'm just young\")\n", + "\n", + "print('End of the cell block...')\n", + "print('------------------------')\n", + "\n", + "\n", + "my_age = 9\n", + "\n", + "if my_age >= 18 and my_age <= 65:\n", + " print(\"I'm an adult, I have to work right now :(\")\n", + "elif my_age > 65:\n", + " print(\"I can finally retire!\")\n", + "elif my_age < 10: # second elif block\n", + " print(\"I'm really really young\")\n", + "else:\n", + " print(\"I'm just young\")\n", + "\n", + "print('End of the cell block...')\n", + "print('------------------------')\n", + "\n", + "\n", + "my_age = 13\n", + "\n", + "if my_age >= 18 and my_age <= 65:\n", + " print(\"I'm an adult, I have to work right now :(\")\n", + "elif my_age > 65:\n", + " print(\"I can finally retire!\")\n", + "elif my_age < 10:\n", + " print(\"I'm really really young\")\n", + "else: # else block\n", + " print(\"I'm just young\")\n", + "\n", + "print('End of the cell block...')\n", + "print('------------------------')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "xAytN9YkYOtw", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "That's almost everything you have to know about if statements! The last two things are:\n", + "\n", + "1. It goes from top to bottom. When the first condition to be True runs, it skips all conditions after it — as shown below:" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "clMld7oKa0n7", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "5cfedbfb-f653-4d90-abd0-658353746aea" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Condition #3\n" + ] + } + ], + "source": [ + "random_number = 17\n", + "\n", + "if random_number > 35:\n", + " print('Condition #1')\n", + "elif random_number > 25:\n", + " print('Condition #2')\n", + "elif random_number > 15:\n", + " print('Condition #3')\n", + "elif random_number > 5:\n", + " print('Condition #4')\n", + "else:\n", + " print('Condition #5')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "rfwRtedNbVs8", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "2. You can put almost everything inside each condition block and you can define variables within each block:" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 242 + }, + "collapsed": true, + "id": "5II4-Zcvbf3j", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "cb2f7c29-2970-48a2-eacc-56d6e3f1a829" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I am a poor BSc student\n", + "x = 5\n" + ] + }, + { + "ename": "NameError", + "evalue": "name 'b' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[22], line 20\u001b[0m\n\u001b[0;32m 17\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39m'\u001b[39m\u001b[39mI am a poor MSc student\u001b[39m\u001b[39m'\u001b[39m)\n\u001b[0;32m 19\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39m'\u001b[39m\u001b[39mx =\u001b[39m\u001b[39m'\u001b[39m, x)\n\u001b[1;32m---> 20\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39m'\u001b[39m\u001b[39mb =\u001b[39m\u001b[39m'\u001b[39m, b)\n", + "\u001b[1;31mNameError\u001b[0m: name 'b' is not defined" + ] + } + ], + "source": [ + "my_income = 150\n", + "my_degree = 'BSc'\n", + "\n", + "if my_degree == 'BSc':\n", + " x = 5\n", + " if my_income > 300:\n", + " b = 2\n", + " print('I am a rich BSc student')\n", + " else:\n", + " print('I am a poor BSc student')\n", + "\n", + "elif my_degree == 'MSc':\n", + "\n", + " if my_income > 300:\n", + " print('I am a rich MSc student')\n", + " else:\n", + " print('I am a poor MSc student')\n", + "\n", + "print('x =', x)\n", + "print('b =', b)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "9nDrNWr2cjMd", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "As you can see, we can make it as complicated as we want in terms of conditional branching.

Additionally, you can see that only variables within the blocks which run were created, while other variables were not. Thus, we have a NameError that we tried to access a variable (b) that was not defined." + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "Python_2_1.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/book/flow/intro.md b/book/flow/intro.md new file mode 100644 index 0000000..f55b3ab --- /dev/null +++ b/book/flow/intro.md @@ -0,0 +1,6 @@ +# Flow + +This chapter is all about ... + +% a short overview for this chapter + diff --git a/book/flow/loops.ipynb b/book/flow/loops.ipynb new file mode 100644 index 0000000..e350ac6 --- /dev/null +++ b/book/flow/loops.ipynb @@ -0,0 +1,853 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "fHmKWsUSKuj4", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "# Loops\n", + "\n", + "Let's do another step to automatize things even more! Previous Sections introduced a lot of fundamental concepts, but they still don't unveil the true power of any programming language — loops!

If we want to perform the same procedure multiple times, then we would have to take the same code and copy-paste it. This approach would work, however it would require a lot of manual work and it does not look cool.

This problem is resolved with a loop construction. As the name suggest, this construction allows you to loop (or run) certain piece of code several times at one execution." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "BcEOnv2kTT9A", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### for loop\n", + "\n", + "The first and the most popular looping technique is a for loop. Let's see some examples:\n", + "\n", + "Let's create a list with some stuff in it. In order to iterate (or go through each element of a list) we use a `for` loop.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "fNaiOimubLMF", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "77085dd8-83cc-41d8-b7c1-17fc55dc38eb" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Start of the loop\n", + "In my list I can find: 100\n", + "In my list I can find: marble\n", + "In my list I can find: False\n", + "In my list I can find: 2\n", + "In my list I can find: 2\n", + "In my list I can find: [7, 7, 7]\n", + "In my list I can find: end\n", + "End of the loop\n" + ] + } + ], + "source": [ + "my_list = [100, 'marble', False, 2, 2, [7, 7, 7], 'end']\n", + "\n", + "print('Start of the loop')\n", + "for list_item in my_list:\n", + " print('In my list I can find:', list_item)\n", + "print('End of the loop')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "NkKA4qLDb9IM", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "General for loop construction looks like this:

\n", + "for iterator_variable in iterable:\n", + " do something with iterator_variable

\n", + "\n", + "During each iteration the following steps are happening under the hood (or above it):\n", + "1. iterator_variable = iterable[0]iterator_variable is assigned the first value from the iterable.\n", + "2. Then, you use iterator_variable as you wish.\n", + "3. By the end of the 'cycle', the next element from the iterable is selected (iterable[1]), i.e., we return to step 1, but now assigning the second element... and so on.\n", + "4. When there is not a next element (in other words, we have reached the end of the iterable) — it exits and the code under the loop is now executed.\n", + "\n", + "Looks cool, but what if we want to alter the original iterable (not the iterator_variable) within the loop?\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "1hZm9bOuhOiE", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "0b50490d-1d74-41cb-ba84-d4a595a7eede" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Try #1, before: [100, 'marble', False, 2, 2, [7, 7, 7], 'end']\n", + "Try #1, after [100, 'marble', False, 2, 2, [7, 7, 7], 'end']\n" + ] + } + ], + "source": [ + "x = my_list\n", + "print('Try #1, before:', x)\n", + "\n", + "for item in x:\n", + " item = [5,6,7]\n", + "\n", + "print('Try #1, after', x)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Nothing has changed.... let's try another method. `range()` is used to generate a sequence of numbers more info [here](https://www.w3schools.com/python/ref_func_range.asp).\n", + "\n", + "`range(length_of_x)` will generate numbers from 0 till `length_of_x`, excluding the last one.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "range(0, 7)\n", + "Try #2, before [100, 'marble', False, 2, 2, [7, 7, 7], 'end']\n", + "Try #2, after [-1, -1, -1, -1, -1, -1, -1]\n" + ] + } + ], + "source": [ + "length_of_x = len(x)\n", + "\n", + "indices = range(length_of_x)\n", + "\n", + "print(indices)\n", + "print('Try #2, before', my_list)\n", + "\n", + "for id in indices:\n", + " my_list[id] = -1\n", + "\n", + "print('Try #2, after', my_list)\n", + " \n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Now we have a method in our arsenal which can not only loop through a list but also access and alter its contents. Also, you can generate new data by using a for loop and by applying some processing to it. Here's an example on how you can automatize your greetings routine!\n", + "\n", + "We create a variable `message` with a general greeting and a list with your friends names. Then an empty list where all greetings will be stored (otherwise you cannot use the `.append` in the for loop below!). \n" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['Ohayo, Mike-kun!', 'Ohayo, Alex-kun!', 'Ohayo, Maria-kun!']\n" + ] + } + ], + "source": [ + "\n", + "message = \"Ohayo\"\n", + "names = [\"Mike\", \"Alex\", \"Maria\"]\n", + "greetings = []\n", + "\n", + "for name in names:\n", + " personalized_greeting = f'{message}, {name}-kun!' \n", + " greetings.append(personalized_greeting) \n", + "\n", + "print(greetings)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "And you can also have loops inside loops!. Let's say that you put down all your expenses per day separately in euros. You can also keep them within one list together.Additionally, you can access also each expense separately! day3 is third array and 2nd expense is second element within that array." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "All my expenses [[15, 100, 9], [200], [10, 12, 15, 5, 1]]\n", + "My second expense on day 3 is 12\n" + ] + } + ], + "source": [ + "day1_expenses = [15, 100, 9]\n", + "day2_expenses = [200]\n", + "day3_expenses = [10, 12, 15, 5, 1]\n", + "\n", + "expenses = [day1_expenses, day2_expenses, day3_expenses]\n", + "print('All my expenses', expenses)\n", + "\n", + "print(f'My second expense on day 3 is {expenses[2][1]}')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's use it in some calculations. The code bellow iterates over the expenses for each day, calculates the total expenses for each day, and then adds them together to obtain the overall total expenses. " + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Option #1: In total I have spent 367 euro!\n" + ] + } + ], + "source": [ + "total_expenses = 0\n", + "\n", + "for i in range(len(expenses)): \n", + " daily_expenses_list = expenses[i]\n", + " daily_expenses = 0\n", + " for j in range(len(daily_expenses_list)): \n", + " daily_expenses += daily_expenses_list[j]\n", + " total_expenses += daily_expenses\n", + " \n", + "print(f'Option #1: In total I have spent {total_expenses} euro!')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`````{admonition} Let's break it down\n", + "This code calculates the total expenses over multiple days using nested loops. Here's an explanation in simpler terms:\n", + "\n", + "1. We start with the variable `total_expenses` set to 0 to keep track of the total expenses.\n", + "2. The code loops over each day's expenses using the outer loop, which runs from 0 to the length of the `expenses` list.\n", + "3. Inside the loop, it accesses the expenses made on the current day by assigning `daily_expenses_list` to the expenses at index `i`.\n", + "4. It initializes `daily_expenses` as 0 to temporarily store the sum of expenses for the current day.\n", + "5. The code enters the inner loop, which iterates over the expenses for the current day using the range of the length of `daily_expenses_list`.\n", + "6. Inside the inner loop, it adds each expense to `daily_expenses` to calculate the total expenses for the current day.\n", + "7. After the inner loop completes, it adds `daily_expenses` to the `total_expenses` variable to accumulate the expenses across all days.\n", + "8. Once the outer loop finishes, it prints the total expenses using an f-string format to display the result.\n", + "`````\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Option #2" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Option #2: In total I have spent 367 euro!\n" + ] + } + ], + "source": [ + "total_expenses = 0\n", + "\n", + "for i in range(len(expenses)):\n", + " for j in range(len(expenses[i])):\n", + " total_expenses += expenses[i][j]\n", + " \n", + "print(f'Option #2: In total I have spent {total_expenses} euro!')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Option #3 - advanced techniques gathered after eternal suffering." + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Option #3: In total I have spent 367 euro!\n" + ] + } + ], + "source": [ + "total_expenses = 0\n", + "total_expenses = sum(map(sum, expenses))\n", + "print(f'Option #3: In total I have spent {total_expenses} euro!')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "TNGZ78d8LOYC", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### while loop\n", + "\n", + "The second popular loop construction is a while loop. The main difference is that it is suited for code structures that must repeat unless a certain logical condition is satisfied. It looks like this:

while logical_condition == True:
do something

And here is a working code example:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "rqsX011pL6p6", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "39bce5bb-bf01-469c-8758-6127efc4e943" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "sum in the beginning of the cycle: 0\n", + "sum in the end of the cycle: 1\n", + "sum in the beginning of the cycle: 1\n", + "sum in the end of the cycle: 2\n", + "sum in the beginning of the cycle: 2\n", + "sum in the end of the cycle: 3\n", + "sum in the beginning of the cycle: 3\n", + "sum in the end of the cycle: 4\n", + "sum in the beginning of the cycle: 4\n", + "sum in the end of the cycle: 5\n" + ] + } + ], + "source": [ + "sum = 0\n", + "\n", + "while sum < 5:\n", + " print('sum in the beginning of the cycle:', sum)\n", + " sum += 1\n", + " print('sum in the end of the cycle:', sum)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "mW02NDD4MJWn", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "As you can see, this loop was used to increase the value of the sum variable until it reached $5$. The moment it reached $5$ and the loop condition was checked — it returned False and, therefore, the loop stopped.

Additionally, it is worth to mention that the code inside the loop was altering the variable used in the loop condition statement, which allowed it to first run, and then stop. In the case where the code doesn't alter the loop condition, it won't stop (infinite loop), unless another special word is used.

Here's a simple example of an infinite loop, which you may run (by removing the #'s) but in order to stop it — you have to interrupt the Notebook's kernel or restart it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000 + }, + "collapsed": true, + "id": "AmIcH59oNaxU", + "outputId": "e944bfe2-f906-45c9-ef2a-03280956679a" + }, + "outputs": [], + "source": [ + "# a, b = 0, 7\n", + "\n", + "# while a + b < 10:\n", + "# a += 1\n", + "# b -= 1\n", + "# print(f'a:{a};b:{b}')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "ryvB-qKfNxPh", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### break keyword\n", + "\n", + "After meeting and understanding the loop constructions, we can add a bit more control to it. For example, it would be nice to exit a loop earlier than it ends — in order to avoid infinite loops or just in case there is no need to run the loop further. This can be achieved by using the break keyword. The moment this keyword is executed, the code exits from the current loop." + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "hvib4ruNTN6_", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "b0f08946-864e-430a-a8cc-765303a9ac6e" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Before normal loop\n", + "0 iteration and still running...\n", + "1 iteration and still running...\n", + "2 iteration and still running...\n", + "3 iteration and still running...\n", + "4 iteration and still running...\n", + "5 iteration and still running...\n", + "6 iteration and still running...\n", + "After normal loop\n", + "Before interrupted loop\n", + "0 iteration and still running...\n", + "1 iteration and still running...\n", + "2 iteration and still running...\n", + "3 iteration and still running...\n", + "4 iteration and still running...\n", + "Leaving the loop\n", + "After interupted loop\n" + ] + } + ], + "source": [ + "stop_iteration = 4\n", + "\n", + "print('Before normal loop')\n", + "for i in range(7):\n", + " print(f'{i} iteration and still running...')\n", + "print('After normal loop')\n", + "\n", + "print('Before interrupted loop')\n", + "for i in range(7):\n", + " print(f'{i} iteration and still running...')\n", + "\n", + " if i == stop_iteration:\n", + " print('Leaving the loop')\n", + " break\n", + "print('After interupted loop')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "guxGK4uGUXBA", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "The second loop shows how a small intrusion of an if statement and the break keyword can help us with stopping the loop earlier. The same word can be also used in a while loop:" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "tVkdaOP8Ul-W", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "5f391d65-82a2-4408-d74d-af89b84a040b" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Before the loop\n", + "Inside the loop #1\n", + "Inside the loop #2\n", + "Inside the loop #3\n", + "Inside the loop #4\n", + "Inside the loop #5\n", + "Inside the loop #6\n", + "Too many iterations is bad for your health\n", + "After the loop\n" + ] + } + ], + "source": [ + "iteration_number = 0\n", + "\n", + "print('Before the loop')\n", + "while True:\n", + " iteration_number += 1\n", + "\n", + " print(f'Inside the loop #{iteration_number}')\n", + " if iteration_number > 5:\n", + " print('Too many iterations is bad for your health')\n", + " break\n", + "print('After the loop')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "AtRCfdMlWzhn", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### continue keyword\n", + "\n", + "Another possibility to be more flexible when using loops is to use the continue keyword.

This will allow you to skip some iterations (more precisely — the moment the keyword is used it will skip the code underneath it and will start the next iteration from the beginning)." + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "_1q4EB0bXMyk", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "57b11d07-251a-4319-d0ba-1d3ee1685b61" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Begin normal loop\n", + "\n", + "0 iteration and still running...\n", + "Calculating cool function for 0 -> f(0) = 3\n", + "1 iteration and still running...\n", + "Calculating cool function for 1 -> f(1) = 15\n", + "2 iteration and still running...\n", + "Calculating cool function for 2 -> f(2) = 41\n", + "3 iteration and still running...\n", + "Calculating cool function for 3 -> f(3) = 81\n", + "4 iteration and still running...\n", + "Calculating cool function for 4 -> f(4) = 135\n", + "5 iteration and still running...\n", + "Calculating cool function for 5 -> f(5) = 203\n", + "6 iteration and still running...\n", + "Calculating cool function for 6 -> f(6) = 285\n", + "\n", + "End normal loop\n", + "\n", + "-------------------\n", + "Begin altered loop\n", + "\n", + "0 iteration and still running...\n", + "1 iteration and still running...\n", + "Calculating cool function for 1 -> f(1) = 15\n", + "2 iteration and still running...\n", + "3 iteration and still running...\n", + "Calculating cool function for 3 -> f(3) = 81\n", + "4 iteration and still running...\n", + "5 iteration and still running...\n", + "Calculating cool function for 5 -> f(5) = 203\n", + "6 iteration and still running...\n", + "\n", + "End altered loop\n" + ] + } + ], + "source": [ + "def calculate_cool_function(arg):\n", + " res = 7 * arg ** 2 + 5 * arg + 3\n", + " print(f'Calculating cool function for {arg} -> f({arg}) = {res}')\n", + "\n", + "print('Begin normal loop\\n')\n", + "for i in range(7):\n", + " print(f'{i} iteration and still running...')\n", + " calculate_cool_function(i)\n", + "print('\\nEnd normal loop\\n')\n", + "\n", + "print('-------------------')\n", + "\n", + "print('Begin altered loop\\n')\n", + "for i in range(7):\n", + " print(f'{i} iteration and still running...')\n", + "\n", + " # skipping every even iteration\n", + " if i % 2 == 0:\n", + " continue\n", + " \n", + " calculate_cool_function(i)\n", + " \n", + "print('\\nEnd altered loop')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "_30hKsC4a1vy", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "As you can see, with the help of the continue keyword we managed to skip some of the iterations. Also worth noting that $0$ is divisible by any number, for that reason the calculate_cool_function(i) at i = 0 didn't run." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "lDKimbtECAAz", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "## Additional study material\n", + "\n", + "* Official Python Documentation - https://docs.python.org/3/tutorial/controlflow.html\n", + "* https://realpython.com/python-conditional-statements/\n", + "* Think Python (2nd ed.) - Section 5\n", + "\n", + "* Official Python Documentation - https://docs.python.org/3/tutorial/datastructures.html\n", + "* https://realpython.com/python-data-structures/\n", + "* Think Python (2nd ed.) - Sections 8, 10, 11, 12\n", + "\n", + "* Official Python Documentation - https://docs.python.org/3/tutorial/controlflow.html\n", + "* https://realpython.com/python-for-loop/\n", + "* Think Python (2nd ed.) - Section 7" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### After this Notebook you should be able to:\n", + "\n", + "- generate an array for the x-axis\n", + "- calculate the **`cos`** or **`sin`** of the x-axis\n", + "- plot such functions\n", + "- understand how to load Python files as modules\n", + "- understand conditions with **`if`**, **`elif`** and, **`else`**\n", + "- understand the differences between **`list`**, **`tuple`**, and **`dict`**\n", + "- slice lists and tuples\n", + "- use **`for`** and **`while`** loops\n", + "- use the **`break`** and **`continue`** keywords inside of loops\n" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "Python_2_1.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/book/flow/nutshell.md b/book/flow/nutshell.md new file mode 100644 index 0000000..91c024e --- /dev/null +++ b/book/flow/nutshell.md @@ -0,0 +1,3 @@ +# Flow: in a Nutshell + +Nutshell. \ No newline at end of file diff --git a/book/flow/nutshell/conditions.ipynb b/book/flow/nutshell/conditions.ipynb new file mode 100644 index 0000000..d133b5d --- /dev/null +++ b/book/flow/nutshell/conditions.ipynb @@ -0,0 +1,82 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Conditions and if statements\n", + "\n", + "\n", + "In previous sections, you have acquired essential skills in Python such as variable creation, operator utilization, and code analysis. These skills enable you to accomplish a wide range of tasks. However, there is still a need for increased flexibility. Manually modifying your code to accommodate different data and reverting those changes can be cumbersome. In this section, you will delve into the concept of code control, which allows you to navigate the execution of your code based on specific conditions. To achieve this, you will explore a fundamental programming construct called the if statement. Through this construct, you will gain the ability to selectively process data based on defined conditions, enhancing the adaptability and efficiency of your code.\n", + "\n", + "We have three sections:\n", + "\n", + "* If Statement: The if statement enables us to execute a block of code only if a specified condition is true. It provides a way to make decisions and selectively perform actions based on whether a condition evaluates to true or false.\n", + "\n", + "* Elif Statement: The elif statement allows us to consider multiple conditions one after another and execute different blocks of code based on the first condition that evaluates to true. It provides a means to handle various possibilities and choose the appropriate action based on the situation.\n", + "\n", + "* If-else Statement: The if-else statement combines the if and else statements to perform one action if a condition is true and a different action if the condition is false. It offers a way to provide alternative paths of execution, ensuring that the code responds differently based on whether a condition is met or not.\n", + "\n", + "These conditional statements allow you to make decisions and control the flow of your program based on specific conditions. For example like this: \n" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x is positive\n", + "x is non-positive\n", + "x is zero\n" + ] + } + ], + "source": [ + "x = 5\n", + "if x > 0:\n", + " print(\"x is positive\")\n", + "\n", + "x = -2\n", + "if x > 0:\n", + " print(\"x is positive\")\n", + "else:\n", + " print(\"x is non-positive\")\n", + "\n", + "x = 0\n", + "if x > 0:\n", + " print(\"x is positive\")\n", + "elif x < 0:\n", + " print(\"x is negative\")\n", + "else:\n", + " print(\"x is zero\")\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/flow/nutshell/loops.ipynb b/book/flow/nutshell/loops.ipynb new file mode 100644 index 0000000..2f2abe8 --- /dev/null +++ b/book/flow/nutshell/loops.ipynb @@ -0,0 +1,181 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Loops " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### for loop \n", + "for Loop: A for loop is used to iterate over a sequence (such as a list, tuple, or string) or any iterable object. It allows you to perform a set of statements repeatedly for each item in the sequence. Here is a simple example of how to use a for loop:" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "apple\n", + "banana\n", + "orange\n" + ] + } + ], + "source": [ + "fruits = [\"apple\", \"banana\", \"orange\"]\n", + "for fruit in fruits:\n", + " print(fruit)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### while loop\n", + "while Loop: A while loop is used to repeatedly execute a block of code as long as a given condition is true. It allows you to keep looping until the condition becomes false. Here is a simple example of how to use a while loop:" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n" + ] + } + ], + "source": [ + "count = 0\n", + "while count < 5:\n", + " print(count)\n", + " count += 1\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### break statement\n", + "break Statement: The break statement is used to prematurely exit a loop. When encountered, it terminates the loop and resumes execution at the next statement outside the loop. Here is a simple example of how to use a break statement:" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "apple\n" + ] + } + ], + "source": [ + "fruits = [\"apple\", \"banana\", \"orange\"]\n", + "for fruit in fruits:\n", + " if fruit == \"banana\":\n", + " break\n", + " print(fruit)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### continue statement\n", + "continue Statement: The continue statement is used to skip the remaining code inside a loop for the current iteration and move to the next iteration. Here is a simple example of how to use a continue statement:" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "2\n", + "4\n", + "5\n" + ] + } + ], + "source": [ + "numbers = [1, 2, 3, 4, 5]\n", + "for num in numbers:\n", + " if num == 3:\n", + " continue\n", + " print(num)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Break down of all examples**: In the first example, the for loop iterates over a list of fruits and prints each fruit. The while loop in the second example prints numbers from 0 to 4. The break statement in the third example terminates the loop when the condition is met. Lastly, the continue statement in the fourth example skips printing the number 3 and moves to the next iteration. These loop constructs provide powerful control flow mechanisms to repeat and control the execution of code blocks based on specific conditions." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/flow/nutshell/structures.ipynb b/book/flow/nutshell/structures.ipynb new file mode 100644 index 0000000..dcc9e18 --- /dev/null +++ b/book/flow/nutshell/structures.ipynb @@ -0,0 +1,314 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Data Structures\n", + "\n", + "Welcome to an exciting new adventure in data management! In the previous module, you learned how to create variables, which was just the tip of the iceberg. Now, imagine a scenario where you have numerous variables or want to organize and access them within a single entity. That's where data structures come into play!\n", + "\n", + "Data structures are like superheroes that help us tackle complex data management challenges. They come in various forms, each with its unique purpose and complexity. Today, we'll dive into some of the superheroes of Python's built-in data structures: the mighty list, the versatile dict, and the steadfast tuple. These data structures provide us with powerful tools to store, organize, and manipulate data, enabling us to unleash the true potential of our code. Let's dive in and unlock the secrets of organized data!" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### List\n", + "A list is a powerful data structure in Python that allows you to store and manipulate an ordered collection of items. It's like having a magic box where you can keep multiple things together and change them whenever you want. Let's explore 4 different ways to create and use lists:" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. Creating an empty list:\n", + "You can create an empty list by simply using empty square brackets [ ]. It's like having a blank canvas ready to be filled with items." + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2, 5, 3]\n" + ] + } + ], + "source": [ + "my_list = [2,5,3]\n", + "\n", + "print (my_list)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. Creating an empty list - using the class constructor: You can also use the list class constructor list() to create an empty list. It's another way of preparing your container for future data." + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [], + "source": [ + "my_list = list()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. Creating a list from existing data: To create a list with existing data, you can directly enclose the items within square brackets [ ], separating them with commas. It's like assembling your collection of items in one go." + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['apple', 'banana', 'orange', 'kiwi']\n" + ] + } + ], + "source": [ + "fruits = ['apple', 'banana', 'orange', 'kiwi']\n", + "print (fruits)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "4. Creating a list from existing data: You can use the list constructor list( ) with an iterable (such as a string or another list) to create a new list containing the elements of that iterable. It's like transforming one collection into another." + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 4, 5]\n" + ] + } + ], + "source": [ + "numbers = list(range(1, 6)) # Creates a list [1, 2, 3, 4, 5]\n", + "print (numbers)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### tuple\n", + "A tuple is a data structure in Python that allows you to store an ordered collection of items. Unlike lists, tuples are immutable, meaning their elements cannot be modified once they are assigned. Let's explore how to define tuples and create examples:" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. Defining a tuple using ( ) brackets or comma:\n", + "You can define a tuple by enclosing the items within parentheses () or by simply separating them with commas. It's like creating a fixed ensemble of elements." + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(1, 2, 3)\n", + "(1, 2, 3)\n" + ] + } + ], + "source": [ + "my_tuple1 = (1, 2, 3)\n", + "my_tuple2 = 1, 2, 3\n", + "\n", + "print (my_tuple1)\n", + "print (my_tuple2)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. Creating a tuple using the tuple class constructor: You can also use the tuple class constructor tuple() to create a tuple. It accepts an iterable as an argument and generates a tuple with its elements. It's like assembling data into a coordinated ensemble." + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(4, 5, 6)\n", + "(1, 2, 3)\n", + "(3, 5)\n", + "('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday')\n" + ] + } + ], + "source": [ + "my_tuple3 = tuple([4, 5, 6])\n", + "\n", + "coordinates = (3, 5) \n", + "days_of_week = tuple(['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']) \n", + "\n", + "my_tuple4 = (1, 2, 3)\n", + "print (my_tuple3)\n", + "print (my_tuple4)\n", + "print (coordinates)\n", + "print (days_of_week)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Dict\n", + "A dictionary is a versatile data structure in Python that allows you to store and retrieve data using a key-value pairing. It's like having a real-life dictionary where you can quickly look up information using specific words. Let's explore how to define dictionaries, we will explore 3 examples:" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. Creating a dictionary using { } brackets: You can create a dictionary by enclosing key-value pairs within curly braces { }, separating each pair with a colon ' : ' It's like building a repository of information with quick access to specific entries." + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'name': 'John', 'age': 25, 'city': 'New York'}\n" + ] + } + ], + "source": [ + "my_dict = {\"name\": \"John\", \"age\": 25, \"city\": \"New York\"}\n", + "\n", + "print (my_dict)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. Creating an empty dictionary using the class constructor: You can also use the dict class constructor dict( ) to create an empty dictionary. It's like preparing a blank canvas to populate with key-value pairs later." + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [], + "source": [ + "my_dict2 = dict()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. Creating a non-empty dictionary by specifying pairs of key-value patterns: To create a dictionary with existing data, you can specify pairs of key-value patterns within the curly braces { }. Each key-value pair is separated by a colon : and pairs are separated by commas. It's like defining relationships between different pieces of information." + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'name': 'Alice', 'age': 30, 'city': 'London'}\n" + ] + } + ], + "source": [ + "student_scores = {\"Alice\": 85, \"Bob\": 92, \"Charlie\": 78}\n", + "contacts = {\"John\": \"+123456789\", \"Emily\": \"+987654321\", \"Sam\": \"+345678912\"}\n", + "my_dict3 = dict()\n", + "my_dict3[\"name\"] = \"Alice\"\n", + "my_dict3[\"age\"] = 30\n", + "my_dict3[\"city\"] = \"London\"\n", + "\n", + "print (my_dict3)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the above code cell, we have created two dictionaries: student_scores and contacts, by specifying key-value pairs within the { } brackets. Additionally, we have also demonstrated how to create an empty dictionary my_dict3 using the dict( ) constructor and then added key-value pairs to it using the square bracket notation. These examples showcase the flexibility of dictionaries in storing and accessing data through key-value relationships." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/flow/structures.ipynb b/book/flow/structures.ipynb new file mode 100644 index 0000000..6af696d --- /dev/null +++ b/book/flow/structures.ipynb @@ -0,0 +1,1113 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "fHmKWsUSKuj4", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "# Data Structures\n", + "\n", + "In this Section you will tackle a data management problem! In the first module you have learned how to create variables, which is cool. But when you populate a lot of variables, or you want to store & access them within one entity, you need to have a data structure.

There are plenty of them, which differ their use cases and complexity. Today we will tackle some of the standard Python built-in data structures. The most popular of those are: list, dict and tuple." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "BcEOnv2kTT9A", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### list\n", + "\n", + "First, the easiest and the most popular data structure in Python: list (which is similar to a typical array you could have seen in a different programming language).

\n", + "You can create a list in the following ways:\n", + "\n", + "1. Creating an empty list, option 1\n", + "2. Creating an empty list, option 2 - using the class constructor\n", + "3. Creating a list from existing data - option 1\n", + "4. Creating a list from existing data - option 2" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "U8OUPaXESz44", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "ee38751f-5efe-4a85-a9a9-a34efc3bfb02" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Type of my_list1 object \n", + "Contents of my_list1 []\n", + "--------------------\n", + "Type of my_list2 object \n", + "Contents of my_list2 []\n", + "--------------------\n", + "Type of my_list3 object \n", + "Contents of my_list3 [5, 'hello', 37.5]\n", + "--------------------\n", + "Type of my_list3 object \n", + "Contents of list_with_letters ['s', 'a', 'n', 'd', 's', 't', 'o', 'n', 'e']\n", + "--------------------\n" + ] + } + ], + "source": [ + "#1\n", + "empty_list1 = []\n", + "print('Type of my_list1 object', type(empty_list1))\n", + "print('Contents of my_list1', empty_list1)\n", + "print('--------------------')\n", + "\n", + "#2\n", + "empty_list2 = list()\n", + "print('Type of my_list2 object', type(empty_list2))\n", + "print('Contents of my_list2', empty_list2)\n", + "print('--------------------')\n", + "\n", + "#3\n", + "my_var1 = 5\n", + "my_var2 = \"hello\"\n", + "my_var3 = 37.5\n", + "\n", + "my_list = [my_var1, my_var2, my_var3]\n", + "print('Type of my_list3 object', type(my_list))\n", + "print('Contents of my_list3', my_list)\n", + "print('--------------------')\n", + "\n", + "\n", + "#4\n", + "cool_rock = \"sandstone\" # remember that a string is a collection of characters\n", + "\n", + "list_with_letters = list(cool_rock)\n", + "\n", + "print('Type of my_list3 object', type(list_with_letters))\n", + "print('Contents of list_with_letters', list_with_letters)\n", + "print('--------------------')\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "I-9MNCzBUgH9", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "As you can see, in all three cases we created a list, only the method how we did it was slightly different:\n", + "- the first method uses the bracket notation.\n", + "- the second method uses class constructor approach. \n", + "\n", + "Both methods also apply to the other data structures.\n", + "\n", + "Now, we have a list — what can we do with it?\n", + "\n", + "Well... we can access and modify any element of an existing list. In order to access a list element, square brackets [] are used with the index of the element we want to access inside. Sounds easy, but keep in mind that Python has a zero-based indexing (as mentioned in Section 1.4 in Notebook 1).\n", + "\n", + ":::{note}\n", + "A zero-based indexing means that the first element has index 0 (not 1), the second element has index 1 (not 2) and the n-th element has index n - 1 (not n)!\n", + ":::" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The ``len()` function returns the lengths of an iterable (string, list, array, etc). Since we have 3 elements, thus we can access 0th, 1st, and 2nd elements. \n", + "\n", + "After the element is accessed, it can be used as any variable, the list only provides a convenient storage. Since it is a storage - we can easily alter and swap list elements" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 295 + }, + "collapsed": true, + "id": "CksNFv0AVmLw", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "bbddff89-959c-4065-89a5-04500ceedf91" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n", + "First element of my list: 5\n", + "Last element of my list: 37.5\n", + "Sum of 5 and 37.5 is 42.5\n", + "[12, 'My new element', 37.5]\n" + ] + } + ], + "source": [ + "print(len(my_list))\n", + "print('First element of my list:', my_list[0])\n", + "print('Last element of my list:', my_list[2])\n", + "\n", + "summation = my_list[0] + my_list[2]\n", + "print(f'Sum of {my_list[0]} and {my_list[2]} is {summation}')\n", + "\n", + "\n", + "my_list[0] += 7\n", + "my_list[1] = \"My new element\"\n", + "\n", + "print(my_list)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "we can only access data we have - Python will give us an error for the following" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "ename": "IndexError", + "evalue": "list assignment index out of range", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mIndexError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[4], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m my_list[\u001b[39m10\u001b[39m] \u001b[39m=\u001b[39m \u001b[39m199\u001b[39m\n", + "\u001b[1;31mIndexError\u001b[0m: list assignment index out of range" + ] + } + ], + "source": [ + "my_list[10] = 199" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "zxkLDWef7IM-", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "We can also add new elements to a list, or remove them! Adding is realized with the append method and removal of an element uses the del keyword. We can also store a list inside a list - list inception! Useful for matrices, images etc. " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "Yos0Cl9C7W1H", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "ba48887c-c2ff-4fc6-a231-68543e8bf97a" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[12, 'My new element', 37.5, 'new addition to my variable collection!']\n", + "[12, 'My new element', 37.5, 'new addition to my variable collection!', ['another list', False, (1+2j)]]\n", + "[12, 'My new element', 'new addition to my variable collection!', ['another list', False, (1+2j)]]\n" + ] + } + ], + "source": [ + "my_list.append(\"new addition to my variable collection!\")\n", + "print(my_list)\n", + "\n", + "my_list.append(['another list', False, 1 + 2j])\n", + "print(my_list)\n", + "\n", + "del my_list[2]\n", + "print(my_list)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "WZgLxAbJ8icK", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Lists also have other useful functionalities, as you can see from the official documentation. Since lists are still objects you can try and apply some operations to them as well." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "UEBv_4u09K9T", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "96987502-088b-48d8-d114-2b9967f2de78" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2, 4, False, 'second list', 0, 222]\n", + "['second list', 0, 222, 'second list', 0, 222, 'second list', 0, 222, 'second list', 0, 222]\n", + "['second list', 0, 222, 5050, 0, 222, 'second list', 0, 222, 'second list', 0, 222]\n" + ] + } + ], + "source": [ + "lst1 = [2, 4, False]\n", + "lst2 = ['second list', 0, 222]\n", + "\n", + "lst1 = lst1 + lst2\n", + "print(lst1)\n", + "\n", + "lst2 = lst2 * 4\n", + "print(lst2)\n", + "\n", + "lst2[3] = 5050\n", + "print(lst2)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "SVvYBl6H96du", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "As you can see, adding lists together concatenates them and multiplying them basically does the same thing (it performs addition several times, just like in real math...).

Additionally, you can also use the in keyword to check the presence of a value inside a list." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "15hwh0COFf-p", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "2b3d16c6-9487-49ea-a6f6-8ffb989ac95c" + }, + "outputs": [], + "source": [ + "print(lst1)\n", + "\n", + "if 222 in lst1:\n", + " print('We found 222 inside lst1')\n", + "else:\n", + " print('Nope, nothing there....')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "NAJZYyQd-fG2", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### tuple\n", + "\n", + "If you understood how list works, then you already understand 95% of tuple. Tuples are just like lists, with some small differences.

1. In order to create a tuple you need to use () brackets, comma or a tuple class constructor.
2. You can change the content of your list, however tuples are immutable (just like strings).\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 313 + }, + "collapsed": true, + "id": "QnEd7YSsE2Ih", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "1a2e1b57-dbff-4c7d-d7c4-8968fecf67a1" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Type of tupl1 \n", + "Content of tupl1 ()\n", + " ()\n" + ] + } + ], + "source": [ + "#1\n", + "tupl1 = tuple() \n", + "print('Type of tupl1', type(tupl1))\n", + "print('Content of tupl1', tupl1)\n", + "#2\n", + "tupl2 = () # option 2 with ()\n", + "print(type(tupl2), tupl2)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating a non-empty tuple using brackets or # Creating a non-empty tuple using comma. Can we change an element of a tuple?" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "my tuple (26.5, 'Oil', False, 'some additional stuff', 777)\n", + "A comma made tuple (2, 'hi!', 228)\n", + "4th element of my_tuple: some additional stuff\n" + ] + }, + { + "ename": "TypeError", + "evalue": "'tuple' object does not support item assignment", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[8], line 13\u001b[0m\n\u001b[0;32m 10\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39m'\u001b[39m\u001b[39mA comma made tuple\u001b[39m\u001b[39m'\u001b[39m, comma_tuple)\n\u001b[0;32m 12\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39m'\u001b[39m\u001b[39m4th element of my_tuple:\u001b[39m\u001b[39m'\u001b[39m, my_tuple[\u001b[39m3\u001b[39m])\n\u001b[1;32m---> 13\u001b[0m my_tuple[\u001b[39m3\u001b[39m] \u001b[39m=\u001b[39m \u001b[39m'\u001b[39m\u001b[39mwill I change?\u001b[39m\u001b[39m'\u001b[39m\n", + "\u001b[1;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" + ] + } + ], + "source": [ + "my_var1 = 26.5\n", + "my_var2 = 'Oil'\n", + "my_var3 = False\n", + "\n", + "my_tuple = (my_var1, my_var2, my_var3, 'some additional stuff', 777)\n", + "print('my tuple', my_tuple)\n", + "\n", + "\n", + "comma_tuple = 2, 'hi!', 228\n", + "print('A comma made tuple', comma_tuple)\n", + "\n", + "print('4th element of my_tuple:', my_tuple[3])\n", + "my_tuple[3] = 'will I change?'" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "1RxahCCiHJRl", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Since tuples are immutable, it has no append() method nor any other methods that alter the object they target.\n", + "\n", + "You might think that tuple is a useless class. However, there are some reasons for it to exist:\n", + "\n", + "1.Storing constants & objects which shouldn't be changed.\n", + "2.Saving memory (tuple uses less memory to store the same data than a list). ``.__sizeof__()`` determines the size of a variable in bytes.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "A9cA-BpNIMzd", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "d7100baa-0a2c-4498-b8c0-01d1733e732f" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "size of a = 48 bytes\n", + "size of b = 64 bytes\n" + ] + } + ], + "source": [ + "my_name = 'Vasyan'\n", + "my_age = 27\n", + "is_student = True\n", + "\n", + "a = (my_name, my_age, is_student)\n", + "b = [my_name, my_age, is_student]\n", + "\n", + "print('size of a =', a.__sizeof__(), 'bytes') \n", + "print('size of b =', b.__sizeof__(), 'bytes')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "IYyveiZJJOTZ", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### dict\n", + "\n", + "After seeing lists and tuples, you may think:

\"Wow, storing all my variables within another variable is cool and gnarly! But... sometimes it's boring & inconvenient to access my data by using it's position within a tuple/list. Is there a way that I can store my object within a data structure but access it via something meaningful, like a keyword...?\"

Don't worry if you had this exact same thought.. Python had it as well!

Dictionaries are suited especially for that purpose — to each element you want to store, you give it a nickname (i.e., a key) and use that key to access the value you want.\n", + "\n", + "To create an empty dictionary we used ``{}`` or class constructor ``dict()``" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "r5vjDJ8CKaT8", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "46ee6315-d5a5-40a5-8db3-175a681dbf0c" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Type of empty_dict1 \n", + "Content of it -> {}\n", + "Type of empty_dict2 \n", + "Content of it -> {}\n" + ] + } + ], + "source": [ + "empty_dict1 = {}\n", + "print('Type of empty_dict1', type(empty_dict1))\n", + "print('Content of it ->', empty_dict1)\n", + "\n", + "\n", + "empty_dict2 = dict()\n", + "print('Type of empty_dict2', type(empty_dict2))\n", + "print('Content of it ->', empty_dict2)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To create a non-empty dictionary we specify pairs of **key:value** pattern" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Content of my_dict>>> {'name': 'Jarno', 'color': 'red', 'year': 2007, 'is cool': True, 6: 'it works', (2, 22): 'that is a strange key'}\n" + ] + } + ], + "source": [ + "my_dict = {\n", + " 'name': 'Jarno',\n", + " 'color': 'red',\n", + " 'year': 2007,\n", + " 'is cool': True,\n", + " 6: 'it works',\n", + " (2, 22): 'that is a strange key'\n", + "}\n", + "\n", + "print('Content of my_dict>>>', my_dict)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "2tQEahKqM9p8", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "In the last example, you can see that only strings, numbers, or tuples were used as keys. Dictionaries can only use immutable data (or numbers) as keys:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 242 + }, + "collapsed": true, + "id": "V38R-AweNbF7", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "6039cc3b-8d72-4f23-986f-e1027265aec5" + }, + "outputs": [ + { + "ename": "TypeError", + "evalue": "unhashable type: 'list'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[14], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m mutable_key_dict \u001b[39m=\u001b[39m {\n\u001b[0;32m 2\u001b[0m \u001b[39m5\u001b[39m: \u001b[39m'\u001b[39m\u001b[39mlets try\u001b[39m\u001b[39m'\u001b[39m,\n\u001b[0;32m 3\u001b[0m \u001b[39mTrue\u001b[39;00m: \u001b[39m'\u001b[39m\u001b[39mI hope it will run perfectly\u001b[39m\u001b[39m'\u001b[39m,\n\u001b[0;32m 4\u001b[0m \u001b[39m6.78\u001b[39m: \u001b[39m'\u001b[39m\u001b[39mheh\u001b[39m\u001b[39m'\u001b[39m,\n\u001b[0;32m 5\u001b[0m [\u001b[39m'\u001b[39m\u001b[39mNo problemo\u001b[39m\u001b[39m'\u001b[39m, \u001b[39m'\u001b[39m\u001b[39mright?\u001b[39m\u001b[39m'\u001b[39m]: \u001b[39mFalse\u001b[39;00m \n\u001b[0;32m 6\u001b[0m }\n\u001b[0;32m 8\u001b[0m \u001b[39mprint\u001b[39m(mutable_key_dict)\n", + "\u001b[1;31mTypeError\u001b[0m: unhashable type: 'list'" + ] + } + ], + "source": [ + "mutable_key_dict = {\n", + " 5: 'lets try',\n", + " True: 'I hope it will run perfectly',\n", + " 6.78: 'heh',\n", + " ['No problemo', 'right?']: False \n", + "}\n", + "\n", + "print(mutable_key_dict)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "erVQ8Yy6OFzW", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Alright, now it is time to access the data we have managed to store inside my_dict using keys!\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 313 + }, + "collapsed": true, + "id": "4_s_--xzORQx", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "d2dcabbb-057f-41e2-d54c-07d8ca3aa344" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Some random content of my_dict Jarno that is a strange key\n" + ] + } + ], + "source": [ + "print('Some random content of my_dict', my_dict['name'], my_dict[(2, 22)])" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Remember the mutable key dict? Let's make it work by omitting the list item." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Accessing weird dictionary...\n", + "I hope it will run perfectly\n", + "lets try\n", + "heh\n" + ] + } + ], + "source": [ + "mutable_key_dict = {\n", + " 5: 'lets try',\n", + " True: 'I hope it will run perfectly',\n", + " 6.78: 'heh'\n", + "}\n", + "\n", + "\n", + "print('Accessing weird dictionary...')\n", + "print(mutable_key_dict[True])\n", + "print(mutable_key_dict[5])\n", + "print(mutable_key_dict[6.78])" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Trying to access something we have and something we don't have" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "My favorite year is 2007\n" + ] + }, + { + "ename": "KeyError", + "evalue": "'song'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[17], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39m'\u001b[39m\u001b[39mMy favorite year is\u001b[39m\u001b[39m'\u001b[39m, my_dict[\u001b[39m'\u001b[39m\u001b[39myear\u001b[39m\u001b[39m'\u001b[39m])\n\u001b[1;32m----> 2\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39m'\u001b[39m\u001b[39mMy favorite song is\u001b[39m\u001b[39m'\u001b[39m, my_dict[\u001b[39m'\u001b[39;49m\u001b[39msong\u001b[39;49m\u001b[39m'\u001b[39;49m])\n", + "\u001b[1;31mKeyError\u001b[0m: 'song'" + ] + } + ], + "source": [ + "print('My favorite year is', my_dict['year'])\n", + "print('My favorite song is', my_dict['song'])" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "mVmNASbEPw27", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + ":::{warning} \n", + "It is best practice to use mainly strings as keys — the other options are weird and are almost never used.\n", + ":::\n", + "\n", + "What's next? Dictionaries are mutable, so let's go ahead and add some additional data and delete old ones." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "C2Tm8iaXQ4ej", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "62ea0bcc-a09b-474e-dd7b-e2688746ff31" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "my_dict right now {'name': 'Jarno', 'color': 'red', 'year': 2007, 'is cool': True, 6: 'it works', (2, 22): 'that is a strange key'}\n", + "my_dict after some operations {'name': 'Jarno', 'color': 'red', 'is cool': True, 6: 'it works', (2, 22): 'that is a strange key', 'new_element': 'magenta', 'weight': 27.8}\n" + ] + } + ], + "source": [ + "print('my_dict right now', my_dict)\n", + "\n", + "my_dict['new_element'] = 'magenta'\n", + "my_dict['weight'] = 27.8\n", + "del my_dict['year']\n", + "\n", + "print('my_dict after some operations', my_dict)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "J80LstNFSFeN", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "You can also print all keys present in the dictionary using the .keys() method, or check whether a certain key exists in a dictionary, as shown below. More operations can be found here." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "pEYa3nKRUZD1", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "2b850789-9071-414f-ce44-bb23203243a6" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dict_keys(['name', 'color', 'is cool', 6, (2, 22), 'new_element', 'weight'])\n", + "\n", + "my_dict has a ['name'] key: True\n" + ] + } + ], + "source": [ + "print(my_dict.keys())\n", + "print(\"\\nmy_dict has a ['name'] key:\", 'name' in my_dict)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### Real life example: \n", + "\n", + "Analyzing satellite metadata

Metadata is a set of data that describes and gives information about other data. For Sentinel-1, the metadata of the satellite is acquired as an .xml file. It is common for Dictionaries to play an important role in classifying this metadata. One could write a function to read and obtain important information from this metadata and store them in a Dictionary. Some examples of keys for the metadata of Sentinel-1 are:\n", + " \n", + "_dict_keys(['azimuthSteeringRate', 'dataDcPolynomial', 'dcAzimuthtime', 'dcT0', 'rangePixelSpacing', 'azimuthPixelSpacing', 'azimuthFmRatePolynomial', 'azimuthFmRateTime', 'azimuthFmRateT0', 'radarFrequency', 'velocity', 'velocityTime', 'linesPerBurst', 'azimuthTimeInterval', 'rangeSamplingRate', 'slantRangeTime', 'samplesPerBurst', 'no_burst'])_\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "XvpRgp7eUsLP", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "The last important thing for this Notebook are slices. Similar to how you can slice a string (shown in Section 1.4, in Notebook 1). This technique allows you to select a subset of data from an iterable (like a list or a tuple)." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "S96Y3-HcXN3P", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "b0d9151f-f476-4ffa-de00-74f85a4b962c" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The first three elements of x: [1, 2, 3]\n", + "[1, 2, 3]\n", + "The last element is 7 or 7 or 7\n", + "[1, 2, 3]\n", + "[1, 2, 3]\n" + ] + } + ], + "source": [ + "x = [1, 2, 3, 4, 5, 6, 7]\n", + "n = len(x) \n", + "\n", + "print('The first three elements of x:', x[0:3])\n", + "print(x[:3])\n", + "print('The last element is', x[6], 'or', x[n - 1], 'or', x[-1])\n", + "print(x[0:-4])\n", + "print(x[0:3:1])" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`````{admonition} Let's break it down\n", + "This code demonstrates how to select specific elements from a list in Python using slicing:\n", + "\n", + "1. The list `x` contains numbers from 1 to 7.\n", + "2. `x[0:3]` selects the first three elements of `x`.\n", + "3. `x[:3]` achieves the same result by omitting the starting index.\n", + "4. `x[6]`, `x[n - 1]`, and `x[-1]` all access the last element of `x`.\n", + "5. `x[0:-4]` selects elements from the beginning to the fourth-to-last element.\n", + "6. `x[0:3:1]` selects elements with a step size of 1.\n", + "\n", + "`````" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "d4v9TBKyZJEh", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Thus, the general slicing call is given by iterable[start:end:step]. \n", + "\n", + "Here's another example:\n", + "\n", + "You can select all even numbers using `[::2]` or reverse the list using `[::-1]` or select a middle subset for example `[5:9]`." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "GO8qP2d1ZXkq", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "832458e8-6202-4fa8-8898-6d2a2a1ad423" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Selecting all even numbers [0, 2, 4, 6, 8, 10]\n", + "All odd numbers [1, 3, 5, 7, 9]\n", + "Normal order [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n", + "Reversed order [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]\n", + "Numbers from 5 to 8: [5, 6, 7, 8]\n" + ] + } + ], + "source": [ + "numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n", + "\n", + "print('Selecting all even numbers', numbers[::2])\n", + "print('All odd numbers', numbers[1::2])\n", + "print('Normal order', numbers)\n", + "print('Reversed order', numbers[::-1])\n", + "print('Numbers from 5 to 8:', numbers[5:9])" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "Python_2_1.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/book/07/Exercises/01.ipynb b/book/matplotlib/Exercises/01.ipynb similarity index 100% rename from book/07/Exercises/01.ipynb rename to book/matplotlib/Exercises/01.ipynb diff --git a/book/07/Exercises/01.png b/book/matplotlib/Exercises/01.png similarity index 100% rename from book/07/Exercises/01.png rename to book/matplotlib/Exercises/01.png diff --git a/book/07/Exercises/02.png b/book/matplotlib/Exercises/02.png similarity index 100% rename from book/07/Exercises/02.png rename to book/matplotlib/Exercises/02.png diff --git a/book/07/Exercises/03.png b/book/matplotlib/Exercises/03.png similarity index 100% rename from book/07/Exercises/03.png rename to book/matplotlib/Exercises/03.png diff --git a/book/matplotlib/customize.ipynb b/book/matplotlib/customize.ipynb new file mode 100644 index 0000000..72fa842 --- /dev/null +++ b/book/matplotlib/customize.ipynb @@ -0,0 +1,129 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Customizing the Plot\n", + "\n", + "`matplotlib` provides numerous options for customizing your plots. Let's make some modifications to our previous plot. " + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure(figsize=(4,2))\n", + "plt.plot(x, y, linestyle='--', linewidth=5, color='r')\n", + "plt.xlim(2, 8) \n", + "plt.ylim(15, 25)\n", + "plt.xlabel('X-axis', fontsize=14, color='b')\n", + "plt.ylabel('Y-axis', fontsize=14, color='b')\n", + "plt.title('Customized plot', fontsize=18)\n", + "plt.grid(True)\n", + "plt.show() " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`````{admonition} Let's break it down\n", + "1. `plt.figure(figsize=(4,2))`: Creates a new plot with a width of 4 units and height of 2 units.\n", + "2. `plt.plot(x, y, linestyle='--', linewidth=5, color='r')`: Plots the x and y values with a dashed line style, a line width of 5 units, and a red color.\n", + "3. `plt.xlim(2, 8)`: Sets the x-axis limits to range from 2 to 8.\n", + "4. `plt.ylim(10, 30)`: Sets the y-axis limits to range from 15 to 25.\n", + "5. `plt.xlabel('X-axis', fontsize=14, color='b')`: Adds a blue x-axis label with a font size of 14 units.\n", + "6. `plt.ylabel('Y-axis', fontsize=14, color='b')`: Adds a blue y-axis label with a font size of 14 units.\n", + "7. `plt.title('Customized plot', fontsize=18)`: Sets the plot's title to 'Customized plot' with a font size of 18 units.\n", + "8. `plt.grid(True)`: Adds a grid to the plot.\n", + "9. `plt.show()`: Displays the plot on the screen.\n", + "`````" + ] + } + ], + "metadata": { + "hide_input": false, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/matplotlib/histograms.ipynb b/book/matplotlib/histograms.ipynb new file mode 100644 index 0000000..f344bfc --- /dev/null +++ b/book/matplotlib/histograms.ipynb @@ -0,0 +1,129 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Histograms\n", + "\n", + "A histogram is a graphical representation of the distribution of a dataset. It consists of a set of rectangular bars, where the width of each bar represents a range of values, and the height of each bar represents the frequency or count of data points falling within that range. Histograms are commonly used to visualize the distribution and frequency of data in various fields, including geosciences. For example, the study of earthquakes often involves analyzing the distribution of earthquake magnitudes. The magnitudes of earthquakes can provide valuable insights into the frequency and severity of seismic events.\n", + "\n", + "Let's consider a scenario where we have a dataset containing earthquake magnitudes. We want to visualize the distribution of these magnitudes using a histogram." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAi8AAAHHCAYAAAB3K7g2AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy88F64QAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA+PklEQVR4nO3dd3QUZf/+8WtJ2YQSCCQQkBA60hEQREC6lICCShUNiIo+KGCwoc9DERVUQCwIwlcJiHRRbHRBlKIUAanSawAJJYQSILl/f3CyPzabQLLZsBl4v87Zc5h77p353Ds7m4spuzZjjBEAAIBF5PJ2AQAAAJlBeAEAAJZCeAEAAJZCeAEAAJZCeAEAAJZCeAEAAJZCeAEAAJZCeAEAAJZCeAEAAJZCeEG2GDJkiGw22y1ZV+PGjdW4cWPH9PLly2Wz2TRnzpxbsv4ePXqoZMmSt2Rd7kpISNDTTz+tsLAw2Ww29e/f39sl3dD+/ftls9k0cuRIb5dyQynv85MnT3q7lBwlZR9cvnz5LVlf6s8A3P4IL7ipmJgY2Ww2xyMgIEDFihVTy5Yt9fHHH+vcuXMeWc/Ro0c1ZMgQbdy40SPL86ScXFtGvPvuu4qJidHzzz+vr776Sk888US6fUuWLOm0va9/tGrVyqN1/fzzzxoyZIhHl3m7ady4sWw2m8qVK5fm/MWLFzu2z60K7O6YNm2axowZ4+0ycJvw9XYBsI633npLpUqV0pUrV3Ts2DEtX75c/fv31+jRo/X999+rWrVqjr7//e9/9frrr2dq+UePHtXQoUNVsmRJ1ahRI8PPW7RoUabW444b1TZx4kQlJydnew1Z8csvv+i+++7T4MGDM9S/Ro0aGjBggEt7sWLFPFrXzz//rLFjxxJgbiIgIEC7d+/Wn3/+qTp16jjN+/rrrxUQEKBLly55qTpXDzzwgC5evCh/f39H27Rp07Rly5Ycf9QP1kB4QYa1bt1atWvXdkwPHDhQv/zyi9q2bauHHnpI27dvV2BgoCTJ19dXvr7Z+/a6cOGCcufO7fQB6Q1+fn5eXX9GnDhxQpUqVcpw/7vuukvdu3fPtnrOnz+vPHnyZNvybzdlypTR1atXNX36dKfwcunSJX377beKjIzUN99848UKneXKlUsBAQHeLgO3MU4bIUuaNm2q//3vfzpw4ICmTp3qaE/rmpfFixerQYMGKlCggPLmzasKFSrojTfekHTtHPm9994rSerZs6fjMHhMTIyka4fOq1SpovXr1+uBBx5Q7ty5Hc9N73x3UlKS3njjDYWFhSlPnjx66KGHdOjQIac+JUuWVI8ePVyee/0yb1ZbWte8nD9/XgMGDFB4eLjsdrsqVKigkSNHKvWPuNtsNr3wwgv67rvvVKVKFdntdlWuXFkLFixI+wVP5cSJE+rVq5eKFCmigIAAVa9eXZMnT3bMT7n2YN++ffrpp58cte/fvz9Dy7+RzZs3q0ePHipdurQCAgIUFhamp556SnFxcU79Ut4L27ZtU7du3RQcHKwGDRqoR48eGjt2rON1SHmkNmHCBJUpU0Z2u1333nuv1q5d69In5fULCAhQlSpV9O2337psl/Suw0i5viZle2ZmbGk5cOCAypYtqypVquj48eOSpDNnzqh///6O90PZsmX13nvvZeqIXdeuXTVz5kyn5/zwww+6cOGCOnXqlGYd//nPf1ShQgUFBgaqUKFC6tixY5rbfvPmzWrUqJECAwNVvHhxvf3225o0aZLLe6VkyZJq27atfv/9d9WpU0cBAQEqXbq0pkyZ4rS81K9148aN9dNPP+nAgQOO7ZyybVJOS6euK73tlfJ+CAwMVJ06dfTbb7+l+XolJiZq8ODBKlu2rOx2u8LDw/Xqq68qMTHRqd+NPpeQc3HkBVn2xBNP6I033tCiRYv0zDPPpNln69atatu2rapVq6a33npLdrtdu3fv1sqVKyVJFStW1FtvvaVBgwbp2WefVcOGDSVJ999/v2MZcXFxat26tbp06aLu3burSJEiN6zrnXfekc1m02uvvaYTJ05ozJgxat68uTZu3Og4QpQRGantesYYPfTQQ1q2bJl69eqlGjVqaOHChXrllVd05MgRffjhh079f//9d82dO1f/+c9/lC9fPn388cd69NFHdfDgQRUqVCjdui5evKjGjRtr9+7deuGFF1SqVCnNnj1bPXr00JkzZ9SvXz9VrFhRX331lV566SUVL17ccSooNDT0hmO+cuVKmheh5smTx/HaLV68WHv37lXPnj0VFhamrVu3asKECdq6davWrFnjEkQ6duyocuXK6d1335UxRvfcc4+OHj2qxYsX66uvvkqzjmnTpuncuXPq3bu3bDab3n//fT3yyCPau3ev44jXokWL9Oijj6pSpUoaPny4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H12uOXF3bLly5dLUqVPVvn17derUST///LOaNm2qV155Rd9//73atm3ruKX4/Pnz+vvvvzVnzhzt379fISEhGR5v/vz5M/SNxG3bttVXX32l/Pnzq1KlSlq9erWWLFnicvv9q6++qqlTp6pFixZ68cUXHbdKlyhRQqdOnfLYEdFatWpp5syZio6O1r333qu8efOqXbt2qly5su677z4NHDhQp06dUsGCBTVjxgyXUOfn56e3335bvXv3VtOmTdW5c2ft27dPkyZNcrnm5YknntCsWbP03HPPadmyZapfv76SkpK0Y8cOzZo1SwsXLlTt2rUz9LmEHMp7NzrBKlJuZUx5+Pv7m7CwMNOiRQvz0UcfOd2SmyL1rdJLly41Dz/8sClWrJjx9/c3xYoVM127dnW5fXTevHmmUqVKxtfX1+n21etvF00tvVulp0+fbgYOHGgKFy5sAgMDTWRkpDlw4IDL80eNGmXuuusuY7fbTf369c26detclnmj2lLfKm2MMefOnTMvvfSSKVasmPHz8zPlypUzH3zwgUlOTnbqJ8n06dPHpab0buFO7fjx46Znz54mJCTE+Pv7m6pVq6Z5O7enbpW+fpyHDx82HTp0MAUKFDD58+c3HTt2NEePHjWSzODBgx39rr+dOLWrV6+aF1980YSGhhqbzeZ4z6TcvvzBBx+4PCf18o0x5ptvvjEVK1Y0drvdVKpUycydOzfN7fLvv/+aRx991OTOndsEBweb3r17my1btrjcKp2VsV24cME0atTI5M2b16xZs8YYc+39MHDgQFO2bFnj7+9vQkJCzP33329GjhxpLl++fMPtcaP3foq0bpU+ffq0472RN29e07JlS7Njx44031t//fWXadiwobHb7aZ48eJm+PDh5uOPPzaSzLFjxxz90nsfpbcPXn+rdEJCgunWrZspUKCAy3tpz549pnnz5sZut5siRYqYN954wyxevDjNW9s/++wzU6pUKWO3203t2rXNihUr0txfL1++bN577z1TuXJlY7fbTXBwsKlVq5YZOnSoOXv2rDEm459LyHlsxuTwqwIBwA09evTQ8uXLs/3usttV//799fnnnyshIYELV5HjcM0LANzhLl686DQdFxenr776Sg0aNCC4IEfimhcAuMPVq1dPjRs3VsWKFXX8+HF98cUXio+P1//+9z9vlwakifACAHe4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XgAAQLZyK7z4+/tr5syZGjZsmDZt2qTAwEBVrVpVERERnq4PAADAiVvhJUX58uVVvnx5T9UCAABwU26Fl6SkJMXExGjp0qU6ceKEkpOTneb/8ssvHikOAAAgNbfCS79+/RQTE6PIyEhVqVJFNpvN03UBAACkya3wMmPGDM2aNUtt2rTxdD0AAAA35Nat0v7+/ipbtqynawEAALgpt8LLgAED9NFHH8kY4+l6AAAAbsit00a///67li1bpvnz56ty5cry8/Nzmj937lyPFAcAAJCaW+GlQIEC6tChg6drAQAAuCm3wsukSZM8XQcAAECGuHXNiyRdvXpVS5Ys0eeff65z585Jko4ePaqEhASPFQcAAJCaW0deDhw4oFatWungwYNKTExUixYtlC9fPr333ntKTEzU+PHjPV0nAACAJDePvPTr10+1a9fW6dOnFRgY6Gjv0KGDli5d6rHiAAAAUnPryMtvv/2mVatWyd/f36m9ZMmSOnLkiEcKAwAASItbR16Sk5OVlJTk0n748GHly5cvy0UBAACkx63w8uCDD2rMmDGOaZvNpoSEBA0ePJifDAAAANnKrdNGo0aNUsuWLVWpUiVdunRJ3bp1065duxQSEqLp06d7ukYAAAAHt8JL8eLFtWnTJs2YMUObN29WQkKCevXqpccff9zpAl4AAABPcyu8SJKvr6+6d+/uyVoAAABuyq3wMmXKlBvOf/LJJ90qBgAA4GbcCi/9+vVzmr5y5YouXLggf39/5c6dm/ACAACyjVt3G50+fdrpkZCQoJ07d6pBgwZcsAsAALKV279tlFq5cuU0YsQIl6MyNzJu3DhVq1ZNQUFBCgoKUr169TR//nxPlQQAAG5DHgsv0rWLeI8ePZrh/sWLF9eIESO0fv16rVu3Tk2bNtXDDz+srVu3erIsAABwG3Hrmpfvv//eadoYo9jYWH366aeqX79+hpfTrl07p+l33nlH48aN05o1a1S5cmV3SgMAALc5t8JL+/btnaZtNptCQ0PVtGlTjRo1yq1CkpKSNHv2bJ0/f1716tVzaxkAAOD251Z4SU5O9lgBf//9t+rVq6dLly4pb968+vbbb1WpUqU0+yYmJioxMdExHR8f77E6AACANXj0mhd3VKhQQRs3btQff/yh559/XlFRUdq2bVuafYcPH678+fM7HuHh4be4WgAA4G1uHXmJjo7OcN/Ro0ffcL6/v7/Kli0rSapVq5bWrl2rjz76SJ9//rlL34EDBzqtOz4+ngADAMAdxq3w8tdff+mvv/7SlStXVKFCBUnSP//8Ix8fH9WsWdPRz2azZXrZycnJTqeGrme322W3290pGQAA3CbcCi/t2rVTvnz5NHnyZAUHB0u69sV1PXv2VMOGDTVgwIAMLWfgwIFq3bq1SpQooXPnzmnatGlavny5Fi5c6E5ZAADgDuBWeBk1apQWLVrkCC6SFBwcrLffflsPPvhghsPLiRMn9OSTTyo2Nlb58+dXtWrVtHDhQrVo0cKdsgAAwB3ArfASHx+vf//916X933//1blz5zK8nC+++MKd1QMAgDuYW3cbdejQQT179tTcuXN1+PBhHT58WN9884169eqlRx55xNM1AgAAOLh15GX8+PF6+eWX1a1bN125cuXagnx91atXL33wwQceLRAAAOB6boWX3Llz67PPPtMHH3ygPXv2SJLKlCmjPHnyeLQ4AACA1LL0JXWxsbGKjY1VuXLllCdPHhljPFUXAABAmtwKL3FxcWrWrJnKly+vNm3aKDY2VpLUq1evDN9pBAAA4A63wstLL70kPz8/HTx4ULlz53a0d+7cWQsWLPBYcQAAAKm5dc3LokWLtHDhQhUvXtypvVy5cjpw4IBHCgMAAEiLW0dezp8/73TEJcWpU6f4+n4AAJCt3AovDRs21JQpUxzTNptNycnJev/999WkSROPFQcAAJCaW6eN3n//fTVr1kzr1q3T5cuX9eqrr2rr1q06deqUVq5c6ekaAQAAHNw68lKlShX9888/atCggR5++GGdP39ejzzyiP766y+VKVPG0zUCAAA4ZPrIy5UrV9SqVSuNHz9eb775ZnbUBAAAkK5MH3nx8/PT5s2bs6MWAACAm3LrtFH37t35RWgAAOAVbl2we/XqVX355ZdasmSJatWq5fKbRqNHj/ZIcQAAAKllKrzs3btXJUuW1JYtW1SzZk1J0j///OPUx2azea46AACAVDIVXsqVK6fY2FgtW7ZM0rWfA/j4449VpEiRbCkOAAAgtUxd85L6V6Pnz5+v8+fPe7QgAACAG3Hrgt0UqcMMAABAdstUeLHZbC7XtHCNCwAAuJUydc2LMUY9evRw/PjipUuX9Nxzz7ncbTR37lzPVQgAAHCdTIWXqKgop+nu3bt7tBgAAICbyVR4mTRpUnbVAQAAkCFZumAXAADgViO8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAASyG8AAAAS/FqeBk+fLjuvfde5cuXT4ULF1b79u21c+dOb5YEAAByOK+Gl19//VV9+vTRmjVrtHjxYl25ckUPPvigzp8/782yAABADubrzZUvWLDAaTomJkaFCxfW+vXr9cADD3ipKgAAkJN5NbykdvbsWUlSwYIF05yfmJioxMREx3R8fPwtqQsAkPNs377d2yXcEUJCQlSiRAlvl+Ekx4SX5ORk9e/fX/Xr11eVKlXS7DN8+HANHTr0FlcGAMhJkhJOSzabunfv7u1S7ggBgbm1c8f2HBVgckx46dOnj7Zs2aLff/893T4DBw5UdHS0Yzo+Pl7h4eG3ojwAQA6RnJggGaNCbQfIrxB/A7LTlbhDivtxlE6ePEl4Se2FF17Qjz/+qBUrVqh48eLp9rPb7bLb7bewMgBATuVXKFz2sLLeLgNe4NXwYozRiy++qG+//VbLly9XqVKlvFkOAACwAK+Glz59+mjatGmaN2+e8uXLp2PHjkmS8ufPr8DAQG+WBgAAciivfs/LuHHjdPbsWTVu3FhFixZ1PGbOnOnNsgAAQA7m9dNGAAAAmcFvGwEAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEshvAAAAEvxanhZsWKF2rVrp2LFislms+m7777zZjkAAMACvBpezp8/r+rVq2vs2LHeLAMAAFiIrzdX3rp1a7Vu3dqbJQAAAIvxanjJrMTERCUmJjqm4+PjvVgNAADwBktdsDt8+HDlz5/f8QgPD/d2SQAA4BazVHgZOHCgzp4963gcOnTI2yUBAIBbzFKnjex2u+x2u7fLAAAAXmSpIy8AAABePfKSkJCg3bt3O6b37dunjRs3qmDBgipRooQXKwMAADmVV8PLunXr1KRJE8d0dHS0JCkqKkoxMTFeqgoAAORkXg0vjRs3ljHGmyUAAACL4ZoXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKYQXAABgKTkivIwdO1YlS5ZUQECA6tatqz///NPbJQEAgBzK6+Fl5syZio6O1uDBg7VhwwZVr15dLVu21IkTJ7xdGgAAyIG8Hl5Gjx6tZ555Rj179lSlSpU0fvx45c6dW19++aW3SwMAADmQV8PL5cuXtX79ejVv3tzRlitXLjVv3lyrV6/2YmUAACCn8vXmyk+ePKmkpCQVKVLEqb1IkSLasWOHS//ExEQlJiY6ps+ePStJio+P93htCQkJ19Z5bLeSL1/y+PJxzZW4Q5J4nbMbr/Otwet8a/A63zpXTh2WdO1voif/1qYsyxjj3gKMFx05csRIMqtWrXJqf+WVV0ydOnVc+g8ePNhI4sGDBw8ePHjcBo9Dhw65lR+8euQlJCREPj4+On78uFP78ePHFRYW5tJ/4MCBio6OdkwnJyfr1KlTKlSokGw2W7bX62nx8fEKDw/XoUOHFBQU5O1ybpk7ddwSY78Tx36njlti7Hfi2DM6bmOMzp07p2LFirm1Hq+GF39/f9WqVUtLly5V+/btJV0LJEuXLtULL7zg0t9ut8tutzu1FShQ4BZUmr2CgoLuqDd3ijt13BJjvxPHfqeOW2Lsd+LYMzLu/Pnzu718r4YXSYqOjlZUVJRq166tOnXqaMyYMTp//rx69uzp7dIAAEAO5PXw0rlzZ/37778aNGiQjh07pho1amjBggUuF/ECAABIOSC8SNILL7yQ5mmi253dbtfgwYNdToXd7u7UcUuM/U4c+506bomx34ljv1Xjthnj7n1KAAAAt57Xv2EXAAAgMwgvAADAUggvAADAUggvAADAUggv2WDEiBGy2Wzq379/un1iYmJks9mcHgEBAU59jDEaNGiQihYtqsDAQDVv3ly7du3K5uqzJiNjb9y4scvYbTabIiMjHX169OjhMr9Vq1a3YAQZN2TIEJca77777hs+Z/bs2br77rsVEBCgqlWr6ueff3aab4VtntlxT5w4UQ0bNlRwcLCCg4PVvHlz/fnnn059rLC9pcyP/XbazzM79ttlP5ekI0eOqHv37ipUqJACAwNVtWpVrVu37obPWb58uWrWrCm73a6yZcsqJibGpc/YsWNVsmRJBQQEqG7dui77RU6Q2bHPnTtXLVq0UGhoqIKCglSvXj0tXLjQqY87n52pEV48bO3atfr8889VrVq1m/YNCgpSbGys43HgwAGn+e+//74+/vhjjR8/Xn/88Yfy5Mmjli1b6tKlnPlDZBkd+9y5c53GvWXLFvn4+Khjx45O/Vq1auXUb/r06dlZvlsqV67sVOPvv/+ebt9Vq1apa9eu6tWrl/766y+1b99e7du315YtWxx9rLLNMzPu5cuXq2vXrlq2bJlWr16t8PBwPfjggzpy5IhTPytsbylzY5dur/08M2O/Xfbz06dPq379+vLz89P8+fO1bds2jRo1SsHBwek+Z9++fYqMjFSTJk20ceNG9e/fX08//bTTH/GZM2cqOjpagwcP1oYNG1S9enW1bNlSJ06cuBXDyhB3xr5ixQq1aNFCP//8s9avX68mTZqoXbt2+uuvv5z6ZXY/cuHWLyIhTefOnTPlypUzixcvNo0aNTL9+vVLt++kSZNM/vz5052fnJxswsLCzAcffOBoO3PmjLHb7Wb69OkerNozMjP21D788EOTL18+k5CQ4GiLiooyDz/8sOcL9aDBgweb6tWrZ7h/p06dTGRkpFNb3bp1Te/evY0x1tnmmR13alevXjX58uUzkydPdrRZYXsbk/mx3077eVa3u1X389dee800aNAgU8959dVXTeXKlZ3aOnfubFq2bOmYrlOnjunTp49jOikpyRQrVswMHz48awV7kDtjT0ulSpXM0KFDHdNZfS8ZYwxHXjyoT58+ioyMVPPmzTPUPyEhQREREQoPD9fDDz+srVu3Oubt27dPx44dc1pW/vz5VbduXa1evdrjtWdVZsd+vS+++EJdunRRnjx5nNqXL1+uwoULq0KFCnr++ecVFxfnqXI9ZteuXSpWrJhKly6txx9/XAcPHky37+rVq11en5YtWzq2p5W2eWbGndqFCxd05coVFSxY0KndCttbyvzYb6f9PCvb3ar7+ffff6/atWurY8eOKly4sO655x5NnDjxhs+52b5++fJlrV+/3qlPrly51Lx58xy13d0Ze2rJyck6d+6cy/6elfeSxGkjj5kxY4Y2bNig4cOHZ6h/hQoV9OWXX2revHmaOnWqkpOTdf/99+vw4cOSpGPHjkmSy88kFClSxDEvp8js2K/3559/asuWLXr66aed2lu1aqUpU6Zo6dKleu+99/Trr7+qdevWSkpK8lTZWVa3bl3FxMRowYIFGjdunPbt26eGDRvq3LlzafY/duzYDbenVbZ5Zsed2muvvaZixYo5fXBbYXtLmR/77bSfZ2W7W3k/37t3r8aNG6dy5cpp4cKFev7559W3b19Nnjw53eekt6/Hx8fr4sWLOnnypJKSknL8dndn7KmNHDlSCQkJ6tSpk6Mtq58hkjht5AkHDx40hQsXNps2bXK0ZfbUyeXLl02ZMmXMf//7X2OMMStXrjSSzNGjR536dezY0XTq1MkjdXtCVsf+7LPPmqpVq9603549e4wks2TJEndLzXanT582QUFB5v/+7//SnO/n52emTZvm1DZ27FhTuHBhY4x1tnlqNxv39YYPH26Cg4Od3i9pscL2NiZzYzfGuvt5WjIzdivv535+fqZevXpObS+++KK577770n1OuXLlzLvvvuvU9tNPPxlJ5sKFC+bIkSNGklm1apVTn1deecXUqVPHc8VnkTtjv97XX39tcufObRYvXnzDfpndj4zhtJFHrF+/XidOnFDNmjXl6+srX19f/frrr/r444/l6+ubof9F+Pn56Z577tHu3bslSWFhYZKk48ePO/U7fvy4Y15OkJWxnz9/XjNmzFCvXr1uup7SpUsrJCTE8frkRAUKFFD58uXTrTEsLOyG29Mq2zy1m407xciRIzVixAgtWrTophd1W2F7Sxkfewqr7udpyejYrb6fFy1aVJUqVXJqq1ix4g1Pc6S3rwcFBSkwMFAhISHy8fHJ8dvdnbGnmDFjhp5++mnNmjXrppcTZHY/kjht5BHNmjXT33//rY0bNzoetWvX1uOPP66NGzfKx8fnpstISkrS33//raJFi0qSSpUqpbCwMC1dutTRJz4+Xn/88Yfq1auXbWPJrKyMffbs2UpMTFT37t1vup7Dhw8rLi7O8frkRAkJCdqzZ0+6NdarV89pe0rS4sWLHdvTKts8tZuNW7p2R82wYcO0YMEC1a5d+6bLtML2ljI29utZdT9PS0bHbvX9vH79+tq5c6dT2z///KOIiIh0n3Ozfd3f31+1atVy6pOcnKylS5fmqO3uztglafr06erZs6emT5/udGt8ejK7H0nitFF2SX3q5IknnjCvv/66Y3ro0KFm4cKFZs+ePWb9+vWmS5cuJiAgwGzdutXRZ8SIEaZAgQJm3rx5ZvPmzebhhx82pUqVMhcvXryVQ8m0m409RYMGDUznzp1d2s+dO2defvlls3r1arNv3z6zZMkSU7NmTVOuXDlz6dKl7Cw9UwYMGGCWL19u9u3bZ1auXGmaN29uQkJCzIkTJ4wxruNeuXKl8fX1NSNHjjTbt283gwcPNn5+fubvv/929LHCNs/suEeMGGH8/f3NnDlzTGxsrONx7tw5Y4x1trcxmR/77bSfZ3bsKay+n//555/G19fXvPPOO2bXrl2OUyFTp0519Hn99dfNE0884Zjeu3evyZ07t3nllVfM9u3bzdixY42Pj49ZsGCBo8+MGTOM3W43MTExZtu2bebZZ581BQoUMMeOHbul47sRd8b+9ddfG19fXzN27Fin/f3MmTOOPjd7L2UE4SWbpP4D3qhRIxMVFeWY7t+/vylRooTx9/c3RYoUMW3atDEbNmxwWkZycrL53//+Z4oUKWLsdrtp1qyZ2blz5y0agftuNnZjjNmxY4eRZBYtWuTy/AsXLpgHH3zQhIaGGj8/PxMREWGeeeaZHLVTG3Pt1seiRYsaf39/c9ddd5nOnTub3bt3O+anNe5Zs2aZ8uXLG39/f1O5cmXz008/Oc23wjbP7LgjIiKMJJfH4MGDjTHW2d7GZH7st9N+7s77/XbYz40x5ocffjBVqlQxdrvd3H333WbChAlO86OiokyjRo2c2pYtW2Zq1Khh/P39TenSpc2kSZNclvvJJ5843h916tQxa9asycZRuCezY2/UqFGa+/v1742bvZcywmaMMRk/TgMAAOBdXPMCAAAshfACAAAshfACAAAshfACAAAshfACAAAshfACAAAshfACAAAshfACIMcbMmSIatSokS3LjomJUYECBbJl2QCyB+EFgJMePXrIZrPpueeec5nXp08f2Ww29ejR45bW9PLLLzv9DkyPHj3Uvn37W1oDgJyD8ALARXh4uGbMmKGLFy862i5duqRp06apRIkSt7yevHnzqlChQrd8vQByJsILABc1a9ZUeHi45s6d62ibO3euSpQooXvuucfRtmDBAjVo0EAFChRQoUKF1LZtW+3Zs8dpWatWrVKNGjUUEBCg2rVr67vvvpPNZtPGjRslScuXL5fNZtPSpUtVu3Zt5c6dW/fff7/Tr9lef9poyJAhmjx5subNmyebzSabzably5c7lnPmzBnH8zZu3Cibzab9+/c72mJiYlSiRAnlzp1bHTp0UFxcnMv4582bp5o1ayogIEClS5fW0KFDdfXq1Sy8ogA8ifACIE1PPfWUJk2a5Jj+8ssv1bNnT6c+58+fV3R0tNatW6elS5cqV65c6tChg5KTkyVJ8fHxateunapWraoNGzZo2LBheu2119Jc35tvvqlRo0Zp3bp18vX11VNPPZVmv5dfflmdOnVSq1atFBsbq9jYWN1///0ZGtMff/yhXr166YUXXtDGjRvVpEkTvf322059fvvtNz355JPq16+ftm3bps8//1wxMTF65513MrQOANnP19sFAMiZunfvroEDB+rAgQOSpJUrV2rGjBlavny5o8+jjz7q9Jwvv/xSoaGh2rZtm6pUqaJp06bJZrNp4sSJCggIUKVKlXTkyBE988wzLut755131KhRI0nS66+/rsjISF26dEkBAQFO/fLmzavAwEAlJiYqLCwsU2P66KOP1KpVK7366quSpPLly2vVqlVasGCBo8/QoUP1+uuvKyoqSpJUunRpDRs2TK+++qoGDx6cqfUByB4ceQGQptDQUEVGRiomJkaTJk1SZGSkQkJCnPrs2rVLXbt2VenSpRUUFKSSJUtKkg4ePChJ2rlzp6pVq+YUQOrUqZPm+qpVq+b4d9GiRSVJJ06c8OSQtH37dtWtW9eprV69ek7TmzZt0ltvvaW8efM6Hs8884xiY2N14cIFj9YDwD0ceQGQrqeeekovvPCCJGns2LEu89u1a6eIiAhNnDhRxYoVU3JysqpUqaLLly9nel1+fn6Of9tsNklynH7KiFy5rv1fzBjjaLty5Uqm60hISNDQoUP1yCOPuMxLfRQIgHcQXgCkq1WrVrp8+bJsNptatmzpNC8uLk47d+7UxIkT1bBhQ0nS77//7tSnQoUKmjp1qhITE2W32yVJa9euzXJd/v7+SkpKcmoLDQ2VJMXGxio4OFiSHBcFp6hYsaL++OMPp7Y1a9Y4TdesWVM7d+5U2bJls1wngOzBaSMA6fLx8dH27du1bds2+fj4OM0LDg5WoUKFNGHCBO3evVu//PKLoqOjnfp069ZNycnJevbZZ7V9+3YtXLhQI0eOlPT/j664o2TJktq8ebN27typkydP6sqVKypbtqzCw8M1ZMgQ7dq1Sz/99JNGjRrl9Ly+fftqwYIFGjlypHbt2qVPP/3U6XoXSRo0aJCmTJmioUOHauvWrdq+fbtmzJih//73v27XC8CzCC8AbigoKEhBQUEu7bly5dKMGTO0fv16ValSRS+99JI++OADl+f+8MMP2rhxo2rUqKE333xTgwYNkpS1UzDPPPOMKlSooNq1ays0NFQrV66Un5+fpk+frh07dqhatWp67733XO4kuu+++zRx4kR99NFHql69uhYtWuQSSlq2bKkff/xRixYt0r333qv77rtPH374oSIiItyuF4Bn2cz1J4gBIJt9/fXX6tmzp86ePavAwEBvlwPAgrjmBUC2mjJlikqXLq277rpLmzZt0muvvaZOnToRXAC4jfACIFsdO3ZMgwYN0rFjx1S0aFF17NiRL3wDkCWcNgIAAJbCBbsAAMBSCC8AAMBSCC8AAMBSCC8AAMBSCC8AAMBSCC8AAMBSCC8AAMBSCC8AAMBSCC8AAMBS/h903yzyYwO93QAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "earthquake_magnitudes = [4.5, 5.2, 4.8, 5.7, 4.9, 6.2, 5.1,\n", + " 5.5, 4.6, 5.9, 5.3, 4.7, 5.8, 4.4,\n", + " 4.8, 5.1, 5.3, 5.2, 4.9, 5.4, 5.6]\n", + "\n", + "plt.hist(earthquake_magnitudes, bins=5, edgecolor='black')\n", + "plt.xlabel('Magnitude')\n", + "plt.ylabel('Frequency')\n", + "plt.title('Distribution of Earthquake Magnitudes')\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`````{admonition} Let's break it down\n", + "In the example, we first define the earthquake magnitudes in the `earthquake_magnitudes` list. We then create a histogram using `plt.hist()`, where `earthquake_magnitudes` is the data, and `bins=5` specifies the number of bins or bars in the histogram. The `edgecolor='black'` parameter sets the color of the edges of the bars.\n", + "\n", + "We then set the x-axis label as 'Magnitude', the y-axis label as 'Frequency', and the title as 'Distribution of Earthquake Magnitudes' using the appropriate `plt.xlabel()`, `plt.ylabel()`, and `plt.title()` functions.\n", + "\n", + "Finally, we display the histogram on the screen using `plt.show()`.\n", + "\n", + "The resulting histogram will visualize the distribution of earthquake magnitudes, showing the frequency of magnitudes falling within each bin. This information can help geoscientists understand the distribution and characteristics of earthquakes in the studied region.\n", + "`````" + ] + } + ], + "metadata": { + "hide_input": false, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/matplotlib/intro.md b/book/matplotlib/intro.md new file mode 100644 index 0000000..fba20d5 --- /dev/null +++ b/book/matplotlib/intro.md @@ -0,0 +1,6 @@ +# Matplotlib + +This chapter is all about ... + +% a short overview for this chapter + diff --git a/book/matplotlib/introduction.ipynb b/book/matplotlib/introduction.ipynb new file mode 100644 index 0000000..c5c6a52 --- /dev/null +++ b/book/matplotlib/introduction.ipynb @@ -0,0 +1,131 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "## Introduction\n", + "Matplotlib is a Python module that allows you to create visualizations. Until now, you have probably used Excel to make graphs, but Python offers much more versatility. In this section, you will learn how to use matplotlib to make good-looking graphs.\n", + "\n", + "As always, let's import the module. We will also import numpy and pandas." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "From the matplotlib library we will discuss the following functions:\n", + "- plt.subplot()\n", + "- plt.plot()\n", + "- plt.title()\n", + "- plt.suptitle()\n", + "- plt.xlabel() and plt.ylabel()\n", + "- plt.xlim() and plt.ylim()\n", + "- plt.legend()\n", + "- plt.grid()\n", + "- plt.show()" + ] + } + ], + "metadata": { + "hide_input": false, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/matplotlib/nutshell.md b/book/matplotlib/nutshell.md new file mode 100644 index 0000000..dc2a019 --- /dev/null +++ b/book/matplotlib/nutshell.md @@ -0,0 +1,3 @@ +# Matplotlib: in a Nutshell + +Nutshell. \ No newline at end of file diff --git a/book/07/In_a_Nutshell/01.ipynb b/book/matplotlib/nutshell/nutshell.ipynb similarity index 99% rename from book/07/In_a_Nutshell/01.ipynb rename to book/matplotlib/nutshell/nutshell.ipynb index ba32610..fbf93dd 100644 --- a/book/07/In_a_Nutshell/01.ipynb +++ b/book/matplotlib/nutshell/nutshell.ipynb @@ -5,15 +5,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# 7. Matplotlib" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 7.1 Introduction\n", + "## Introduction\n", "\n", "Welcome to the fascinating world of `matplotlib`! `Matplotlib` is a powerful Python module that empowers you to create impressive visualizations. If you're tired of basic graphs in Excel, `matplotlib` is your gateway to a new level of creativity and versatility. With it, you can bring your data to life by crafting captivating graphs that effectively communicate your insights. In this section, you'll learn how to harness the power of `matplotlib` to create visually appealing and engaging graphs.\n", "\n", @@ -259,13 +251,6 @@ "The line \"`from mpl_toolkits.mplot3d import Axes3D`\" imports the Axes3D module from the `mpl_toolkits.mplot3d` package. This module provides the necessary tools and functions for creating 3D plots in `matplotlib`.\n", "```" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/book/matplotlib/scatter.ipynb b/book/matplotlib/scatter.ipynb new file mode 100644 index 0000000..2b19a68 --- /dev/null +++ b/book/matplotlib/scatter.ipynb @@ -0,0 +1,148 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Scatter plot.\n", + "\n", + "A scatter plot is a type of plot used to display the relationship between two variables. In civil engineering, scatter plots can be used to analyze various aspects of data. Let's consider a scenario where civil engineers are studying the relationship between the compressive strength of concrete and the curing time. To investigate this relationship, the engineers collect data from concrete samples. For each sample, they measure the compressive strength after different curing times. The collected data might look like this:\n", + "\n", + "| Curing Time (days) | Compressive Strength (MPa) |\n", + "|--------------------|----------------------------|\n", + "| 3 | 18 |\n", + "| 7 | 28 |\n", + "| 14 | 38 |\n", + "| 21 | 46 |\n", + "| 28 | 55 |\n", + "\n", + "To visualize this data, the engineers can create a scatter plot, where the x-axis represents the curing time in days, and the y-axis represents the compressive strength in megapascals (MPa). Each data point in the plot corresponds to a specific curing time and the corresponding compressive strength. By examining the scatter plot, the civil engineers can observe the trend or pattern of the data points. They can determine if there is a correlation between curing time and compressive strength, and analyze how the strength changes with the increase in curing time. \n", + "\n", + "Let's create the corresponding scatter plot:" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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sDA8+OCDRvsvXryIIUOGwM3NDXfddVeDa5Xm5eXhxRdfRFhYGFxdXREREYFZs2YZxabVatGjR49653744YdwcXFBUVERAODTTz/FfffdB1dXV2g0Gjz22GM4ePCg4fiQkBA88sgjWLly5S3viWyDs1CSWWpra/HTTz9Bq9VCqVRate5nn30WL730EmbNmgU3N7dGjzty5AgWLVqEhQsX4vr165g2bRqee+45w7J0QggMHToUly5dwscffwyVSoVFixbhjz/+gELRePtm/PjxyM3NxZo1a7Bz504AgJeXV5MxT5o0CWPHjsWECRPw73//G88//zx+++03HD9+HB999BGys7Mxbdo0hIWFGboviouL8dhjj8HDwwPLli2DSqXCsmXL8MQTT+D06dNo27Zto9f7/vvv0b1793r7hw4ditzcXHz44Yfw9vbGwoULkZOTg9at//e/ekFBAdRqNZYsWYI2bdrg1KlTmDdvHvLy8rBixQoANxa2HjhwIDIzMxEVFWU499NPP8VTTz0FtVqNvXv3Yty4cXj11VcxaNAgVFRU4Oeff64393z37t2xffv2Jn9/ZEP2/lOCWqb8/HwBQMyYMeOWx549e1YAMFoMWoj63QgrVqwQAMTChQvr1QHAaEHwXr16CXd3d3H58uV65+fk5Agh/tedtHfvXsMxZWVlQqVS3bL7orHumpv3181S+frrrxv26XQ60apVK9GuXTtx7do1w36tViseeOABw89z5swRKpVKXLp0ybCvqqpKBAcHi9dee63R2PR6vXB2djb6fQghxDfffCMAiB07dhjF4unp2eT91tTUiNWrV4vWrVuLq1evCiGEuH79uggODja6r2PHjgkA4rvvvhNCCLFo0SKhVqsbrbfOihUrhCRJorS09JbHkvWxu4YsIkmS1euMi4sz6bgHHnjA6KFjhw4dANzoAgGAgwcPwtvbG48//rjhGA8PD5ssy9evXz/Dv1UqFdq2bYuePXsa/ZUTGRmJnJwcw8/fffcd+vTpA7VajdraWtTW1qJVq1bo1auXUZfHzYqLi1FdXV3vgeuBAwegUqnwxBNPGMXy50W4gRt/4SQnJ6NDhw5wdXWFUqnEqFGjUFtbi+zsbACAQqHAuHHjsGrVKtTW1gK40YoPCQkx/P66dOmCoqIijB07Ftu3b2908WsfHx8IIeqtEEa3B5M8mUWj0cDFxQXnz5+3et03L/zdmJsXl3ZycgIAVFVVAbjR99zQyJOmukHM1VAsDe2riw240W2yadMmKJVKo+3zzz83+jK4WV0dzs7ORvsbu9+bf5/JycmYPn06hg4dis2bN+Pnn3/G+++/b1Q3ALz44ou4cuUKtm3bhpqaGnzxxRcYO3asoavriSeewOeff47//ve/iI2NhY+PD0aPHm3or69TF2dlZWWj90S2wz55Mkvr1q3Ro0cP7NixA7W1tUZ9vjdzcXEBAFy7ds1of3FxcYPHW+uvg4CAgAbHkF++fNkq9VtKrVZjwIAB+Oc//1mv7OYEfvN5AOr1fTd2vze3oFNTUzFkyBAkJSUZ9p04caLeeUFBQRgwYAA+/fRT1NbWoqCgAC+88ILRMc899xyee+45FBQUYPPmzUhMTIRSqcTy5csNx9TFqdFoGr0nsh225Mls06ZNQ35+Pt58880Gy7dt2wbgRstZqVTi5MmThrJr165hz549No3v4Ycfhk6nw969ew37ysvLjdYrbYyTk1O9kTDWFhMTgxMnTuDee+/FQw89ZLTdf//9jZ7n4uKC4OBgnD171mj/I488gpKSEsPDYgAoKSnB999/b3RcZWWl4a+eOqtXr27wWhMmTMDWrVvxzjvvoG/fvggJCWnwOB8fH4wbNw79+vUz+pyBG6OrVCpVi1r425GwJU9mGzRoEF5//XXMmzcPJ06cwDPPPAMfHx+cPXsWn376KUpKSjBo0CAoFAoMHz4c7733Hu655x74+PjgvffegxDCJn36dQYOHIguXbrg2WefRVJSEry9vfH222/D09OzydE1AHDvvfeitrYWKSkp6N69O7y8vIxGmVjDtGnTsHr1avTq1QuvvPIKgoODceXKFRw4cACBgYFITExs9NwePXrUG2o5YMAAdOnSBaNGjcJbb70Fb29vJCUl1RsZ1K9fP6SkpOC9995DZGQkvvjiC6N1bP8sLi4Ovr6+yMjIwNq1a43K5s6di8LCQvTu3Rtt27bFsWPH8O2332LatGlGxx06dAjdu3e/5e+cbMTOD37JAWzatEnExMQIb29voVQqxd133y1efvllcfr0acMxly9fFsOGDRNeXl7irrvuEsnJyY2Orrly5Uq9a6CB0TVxcXFGx/z6668CgNi1a5dhX05Ojhg0aJBwcXERAQEBIikpSYwdO9ZolEtDampqxF//+lfh5+cnJEkSvXr1EkI0Prrm4MGDRueHhISI+Ph4o30NjdjJy8sT48aNM6z9GxQUJJ5++mnx008/NRnfhg0bhIuLS70RKzk5OSIuLs5wvwsWLKj3ey4rKxNjx44Vbdq0EW3atBETJkwQW7ZsafA+hBDipZdeEm3atBFVVVVG+7ds2SL69u0rfH19hbOzswgPDxdz584VNTU1hmOuXbsm1Gq1WL58eZP3Q7bDNV7pjnLt2jV06NABjz/+uGFMeEtUU1OD4OBgvPXWWxg9erTNrqPX6xEeHo4nn3wSy5Ytk33+1q1b8eyzz+LChQvNZs6fOw27a8ihffLJJ9Dr9YiKikJxcTE+/PBDnDt3DuvWrbN3aBZRKpWYMWMGUlJSbJLkr127ht9++w3r169HTk4OJk+ebFY9ixcvxvTp05ng7YhJnhyai4sLFi5ciHPnzgEAOnfujK1bt+Khhx6yb2BWMHHiRJSWlqKgoAA+Pj5WrfvixYt45JFH4Ovri/fee8+s5xHl5eXo1atXk88WyPbYXUNE5MD4uJuIyIExyRMROTAmeSIiB8YkT0TkwJjkiYgcGJM8EZEDY5InInJgTPJERA6MSZ6IyIH9P9khWQ34s8yzAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "curing_time = [3,7,14,21,28]\n", + "compressive_strength = [10,20,30,40,50]\n", + "\n", + "fig, ax = plt.subplots(figsize = (4,3))\n", + "ax.scatter(curing_time, compressive_strength, color='black', s=100)\n", + "ax.set_xlabel('Curing time (days)', fontsize=11)\n", + "ax.set_ylabel('Compressive strength (MPa)', fontsize=11)\n", + "plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "`````{admonition} Let's break it down\n", + "1. `curing_time = [3,7,14,21,28]` and `compressive_strength = [10,20,30,40,50]`: These lines define two lists representing the curing time and corresponding compressive strength data points.\n", + "2. `fig, ax = plt.subplots(figsize=(4, 3))`: This line creates a plot with a figure size of 4 units wide and 3 units high. The plot will contain the figure (`fig`) and axes (`ax`) objects.\n", + "3. `ax.scatter(curing_time, compressive_strength, color='gray', s=100)`: This line creates a scatter plot using the data from `curing_time` and `compressive_strength`. The dots are colored gray and have a size of 100 units.\n", + "4. `ax.set_xlabel('Curing time (days)', fontsize=11)`: This line sets the x-axis label as 'Curing time (days)' with a font size of 11 units.\n", + "5. `ax.set_ylabel('Compressive strength (MPa)', fontsize=11)`: This line sets the y-axis label as 'Compressive strength (MPa)' with a font size of 11 units.\n", + "6. `plt.show()`: This line displays the plot on the screen.\n", + "`````\n", + "\n", + ":::{note}\n", + "Notice the line `fig, ax = plt.subplots(figsize=(8, 6))`.\n", + "\n", + "When plotting with `matplotlib`, we often work with two main objects: the figure (`fig`) and the axes (`ax`).\n", + "- The figure (`fig`) is the entire window or page that everything is drawn on.\n", + "- The axes (`ax`) represents the actual plot or chart area within the figure.\n", + "\n", + "This is special helpful when dealing wit multiple subplots.\n", + ":::" + ] + } + ], + "metadata": { + "hide_input": false, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/matplotlib/simple-plot.ipynb b/book/matplotlib/simple-plot.ipynb new file mode 100644 index 0000000..0c6455c --- /dev/null +++ b/book/matplotlib/simple-plot.ipynb @@ -0,0 +1,135 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Simple plot\n", + "Let's start by creating a simple line plot of the equation $y=3x+5$. We will use numpy to create an array which acts as our x-axis" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "x = np.linspace(0,10)\n", + "y = 3*x + 5\n", + "\n", + "plt.figure(figsize=(6,3))\n", + "plt.plot(x, y)\n", + "plt.xlabel('X-axis')\n", + "plt.ylabel('Y-axis')\n", + "plt.title('Line Plot')\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`````{admonition} Let's break it down\n", + "Here's a breakdown of what each line does:\n", + "1. `x = np.linspace(0, 10)`: This line generates a sequence of evenly spaced numbers between 0 and 10. `np.linspace()` creates an array of numbers with a specified start and end point.\n", + "2. `y = 3*x + 5`: This line calculates the values for the y-axis based on the values of x. It uses a simple equation `3*x + 5`, which means each y-value is obtained by multiplying the corresponding x-value by 3 and adding 5.\n", + "3. `plt.figure(figsize=(6,3))`: This line creates a new figure (or plot) with a specified size. The `figsize` parameter sets the width and height of the figure. In this case, the width is 6 units and the height is 3 units.\n", + "4. `plt.plot(x, y)`: This line plots the x and y values on the figure. It takes the x and y values as input and connects them with a line.\n", + "5. `plt.xlabel('X-axis')`: This line sets the label for the x-axis of the plot to 'X-axis'.\n", + "6. `plt.ylabel('Y-axis')`: This line sets the label for the y-axis of the plot to 'Y-axis'.\n", + "7. `plt.title('Line Plot')`: This line sets the title of the plot to 'Line Plot'.\n", + "8. `plt.show()`: This line displays the plot on the screen. `plt.show()` is a function that shows the plot that has been created.\n", + "`````" + ] + } + ], + "metadata": { + "hide_input": false, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/matplotlib/subplots.ipynb b/book/matplotlib/subplots.ipynb new file mode 100644 index 0000000..84b0320 --- /dev/null +++ b/book/matplotlib/subplots.ipynb @@ -0,0 +1,250 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Subplots\n", + "\n", + "In Python, subplots refer to the division of a single figure into multiple smaller plots or subplots. Each subplot is an independent plot area within the larger figure. Subplots are useful when you want to display multiple plots or visualizations side by side or in a grid-like arrangement.\n", + "\n", + "The `subplots()` function in the matplotlib library is used to create subplots. It allows you to specify the number of rows and columns in the subplot grid, which determines the overall layout of the subplots.\n", + "\n", + "Here's an example to help you understand subplots. We will use the dataset of a sample of 100 vehicles corresponding to the 3-axle vehicle type _3C_ (remember the Maximum bending moment on a simply supported bridge example on `numpy` section?)\n", + "\n", + "First we will read the data set using `pandas`" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
A1_kNA2_kNA3_kND1_mD2_m
042.177.565.35.11.4
148.780.150.25.41.2
251.790.261.65.21.2
341.275.758.65.41.2
425.048.433.55.61.2
\n", + "
" + ], + "text/plain": [ + " A1_kN A2_kN A3_kN D1_m D2_m\n", + "0 42.1 77.5 65.3 5.1 1.4\n", + "1 48.7 80.1 50.2 5.4 1.2\n", + "2 51.7 90.2 61.6 5.2 1.2\n", + "3 41.2 75.7 58.6 5.4 1.2\n", + "4 25.0 48.4 33.5 5.6 1.2" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dataset = pd.read_csv(\"https://raw.githubusercontent.com/\"\n", + " \"mike-mendoza/Bivariate_NPBN_workshop_files/\"\n", + " \"a991bc3d9391a92437af1c3d69ae9fdfe6baf6da/\"\n", + " \"files_pyhton_book_test/V3AX_WIM_BR.csv\")\n", + "dataset.head()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's create one figure with one histogram per colum in the dataset using `for` loop." + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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cR1vH8unT59K+2Nubi78/PzElStXsr2Osl6Lhw4dEiNHjhQVKlQQ5ubmYuDAgeLx48dq2/Dx8RE+Pj5qbZmZmeKrr74Snp6eQqlUigoVKggvLy8RHBwsHfeIiAjRvXt34eTkJIyNjYWTk5MYMGCAuHr1ar7HLrd6385OZGSkACAiIyPzXF9umYiNjRUAxNdff51tmbePrRBC3LhxQwwZMkQ4ODgIIyMjUblyZdG1a1exefPmfPfp8ePHYvDgwcLS0lJYWVmJwYMHi7NnzwoAaq+5guZGCCHmzJkjKleuLMqVKycAiNjYWCGEEDt27BD169cXJiYmwtXVVXz11Vfi559/Vpvn77//FgMGDBBVq1YVSqVS2NnZia5du4ro6Ohsta9cuVJ4eXkJU1NTYWFhIerVqyemTp0q7t+/L82TkJAgunTpIiwsLASAbK8ZIiIiOVIIUcQrVxIREZFWnDt3Do0aNcKvv/6KgQMH6rscIiIiIqJixWtKERER6cGzZ8+ytS1evBjlypVDmzZt9FAREREREZFu8ZpSREREerBgwQKcOXMG7dq1g6GhIfbs2YM9e/Zg5MiRcHZ21nd5RERERETFjqfvERER6cGBAwcQHByMy5cvIy0tDVWrVsXgwYPx+eefw9CQfzMiIiIiotKPnVJERERERERERKRzvKYUERERERERERHpHDuliIiIiIiIiIhI59gpRUREREREREREOsdOKSIiIiIiIiIi0jl2ShERERERERERkc6xU4qIiIiIiIiIiHSOnVJERERERERERKRz7JQiIiIiIiIiIiKdY6cUERERERERERHpHDuliIiIiIiIiIhI59gpRUREREREREREOsdOKSIiIiIiIiIi0jl2ShERERERERERkc6xU4qIiIiIiIiIiHSOnVJERERERERERKRz7JQiIiIiIiIiIiKdY6cUERERERERERHpHDuliIiIiIiIiIhI59gpRUREREREREREOsdOKSIiIiIiIiIi0jl2ShERERERERERkc6xU4qIiIiIiIiIiHSOnVJERERERERERKRz7JSiXMXFxUGhUCA8PFzfpRBRITC7RPLE7BLp3qxZs6BQKPSyHVdXVwQEBBT7tolKI2a39GCnVCm0bNkyKBQKNGvWTN+lZLNhwwYMGjQIHh4eUCgUaNu2rb5LIioxSmp2Hz9+jK+//hpt2rSB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iIiIiIgKwNHREXXq1FFrq127Nm7fvg0AcHBwAAAkJiaqzZOYmChNe9v06dORnJwsPe7cuVMMlRPpll47pdLT09GgQQMsXbo013k6duyI+Ph46fHbb7/psEIiIiIiIiKiwmnZsiViYmLU2q5evQoXFxcAgJubGxwcHBARESFNT0lJwalTp+Dt7Z3jOpVKpXSqHk/Zo9JCr6fvderUCZ06dcpzHqVSmWtPMREREREREVFJM3HiRLRo0QLz5s1D37598ddff2HlypVYuXIlgNfX3ZkwYQLmzp0LDw8PuLm5YcaMGXByckKPHj30WzyRDpX4a0pFRUXBzs4OFSpUQPv27TF37lxUrFgx1/nfvvhbSkqKLsokIiIiIiIiAgA0adIEW7duxfTp0zF79my4ublh8eLFGDhwoDTP1KlTkZ6ejpEjRyIpKQmtWrXC3r17YWJiosfKiXSrRHdKdezYEb169YKbmxtu3LiBzz77DJ06dcKJEydgYGCQ4zJl4eJvrtN2abxs3PwustsuEcmTpu8ZfL8gKhr+viZ6jVkgfevatSu6du2a63SFQoHZs2dj9uzZxVYDc0AlXYnulOrfv7/0/3r16qF+/fqoXr06oqKi0KFDhxyXmT59OiZNmiQ9T0lJgbOzc7HXSkREREREREREBafXC50XVrVq1VCpUiVcv34913l48TciIiIiIiIiopJPVp1Sd+/exePHj+Ho6KjvUoiIiIiIiIiIqAj0evpeWlqa2qin2NhYnDt3DjY2NrCxsUFwcDB69+4NBwcH3LhxA1OnToW7uzv8/Pz0WDURERERERERERWVXjuloqOj0a5dO+l51rWg/P39ERoaigsXLmD16tVISkqCk5MT3nvvPcyZMwdKpVJfJRMRERERERERkRbo9fS9tm3bQgiR7REeHg5TU1Ps27cPDx48QGZmJuLi4rBy5UrY29vrs2QiIiIiIp0JDQ1F/fr1pWulent7Y8+ePdL058+fIzAwEBUrVoS5uTl69+6NxMREPVZMRERUcLK6phQRERERUVlSpUoVzJ8/H2fOnEF0dDTat2+P7t2749KlSwCAiRMn4o8//sCmTZtw6NAh3L9/H7169dJz1URERAWj19P3iIiIiIgod926dVN7/uWXXyI0NBQnT55ElSpV8NNPP2HdunVo3749ACAsLAy1a9fGyZMn0bx5c32UTEREVGAcKUVEREREJAOvXr3C+vXrkZ6eDm9vb5w5cwYvXryAr6+vNE+tWrVQtWpVnDhxQo+VEhERFQxHShEREREVE9dpuzReNm5+Fy1WQnJ28eJFeHt74/nz5zA3N8fWrVtRp04dnDt3DsbGxrC2tlab397eHgkJCXmuMyMjAxkZGdLzlJSU4iidiIgoT+yUolJN0y8D/CJAREREJUXNmjVx7tw5JCcnY/PmzfD398ehQ4eKtM6QkBAEBwdrqUIiIiLN8PQ9IiIiIqISzNjYGO7u7vDy8kJISAgaNGiA7777Dg4ODsjMzERSUpLa/ImJiXBwcMhzndOnT0dycrL0uHPnTjHuARERUc7YKUVEREREJCMqlQoZGRnw8vKCkZERIiIipGkxMTG4ffs2vL2981yHUqmEpaWl2oOIiEjXePoeEREREVEJNX36dHTq1AlVq1ZFamoq1q1bh6ioKOzbtw9WVlYYPnw4Jk2aBBsbG1haWmLs2LHw9vbmnfeIiEgWOFKKiIiojDh8+DC6desGJycnKBQKbNu2TW16QEAAFAqF2qNjx476KZaIAAAPHjzAkCFDULNmTXTo0AGnT5/Gvn378O677wIAFi1ahK5du6J3795o06YNHBwcsGXLFj1XTUREVDAcKUVERFRGpKeno0GDBhg2bBh69eqV4zwdO3ZEWFiY9FypVOqqPCLKwU8//ZTndBMTEyxduhRLly7VUUVERETaw04pIiKiMqJTp07o1KlTnvMolcp8L5BMRERERKQNPH2PiIiIJFFRUbCzs0PNmjUxatQoPH78WN8lEREREVEpxZFSREREBOD1qXu9evWCm5sbbty4gc8++wydOnXCiRMnYGBgkOMyGRkZyMjIkJ6npKToqlwiIiIikjl2ShEREREAoH///tL/69Wrh/r166N69eqIiopChw4dclwmJCQEwcHBuiqRiIiIiEoRnr5HREREOapWrRoqVaqE69ev5zrP9OnTkZycLD3u3LmjwwqJiIiISM7K/Egp12m7NF42bn4XLVZCRERUsty9exePHz+Go6NjrvMolUreoY+IiIiINMKRUkRUaIcPH0a3bt3g5OQEhUKBbdu2qU0PCAiAQqFQe3Ts2FE/xRKRJC0tDefOncO5c+cAALGxsTh37hxu376NtLQ0TJkyBSdPnkRcXBwiIiLQvXt3uLu7w8/PT7+FExEREVGpxE4pIiq09PR0NGjQAEuXLs11no4dOyI+Pl56/PbbbzqskIhyEh0djUaNGqFRo0YAgEmTJqFRo0aYOXMmDAwMcOHCBbz//vuoUaMGhg8fDi8vLxw5coQjoYiIiIioWJT50/eIqPA6deqETp065TmPUqmEg4ODjioiooJo27YthBC5Tt+3b58OqyEiIiKiso4jpYioWERFRcHOzg41a9bEqFGj8PjxY32XRERERERERCUIR0oRkdZ17NgRvXr1gpubG27cuIHPPvsMnTp1wokTJ2BgYJDjMhkZGcjIyJCep6Sk6KpcIiIiIiIi0gN2ShGR1vXv31/6f7169VC/fn1Ur14dUVFR6NChQ47LhISEIDg4WFclEhERERERkZ7x9D0iKnbVqlVDpUqVcP369VznmT59OpKTk6XHnTt3dFghERERERER6RpHShFRsbt79y4eP34MR0fHXOdRKpW8wxcREREREVEZwk4pIiq0tLQ0tVFPsbGxOHfuHGxsbGBjY4Pg4GD07t0bDg4OuHHjBqZOnQp3d3f4+fnpsWoiIiIiIiIqSdgpRUSFFh0djXbt2knPJ02aBADw9/dHaGgoLly4gNWrVyMpKQlOTk547733MGfOHI6EIiIiIiIiIgk7pUgnXKft0njZuPldtFgJaUPbtm0hhMh1+r59+3RYDREREREREckRL3ROREREREREREQ6x04pIiIiIiIiIiLSOXZKERERERERERGRzvGaUkREOiLHa6sVpWYiIiIiIqK8cKQUERERERERERHpHEdKEREREZVAHKlIREREpR1HShERERERERERkc6xU4qIiIiIiIiIiHSOnVJERERERERERKRz7JQiIiIiIiIiIiKd44XOqcTjhV6JiIiIiIiISh+NRkrdvHlT23UQkQ4wu0TyxOwSyROzSyRPzC6R7mjUKeXu7o527drh119/xfPnz7VdExEVE2aXSJ6YXSJ5YnaJ5InZJdIdjTql/v77b9SvXx+TJk2Cg4MDPv74Y/z111/aro2ItIzZJZInZpdInphdInkqjuzOnz8fCoUCEyZMkNqeP3+OwMBAVKxYEebm5ujduzcSExOLWD2RvGjUKdWwYUN89913uH//Pn7++WfEx8ejVatWqFu3LhYuXIiHDx9qu04i0gJml0iemF0ieWJ2ieRJ29k9ffo0VqxYgfr166u1T5w4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BwsLCyQkJCAhIQHPnj0D8Dqnw4cPx6RJkxAZGYkzZ85g6NCh8Pb25p33qEwp1EiprA+ob7fpSlpaGm7cuIHBgwfrbJtEpYG+s0tEmtFHdj09PfHnn39Kzw0NNbonClGZpsvsZl0Q+e3Ti/K6WDLA67AS5USb2Q0NDQUAtG3bVq09LCwMAQEBAIBFixahXLly6N27NzIyMuDn54dly5ZptD0iuSr06XsBAQHSeazPnz/HJ598ku1uBFu2bNFKcZMnT0a3bt3g4uKC+/fvIygoCAYGBhgwYIBW1k9UVug6u0SkHfrILu96S1R0cvi9y+uwEmWnzewWZJSViYkJli5diqVLl2pWMFEpUKhOKX9/f7XngwYN0moxb7t79y4GDBiAx48fw9bWFq1atcLJkydha2tbrNslKm10nd1Zs2Zl+6Bbs2ZNXLlypVi3S1Ta6Dq7QOHvektE2ekyu1mdyImJiXB0dJTaExMT0bBhw1yX43VYibLTx+9dorKuUJ1SYWFhxVVHjtavX6/T7RGVVrrOLsBTgIi0QdfZ1eSutzwFiCg7XWbXzc0NDg4OiIiIkDqhUlJScOrUKYwaNSrX5XgXL6Ls9PGZmais47dEIioWPAWISH40uestTwEiKn5paWlqN/qJjY3FuXPnYGNjg6pVq2LChAmYO3cuPDw84ObmhhkzZsDJyQk9evTQX9FEREQFUKS77xER5SbrFKBq1aph4MCBuH37dp7zZ2RkICUlRe1BRPpVkLveTp8+HcnJydLjzp07OqyQqGyIjo5Go0aN0KhRIwDApEmT0KhRI8ycORMAMHXqVIwdOxYjR45EkyZNkJaWhr1798LExESfZRMREeWLI6WISOs0OQWIoy0oi+u0XRovGze/ixYroYLc9ZanABEVv7Zt2+Z50WSFQoHZs2dj9uzZOqyKcsLfYUREhcORUkSkdZ06dcIHH3yA+vXrw8/PD7t370ZSUhI2btyY6zIcbUGkf5MnT8ahQ4cQFxeH48ePo2fPnrzrLREREREVG46UIqJiV5BTgDjagkj/eNdbIiIiItIldkoRUbEryClARKR/vOstEREREekST98jIq3jKUBERERERESUH46UIiKt4ylARERERIXDi6QTUVnETiki0jqeAkRERERERET54el7RERERERERESkc+yUIiIiIiIiIiIinWOnFBERERERERER6Rw7pYiIiIiIiIiISOfYKUVERERERERERDrHTikiIiIiIiIiItI5Q30XQFQSuU7bpfGycfO7aLESIiIiIiIiotKJI6WIiIiIiIiIiEjn2ClFREREREREREQ6x04pIiIiIiIiIiLSOXZKERERERERERGRzrFTioiIiIiIiIiIdI533yMiolKDd84kIiIiIpIPdkoRERERERHJGP8oQ0RyxdP3iIiIiIiIiIhI59gpRUREREREREREOsdOKSIiIiIiIiIi0jleU0pPinLeNxERERERERGR3HGkFBERERERERER6Rw7pYiIiIiIiIiISOd4+h4RERER6RVvZ09ERFQ2caQUERERERERERHpHDuliIiIiIiIiIhI53j6HhERERERFRuenll68WdLREXFkVJERERERERERKRz7JQiIiIiIiIiIiKdY6cUERERERERERHpHDuliIiIiIiIiIhI59gpRUREREREREREOse77xERERFRkRXlLlxEueHrioiodONIKSIiIiIiIiIi0jl2ShERERERERERkc6xU4qIiIiIiIiIiHSOnVJERERERERERKRzsrjQ+dKlS/H1118jISEBDRo0wJIlS9C0aVN9l0VE+WB2ieSJ2SWSJ2aXNMGLyesfs0tlWYkfKbVhwwZMmjQJQUFB+Pvvv9GgQQP4+fnhwYMH+i6NiPLA7BLJE7NLJE/MLpE8MbtU1pX4TqmFCxfio48+wtChQ1GnTh0sX74c5cuXx88//6zv0ogoD8wukTwxu0TyxOwSyROzS2Vdie6UyszMxJkzZ+Dr6yu1lStXDr6+vjhx4oQeKyOivDC7RPLE7BLJE7NLJE/MLlEJv6bUo0eP8OrVK9jb26u129vb48qVKzkuk5GRgYyMDOl5cnIyACAlJSXH+VUZ/2mpWqLXcnutvTlNCKGrcvSC2SU5YnaZXZInZpfZJXnK7bVWVnILFD67hc0tULTs5rXe0qasHafi2F9Ns1uiO6U0ERISguDg4Gztzs7OeqiGyiKrxfnPk5qaCisrq2KvRU6YXdI3ZlczzC7pG7OrGWaX9C2/7DK32ek6twV5f6Wyd5y0nd0S3SlVqVIlGBgYIDExUa09MTERDg4OOS4zffp0TJo0SXquUqnw5MkTVKxYEQqFItv8KSkpcHZ2xp07d2BpaandHdAz7lvJI4RAamoqnJyc9F1KsdJF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6tWrh/nz50t1+vn5YefOndi/fz+aNGmC5s2bY9GiRXBxcSnCESIqmZhdyo9CCCH0XQTp10cffYQrV67gyJEjWl+3q6srJkyYgAkTJmh93Vni4uLg5uaGs2fPomHDhsW2HaKShtklkh/mlog0ERAQgKSkJGzbtk1r69TFewZRWcfs5o8jpcqgb775BufPn8f169exZMkSrF69OsfTDrTlf//7H8zNzZGcnKz1dXfq1Amenp5aXy9RScTsEskPc0tE2rJz506Ym5tj586dRVrPvHnzYG5urvGoSyIqHGY3bxwpVQb17dsXUVFRSE1NRbVq1TB27Fh88sknxbKtW7du4cWLFwCAatWqFfoaGPm5d+8enj17BgCoWrUqjI2Ntbp+opKE2SWSH+aWiLThwYMHSElJAQA4OjrCzMxM43U9efIET548AQDY2trCyspKKzUSUXbMbv7YKUVERERERERERDrH0/eIiIiIiIiIiEjn2ClFREREREREREQ6x04pIiIiIiIiIiLSOXZKERERERERERGRzrFTioiIiIiIiIiIdI6dUkREREREREREpHPslCIiIiIiIiIiIp1jpxQREREREREREekcO6WIiIiIiIiIiEjn/h/jOBxoVLkrMAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "variable_names = ['Axle 1', 'Axle 2', 'Axle 3',\n", + " 'Inter-axle distance 1', 'Inter-axle distance 2']\n", + "\n", + "xlabels =['Weight [kN]', 'Weight [kN]', 'Weight [kN]',\n", + " 'Distance [m]', 'Distance [m]']\n", + "\n", + "fig, axes = plt.subplots(nrows=1, ncols=5, figsize=(12,3))\n", + "for i,column in enumerate(dataset.columns):\n", + " axes[i].hist(dataset[column])\n", + " axes[i].set_xlabel(xlabels[i])\n", + " axes[i].set_ylabel('Frequency')\n", + " axes[i].set_title(variable_names[i])\n", + "plt.suptitle('Histograms of variables in the dataset') \n", + "plt.tight_layout()\n", + "plt.show()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`````{admonition} Let's break it down\n", + "1. `variable_names` is a list containing the names of different variables in a dataset.\n", + "2. `xlabels` is a list containing the x-axis labels for each histogram.\n", + "3. The code creates a figure with 1 row and 5 columns of subplots using `plt.subplots(nrows=1, ncols=5, figsize=(12, 3))`.\n", + "4. `for i, column in enumerate(dataset.columns)` initiates a loop that iterates over the columns of the dataset. It uses the `enumerate()` function to retrieve both the index (`i`) and the column name (`column`) at each iteration.\n", + "5. It then loops over the columns of the dataset and creates a histogram for each column using `axes[i].hist(dataset[column])`.\n", + "6. The x-axis label, y-axis label, and title of each subplot are set using `axes[i].set_xlabel(xlabels[i])`, `axes[i].set_ylabel('Frequency')`, and `axes[i].set_title(variable_names[i])`, respectively.\n", + "7. The super title for the entire figure is set using `plt.suptitle('Histograms of variables in the dataset')`.\n", + "8. `plt.tight_layout()` adjusts the spacing between subplots.\n", + "9. Finally, `plt.show()` displays the figure with all the subplots.\n", + "`````\n", + "\n" + ] + } + ], + "metadata": { + "hide_input": false, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/modules/Exercises/01.ipynb b/book/modules/Exercises/01.ipynb new file mode 100644 index 0000000..6b39024 --- /dev/null +++ b/book/modules/Exercises/01.ipynb @@ -0,0 +1,292 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "# Exercises" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "::: {note}\n", + "You don't need to worry about using Interactive Jupyter Notebooks for these exercises. You can simply ignore the rocket icon ({fa}`rocket`) and go ahead to answer the questions using the knowledge you've gained from the chapter. Have fun!\n", + "::: " + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": { + "tags": [ + "remove-input" + ] + }, + "outputs": [], + "source": [ + "# jupyterquiz-import\n", + "#import json\n", + "#from jupyterquiz import display_quiz\n", + "#load all questions json file\n", + "#with open(\"01.json\", \"r\") as file:\n", + "# questions = json.load(file)\n", + "\n", + "#questions = [[q] for q in questions]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "su7ODKnqB7tv", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "## Exercise 5.1.1\n", + "\n", + "In the code cell bellow you can see a function that finds the greatest common divisor of any two numbers using the math module. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "YjB37kkNGsr9", + "outputId": "36e77aac-9e26-4c63-fbf5-e030e5539ab1" + }, + "outputs": [], + "source": [ + "import math\n", + "\n", + "def find_greatest_common_divisor(a, b):\n", + " greatest_common_divisor = math.gcds(a, b)\n", + " return greatest_common_divisor\n", + "\n", + "print('The greatest common divisor is:', find_greatest_common_divisor(2, 4))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-input" + ] + }, + "outputs": [], + "source": [ + "# jupyterquiz-exercise-2-1-1\n", + "#display_quiz(questions[0])" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "aaxayx2RH9IM", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "## (Searching) Exercise 5.1.2\n", + "\n", + "We can only take and store measurements at a limited number of locations and/or times. But what if we are interested in a value in between, i.e., at a location/time where we do not have a measurement? Then we can use interpolation to estimate that value. A popular, and simple, interpolation technique is linear interpolation. \n", + "Your task is to use the module scipy to perform a 1D linear interpolation between a set of known points, where x_known and y_known are arrays with the measured $x$ and $y$ values. Use Google to look up the 1D interpolation function in scipy.

In the code below there is something missing after `return` (look the three dots). What should be the correct missing code for the function to give us the desired result?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true, + "id": "ZazhpxxTIzxE" + }, + "outputs": [], + "source": [ + "from scipy import interpolate\n", + "\n", + "def interpolate_inbetween(x_known, y_known, x_predict):\n", + " f = interpolate.interp1d(x_known, y_known)\n", + " return ...\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-input" + ] + }, + "outputs": [], + "source": [ + "# jupyterquiz-exercise-2-1-2\n", + "#display_quiz(questions[1])" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "Ue4CKV8PKnBG", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "## (Searching) Exercise 5.1.3\n", + "\n", + "Now, let's try to measure the running time of a function, for that we will need the time module. Use it to measure the working time of the cool_function() below." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true, + "id": "C1aOizjOK7sl", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [], + "source": [ + "# you do not need to change anything in this cell\n", + "def cool_function():\n", + " x = 0\n", + " for i in range(100000000):\n", + " x += 1\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Which of the following functions will give us the working time of the cool_function()?" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "
\n", + "\n", + "* **Option A**\n", + "```python\n", + "def measure_time(func):\n", + " t0 = time.time()\n", + " t1 = time.time()\n", + " return t1 - t0\n", + "```\n", + "\n", + "* **Option B**\n", + "```python\n", + "def measure_time(func):\n", + " t0 = time.time()\n", + " func()\n", + " t1 = time.time()\n", + " return t1 - t0\n", + "```\n", + "* **Option C**\n", + "```python\n", + "def measure_time(func,t0,t1):\n", + " t0 = time.time()\n", + " func()\n", + " t1 = time.time()\n", + " return func\n", + "```\n", + "\n", + "
\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-input" + ] + }, + "outputs": [], + "source": [ + "# jupyterquiz-exercise-2-1-3\n", + "#display_quiz(questions[2])" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "Python_2_1.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "mude", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/book/modules/Exercises/01.json b/book/modules/Exercises/01.json new file mode 100644 index 0000000..a617970 --- /dev/null +++ b/book/modules/Exercises/01.json @@ -0,0 +1,195 @@ + +[ + { + "question": "What is the error? ", + "type": "many_choice", + "answers": [ + { + "answer": "Wrong arguments types when calling the function.", + "correct": false, + "feedback": "I hope not." + }, + { + "answer": "The module math has no attribute gcds ", + "correct": true, + "feedback": "Correct." + }, + { + "answer": "There is no error in the code. ", + "correct": false, + "feedback": "I hope not." + } + ] + }, + { + "question": "What should be the correct missing code for the function?", + "type": "many_choice", + "answers": [ + { + "answer": "f ", + "correct": false, + "feedback": "I hope not." + }, + { + "answer": " x_predict ", + "correct": false, + "feedback": "I hope not." + }, + { + "answer": " f(x_predict) ", + "correct": true, + "feedback": "Correct." + } + ] + }, + { + "question": "What is the correct answer?", + "type": "many_choice", + "answers": [ + { + "answer": "Option A", + "correct": false, + "feedback": "I hope not." + }, + { + "answer": "Option B", + "correct": true, + "feedback": "Correct." + }, + { + "answer": "Option C.", + "correct": false, + "feedback": "I hope not." + } + ] + }, + { + "question": "What is the error? ", + "type": "many_choice", + "answers": [ + { + "answer": "There is no error in the function.", + "correct": false, + "feedback": "I hope not." + }, + { + "answer": "A else statement is missing.", + "correct": false, + "feedback": "I hope not." + }, + { + "answer": "A else and a return: True statements are missing. ", + "correct": true, + "feedback": "Correct." + } + ] + }, + { + "question": "What will be the outcome of the above code?", + "type": "many_choice", + "answers": [ + { + "answer": "Sand", + "correct": true, + "feedback": "Correct." + }, + { + "answer": "Silt", + "correct": false, + "feedback": "I hope not." + }, + { + "answer": "Error", + "correct": false, + "feedback": "I hope not." + } + ] + }, + { + "question": "What is the correct answer?", + "type": "many_choice", + "answers": [ + { + "answer": "if x % 2 == 0 y = x ** 2 else y = x % 3. ", + "correct": false, + "feedback": "I hope not." + }, + { + "answer": "y = x ** 2 if x % 2 == 0 else x % 3. ", + "correct": true, + "feedback": "Correct." + }, + { + "answer": "x ** 2 if x % 2 == 0 else x % 3.", + "correct": false, + "feedback": "I hope not." + } + ] + }, + { + "question": "What is the error?.", + "type": "many_choice", + "answers": [ + { + "answer": "There is no error.", + "correct": false, + "feedback": "I hope not." + }, + { + "answer": "The argument must be a numpy array.", + "correct": false, + "feedback": "I hope not." + }, + { + "answer": "temp_fahrenheit must be a list ", + "correct": true, + "feedback": "Correct." + } + ] + }, + { + "question": "What is the correct answer?", + "type": "many_choice", + "answers": [ + { + "answer": "sorted(unsorted_list)[0]. ", + "correct": false, + "feedback": "I hope not." + }, + { + "answer": "sorted(unsorted_list)[::-1]. ", + "correct": true, + "feedback": "Correct." + }, + { + "answer": "sorted(unsorted_list)[:-1].", + "correct": false, + "feedback": "I hope not." + } + ] + }, + { + "question": "What is the correct answer?", + "type": "many_choice", + "answers": [ + { + "answer": "Option A", + "correct": false, + "feedback": "I hope not." + }, + { + "answer": "Option B", + "correct": true, + "feedback": "Correct." + }, + { + "answer": "Option C.", + "correct": false, + "feedback": "I hope not." + } + ] + } +] + + + diff --git a/book/modules/intro.md b/book/modules/intro.md new file mode 100644 index 0000000..cd9975e --- /dev/null +++ b/book/modules/intro.md @@ -0,0 +1,6 @@ +# Modules + +This chapter ... + +% a short overview for this chapter + diff --git a/book/modules/modules.ipynb b/book/modules/modules.ipynb new file mode 100644 index 0000000..c56ba9e --- /dev/null +++ b/book/modules/modules.ipynb @@ -0,0 +1,769 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "# Modules" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "fHmKWsUSKuj4", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "## Python Modules\n", + "\n", + "Previously, you have learned how to:

1) initialize variables in Python;
2) perform simple actions with them (eg.: adding numbers together, displaying variables content, etc);
3) work with functions (have your own code in a function to reuse it many times or use a function, which was written by another person).

However, the scope of the last Notebook was limited by your Python knowledge and available functions in standard/vanilla Python (so-called 'built-in' Python functions).\n", + "There are not many Python built-in functions that can be useful for you, such as functions for math, plotting, signal processing, etc. Luckily, there are countless modules/packages written by other people.\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "oyr90lgAQGtD", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### Python built-in modules\n", + "\n", + "By installing any version of Python, you also automatically install its built-in modules.

One may wonder — why do they provide some functions within built-in modules, but not directly as a built-in function, such as the abs() or print()?

The answers may vary, but, generally, it is to keep your code clean; compact; and, working.

It keeps your code clean and compact as you only load functions that you need. It keeps your code working as it allows you to define your own functions with (almost) any kind of name, and use them easily, without worrying that you might 'break' something if there is a function with the same name that does something completely different." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "67a2hkUyRh_P", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### math\n", + "\n", + "The math module is one of the most popular modules since it contains all implementations of basic math functions ($sin$, $cos$, $exp$, rounding, and other functions — the full list can be found here).

In order to access it, you just have to import it into your code with an import statement. Then using ``print()`` to show that ``math`` is actually a built-in Python module." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "A1WjrfHoHYFV", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "e14b2fc7-6b0b-4f6e-8342-45c3791030b9" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "import math\n", + "print(math) " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "0ssGu7FsTEtz", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "You can now use its functions like this:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "11FBTZH7TATg", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "41f2699c-47a3-4ed2-f7be-b1f2ea059819" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Square root of 16 is equal to 4\n" + ] + } + ], + "source": [ + "print(f'Square root of 16 is equal to {int(math.sqrt(16))}')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "0EscmfkpTxXv", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "You can also use the constants defined within the module, such as **`math.pi`**:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "DtwKkug2TiGT", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "60ffed22-e0e0-459b-e1dc-d35edfb5a3ff" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "π is equal to 3.141592653589793\n", + "π is equal to 3.14\n", + "π is equal to 3.1\n", + "π with two decimals is 3.14,with three decimals is 3.142 and with four decimals is 3.1416\n" + ] + } + ], + "source": [ + "print(f'π is equal to {math.pi}')\n", + "print('π is equal to {:.2f}'.format(math.pi)) \n", + "print('π is equal to {:.1f}'.format(math.pi))\n", + "print('π with two decimals is {:.2f},'\n", + " 'with three decimals is {:.3f} and with four decimals is {:.4f}'.\\\n", + " format(math.pi, math.pi, math.pi))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "`````{admonition} Let's break it down\n", + "\n", + "* ``print('π is equal to {:.2f}'.format(math.pi))`` print the variable up to some decimal, (two for example).\n", + "\n", + "* ``print('π is equal to {:.1f}'.format(math.pi))`` change the number 2 on the ':.2f' to print with more (or fewer) decimals.\n", + "\n", + "* The last line show how to print is quickly if you have to print a sentence with many variables in it.\n", + "\n", + "More information on printing best practices here.\n", + "\n", + "`````" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "M8OQGFnGf_S9", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### ``math.pi``\n", + "\n", + "As you can see, both constants and functions of a module are accessed by using: the module's name (in this case math) and a . followed by the name of the constant/function (in this case pi).

We are able to do this since we have loaded all contents of the module by using the import keyword. If we try to use these functions somehow differently — we will get an error:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 201 + }, + "collapsed": true, + "id": "98zHvteQUA3S", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "914a0a33-dfc6-45bc-d4c2-941ec4e666a9" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Square root of 16 is equal to\n", + "4.0\n" + ] + } + ], + "source": [ + "print('Square root of 16 is equal to')\n", + "print(sqrt(16))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "LRTVWDEqhGyk", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "You could, however, directly specify the functionality of the module you want to access. Then, the above cell would work.

This is done by typing: from module_name import necessary_functionality, as shown below:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "By8SDKMXhBKD", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "b277aeda-58a3-4e6d-de0e-038d843d77fe" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Square root of 16 is equal to 4.\n" + ] + } + ], + "source": [ + "from math import sqrt\n", + "\n", + "print(f'Square root of 16 is equal to {int(sqrt(16))}.')" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "pVo16M0whkK7", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "053cee25-dc6b-4604-d69c-1025bbf60e6c" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "π is equal to 3.141592653589793.\n" + ] + } + ], + "source": [ + "from math import pi\n", + "\n", + "print(f'π is equal to {pi}.')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### Listing all functions\n", + "\n", + "Sometimes, when you use a module for the first time, you may have no clue about the functions inside of it. In order to unveil all the potential a module has to offer, you can either access the documentation on the corresponding web resource or you can use some Python code.\n", + "\n", + "\n", + "You can listing all contents of a module using ``dir()``. To learn something about, let's say, ``hypot`` thingy you can type the module name - dot -function name, for example ``math.hypot``." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "contents of math: ['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']\n", + "math hypot is a \n" + ] + } + ], + "source": [ + "import math\n", + "print('contents of math:', dir(math))\n", + "print('math hypot is a', math.hypot) " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also use ``?`` or ``??`` to read the documentation about it in Python" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1;31mDocstring:\u001b[0m\n", + "hypot(*coordinates) -> value\n", + "\n", + "Multidimensional Euclidean distance from the origin to a point.\n", + "\n", + "Roughly equivalent to:\n", + " sqrt(sum(x**2 for x in coordinates))\n", + "\n", + "For a two dimensional point (x, y), gives the hypotenuse\n", + "using the Pythagorean theorem: sqrt(x*x + y*y).\n", + "\n", + "For example, the hypotenuse of a 3/4/5 right triangle is:\n", + "\n", + " >>> hypot(3.0, 4.0)\n", + " 5.0\n", + "\u001b[1;31mType:\u001b[0m builtin_function_or_method\n" + ] + } + ], + "source": [ + "math.hypot?" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "2SUM0W23oAdC", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### Python third-party modules\n", + "\n", + "Besides built-in modules, there are also modules developed by other people and companies, which can be also used in your code.\n", + "\n", + "These modules are not installed by default in Python, they are usually installed by using the 'pip' or 'conda' package managers and accessed like any other Python module.

This YouTube video explains how to install Python Packages with 'pip' and 'conda'.\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "_o1yzxJC0NaZ", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### numpy\n", + "\n", + "The numpy module is one of the most popular Python modules for numerical applications. Due to its popularity, developers tend to skip using the whole module name and use a smaller version of it (np). A different name to access a module can be done by using the as keyword, as shown below." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "collapsed": true, + "id": "qWOdG82IhoiX", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "99446932-b303-4d84-912a-e1d4fb90545d" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "\n", + "x = [0. 0.12822827 0.25645654 0.38468481 0.51291309 0.64114136\n", + " 0.76936963 0.8975979 1.02582617 1.15405444 1.28228272 1.41051099\n", + " 1.53873926 1.66696753 1.7951958 1.92342407 2.05165235 2.17988062\n", + " 2.30810889 2.43633716 2.56456543 2.6927937 2.82102197 2.94925025\n", + " 3.07747852 3.20570679 3.33393506 3.46216333 3.5903916 3.71861988\n", + " 3.84684815 3.97507642 4.10330469 4.23153296 4.35976123 4.48798951\n", + " 4.61621778 4.74444605 4.87267432 5.00090259 5.12913086 5.25735913\n", + " 5.38558741 5.51381568 5.64204395 5.77027222 5.89850049 6.02672876\n", + " 6.15495704 6.28318531]\n", + "\n", + "\n", + "y = [ 1. 0.99179001 0.96729486 0.92691676 0.8713187 0.80141362\n", + " 0.71834935 0.6234898 0.51839257 0.40478334 0.28452759 0.1595999\n", + " 0.03205158 -0.09602303 -0.22252093 -0.34536505 -0.46253829 -0.57211666\n", + " -0.67230089 -0.76144596 -0.8380881 -0.90096887 -0.94905575 -0.98155916\n", + " -0.99794539 -0.99794539 -0.98155916 -0.94905575 -0.90096887 -0.8380881\n", + " -0.76144596 -0.67230089 -0.57211666 -0.46253829 -0.34536505 -0.22252093\n", + " -0.09602303 0.03205158 0.1595999 0.28452759 0.40478334 0.51839257\n", + " 0.6234898 0.71834935 0.80141362 0.8713187 0.92691676 0.96729486\n", + " 0.99179001 1. ]\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "print(np)\n", + "x = np.linspace(0, 2 * np.pi, 50)\n", + "y = np.cos(x)\n", + "print('\\n\\nx =', x)\n", + "print('\\n\\ny =', y)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`````{admonition} Let's break it down\n", + "The code uses the ``numpy`` library in Python to perform the following tasks:\n", + "1. It imports the ``numpy`` library.\n", + "2. It prints information about the ``numpy`` package.\n", + "3. It creates an array ``x`` with 50 equally spaced values between $0$ and $2\\pi$.\n", + "4. It calculates the cosine of each element in the array ``x`` and stores the results in the array ``y``.\n", + "5. It prints the arrays ``x`` and ``y``.\n", + "\n", + "In summary, the code imports the ``numpy`` library, creates an array ``x`` with $50$ evenly spaced elements between $0$ and $2\\pi$, calculates the cosine of each element in ``x``, and finally prints the arrays ``x`` and ``y``.\n", + "````` " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "You will learn more about this and other packages in separate Notebooks since these packages are frequently used by the scientific programming community." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "bl_ufrrc2PGB", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### ``matplotlib``\n", + "\n", + "The matplotlib module is used to plot data. It contains a lot of visualization techniques and, for simplicity, it has many submodules within the main module. Thus, in order to access functions, you have to specify the whole path that you want to import.

For example, if the function you need is located within the matplotlib module and pyplot submodule, you need to import matplotlib.pyplot; then, the access command to that function is simply pyplot.your_function().

Below we use the data generated in the previous cell to create a simple plot using the pyplot.plot() function:\n", + "\n", + "In order to import a submodule the parent module must also be specified. It is common to import ``matplotlib.pyplot`` as ``plt``.\n", + "\n", + "The ``plt.plot()`` function takes x-axis values as the first argument and y-axis, or $f(x)$, values as the second argument\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 282 + }, + "collapsed": true, + "id": "COq85MFE06s1", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "67086bf1-4b12-4929-a420-ae9322bbbcce" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "plt.plot(x, y)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "``plt.scatter()`` works in a similar way, but it does not connect the dots." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 282 + }, + "collapsed": true, + "id": "bd01J-Dc8iDJ", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "outputId": "792ba793-3ff8-4f5a-bcdd-8271082d6c83" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.scatter(x, y)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "qdHLw0oC84pg", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### Loading Python files as modules\n", + "\n", + "Finally, you can also load your own (or somebody else's) Python files as modules. This is quite helpful, as it allows you to keep your code projects well-structured without the need to copy and paste everything.

In order to import another *.py file as a module, you only need to have that file and your Notebook file in the same directory and use the import keyword. More info on this here." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "lDKimbtECAAz", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "## Additional study material\n", + "\n", + "* Official Python Documentation - https://docs.python.org/3/tutorial/modules.html\n", + "* https://realpython.com/python-modules-packages/\n", + "* Think Python (2nd ed.) - Sections 3 and 14 \n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### After this Notebook you should be able to:\n", + "\n", + "- understand the difference between built-in and third-party modules\n", + "- use functions from the **`math`** module\n", + "- find available functions from any module\n", + "- generate an array for the x-axis\n", + "- calculate the **`cos`** or **`sin`** of the x-axis\n", + "- plot such functions\n", + "- understand how to load Python files as modules" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "Python_2_1.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/book/modules/nutshell.md b/book/modules/nutshell.md new file mode 100644 index 0000000..8157033 --- /dev/null +++ b/book/modules/nutshell.md @@ -0,0 +1,3 @@ +# Modules: in a Nutshell + +Nutshell. \ No newline at end of file diff --git a/book/02/In_a_Nutshell/01.ipynb b/book/modules/nutshell/modules.ipynb similarity index 75% rename from book/02/In_a_Nutshell/01.ipynb rename to book/modules/nutshell/modules.ipynb index bdae527..ace88d1 100644 --- a/book/02/In_a_Nutshell/01.ipynb +++ b/book/modules/nutshell/modules.ipynb @@ -5,7 +5,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# 2. Modules, conditions, data structures and loops" + "# Modules" ] }, { @@ -13,15 +13,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## 2.1 Python Modules" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Math " + "## Math " ] }, { @@ -94,7 +86,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Listing all functions " + "## Listing all functions " ] }, { @@ -147,7 +139,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Python third-party modules\n", + "## Python third-party modules\n", "\n", "Besides built-in modules, there are also modules developed by other people and companies, which can be also used in your code.\n", "\n", @@ -159,7 +151,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### numpy\n", + "## numpy\n", "\n", "The numpy module is one of the most popular Python modules for numerical applications. Due to its popularity, developers tend to skip using the whole module name and use a smaller version of it (np). A different name to access a module can be done by using the as keyword, as shown below. The **import numpy as np** statement imports the NumPy module, allowing us to use its functionalities." ] @@ -183,7 +175,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Matplotlib\n", + "## Matplotlib\n", "\n", "Matplotlib is a Python library widely used for creating visualizations and plots. It provides a simple and flexible way to display data in the form of graphs, charts, and other visual representations. It is commonly used in scientific and data analysis applications. \n", "\n", @@ -244,509 +236,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Loading Python files as modules\n", + "## Loading Python files as modules\n", "\n", "Finally, you can also load your own (or somebody else's) Python files as modules. This is quite helpful, as it allows you to keep your code projects well-structured without the need to copy and paste everything.

In order to import another *.py file as a module, you only need to have that file and your Notebook file in the same directory and use the import keyword. More info on this here." ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 2.2 Conditions and if statements\n", - "\n", - "\n", - "In previous sections, you have acquired essential skills in Python such as variable creation, operator utilization, and code analysis. These skills enable you to accomplish a wide range of tasks. However, there is still a need for increased flexibility. Manually modifying your code to accommodate different data and reverting those changes can be cumbersome. In this section, you will delve into the concept of code control, which allows you to navigate the execution of your code based on specific conditions. To achieve this, you will explore a fundamental programming construct called the if statement. Through this construct, you will gain the ability to selectively process data based on defined conditions, enhancing the adaptability and efficiency of your code.\n", - "\n", - "We have three sections:\n", - "\n", - "* If Statement: The if statement enables us to execute a block of code only if a specified condition is true. It provides a way to make decisions and selectively perform actions based on whether a condition evaluates to true or false.\n", - "\n", - "* Elif Statement: The elif statement allows us to consider multiple conditions one after another and execute different blocks of code based on the first condition that evaluates to true. It provides a means to handle various possibilities and choose the appropriate action based on the situation.\n", - "\n", - "* If-else Statement: The if-else statement combines the if and else statements to perform one action if a condition is true and a different action if the condition is false. It offers a way to provide alternative paths of execution, ensuring that the code responds differently based on whether a condition is met or not.\n", - "\n", - "These conditional statements allow you to make decisions and control the flow of your program based on specific conditions. For example like this: \n" - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "x is positive\n", - "x is non-positive\n", - "x is zero\n" - ] - } - ], - "source": [ - "x = 5\n", - "if x > 0:\n", - " print(\"x is positive\")\n", - "\n", - "x = -2\n", - "if x > 0:\n", - " print(\"x is positive\")\n", - "else:\n", - " print(\"x is non-positive\")\n", - "\n", - "x = 0\n", - "if x > 0:\n", - " print(\"x is positive\")\n", - "elif x < 0:\n", - " print(\"x is negative\")\n", - "else:\n", - " print(\"x is zero\")\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 2.3 Data Structures\n", - "\n", - "Welcome to an exciting new adventure in data management! In the previous module, you learned how to create variables, which was just the tip of the iceberg. Now, imagine a scenario where you have numerous variables or want to organize and access them within a single entity. That's where data structures come into play!\n", - "\n", - "Data structures are like superheroes that help us tackle complex data management challenges. They come in various forms, each with its unique purpose and complexity. Today, we'll dive into some of the superheroes of Python's built-in data structures: the mighty list, the versatile dict, and the steadfast tuple. These data structures provide us with powerful tools to store, organize, and manipulate data, enabling us to unleash the true potential of our code. Let's dive in and unlock the secrets of organized data!" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### List\n", - "A list is a powerful data structure in Python that allows you to store and manipulate an ordered collection of items. It's like having a magic box where you can keep multiple things together and change them whenever you want. Let's explore 4 different ways to create and use lists:" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "1. Creating an empty list:\n", - "You can create an empty list by simply using empty square brackets [ ]. It's like having a blank canvas ready to be filled with items." - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[2, 5, 3]\n" - ] - } - ], - "source": [ - "my_list = [2,5,3]\n", - "\n", - "print (my_list)\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "2. Creating an empty list - using the class constructor: You can also use the list class constructor list() to create an empty list. It's another way of preparing your container for future data." - ] - }, - { - "cell_type": "code", - "execution_count": 66, - "metadata": {}, - "outputs": [], - "source": [ - "my_list = list()\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "3. Creating a list from existing data: To create a list with existing data, you can directly enclose the items within square brackets [ ], separating them with commas. It's like assembling your collection of items in one go." - ] - }, - { - "cell_type": "code", - "execution_count": 67, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['apple', 'banana', 'orange', 'kiwi']\n" - ] - } - ], - "source": [ - "fruits = ['apple', 'banana', 'orange', 'kiwi']\n", - "print (fruits)\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "4. Creating a list from existing data: You can use the list constructor list( ) with an iterable (such as a string or another list) to create a new list containing the elements of that iterable. It's like transforming one collection into another." - ] - }, - { - "cell_type": "code", - "execution_count": 68, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[1, 2, 3, 4, 5]\n" - ] - } - ], - "source": [ - "numbers = list(range(1, 6)) # Creates a list [1, 2, 3, 4, 5]\n", - "print (numbers)\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### tuple\n", - "A tuple is a data structure in Python that allows you to store an ordered collection of items. Unlike lists, tuples are immutable, meaning their elements cannot be modified once they are assigned. Let's explore how to define tuples and create examples:" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "1. Defining a tuple using ( ) brackets or comma:\n", - "You can define a tuple by enclosing the items within parentheses () or by simply separating them with commas. It's like creating a fixed ensemble of elements." - ] - }, - { - "cell_type": "code", - "execution_count": 69, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(1, 2, 3)\n", - "(1, 2, 3)\n" - ] - } - ], - "source": [ - "my_tuple1 = (1, 2, 3)\n", - "my_tuple2 = 1, 2, 3\n", - "\n", - "print (my_tuple1)\n", - "print (my_tuple2)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "2. Creating a tuple using the tuple class constructor: You can also use the tuple class constructor tuple() to create a tuple. It accepts an iterable as an argument and generates a tuple with its elements. It's like assembling data into a coordinated ensemble." - ] - }, - { - "cell_type": "code", - "execution_count": 70, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(4, 5, 6)\n", - "(1, 2, 3)\n", - "(3, 5)\n", - "('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday')\n" - ] - } - ], - "source": [ - "my_tuple3 = tuple([4, 5, 6])\n", - "\n", - "coordinates = (3, 5) \n", - "days_of_week = tuple(['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']) \n", - "\n", - "my_tuple4 = (1, 2, 3)\n", - "print (my_tuple3)\n", - "print (my_tuple4)\n", - "print (coordinates)\n", - "print (days_of_week)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Dict\n", - "A dictionary is a versatile data structure in Python that allows you to store and retrieve data using a key-value pairing. It's like having a real-life dictionary where you can quickly look up information using specific words. Let's explore how to define dictionaries, we will explore 3 examples:" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "1. Creating a dictionary using { } brackets: You can create a dictionary by enclosing key-value pairs within curly braces { }, separating each pair with a colon ' : ' It's like building a repository of information with quick access to specific entries." - ] - }, - { - "cell_type": "code", - "execution_count": 71, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'name': 'John', 'age': 25, 'city': 'New York'}\n" - ] - } - ], - "source": [ - "my_dict = {\"name\": \"John\", \"age\": 25, \"city\": \"New York\"}\n", - "\n", - "print (my_dict)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "2. Creating an empty dictionary using the class constructor: You can also use the dict class constructor dict( ) to create an empty dictionary. It's like preparing a blank canvas to populate with key-value pairs later." - ] - }, - { - "cell_type": "code", - "execution_count": 72, - "metadata": {}, - "outputs": [], - "source": [ - "my_dict2 = dict()\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "3. Creating a non-empty dictionary by specifying pairs of key-value patterns: To create a dictionary with existing data, you can specify pairs of key-value patterns within the curly braces { }. Each key-value pair is separated by a colon : and pairs are separated by commas. It's like defining relationships between different pieces of information." - ] - }, - { - "cell_type": "code", - "execution_count": 73, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'name': 'Alice', 'age': 30, 'city': 'London'}\n" - ] - } - ], - "source": [ - "student_scores = {\"Alice\": 85, \"Bob\": 92, \"Charlie\": 78}\n", - "contacts = {\"John\": \"+123456789\", \"Emily\": \"+987654321\", \"Sam\": \"+345678912\"}\n", - "my_dict3 = dict()\n", - "my_dict3[\"name\"] = \"Alice\"\n", - "my_dict3[\"age\"] = 30\n", - "my_dict3[\"city\"] = \"London\"\n", - "\n", - "print (my_dict3)\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In the above code cell, we have created two dictionaries: student_scores and contacts, by specifying key-value pairs within the { } brackets. Additionally, we have also demonstrated how to create an empty dictionary my_dict3 using the dict( ) constructor and then added key-value pairs to it using the square bracket notation. These examples showcase the flexibility of dictionaries in storing and accessing data through key-value relationships." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.4 Loops " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### for loop \n", - "for Loop: A for loop is used to iterate over a sequence (such as a list, tuple, or string) or any iterable object. It allows you to perform a set of statements repeatedly for each item in the sequence. Here is a simple example of how to use a for loop:" - ] - }, - { - "cell_type": "code", - "execution_count": 74, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "apple\n", - "banana\n", - "orange\n" - ] - } - ], - "source": [ - "fruits = [\"apple\", \"banana\", \"orange\"]\n", - "for fruit in fruits:\n", - " print(fruit)\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### while loop\n", - "while Loop: A while loop is used to repeatedly execute a block of code as long as a given condition is true. It allows you to keep looping until the condition becomes false. Here is a simple example of how to use a while loop:" - ] - }, - { - "cell_type": "code", - "execution_count": 75, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0\n", - "1\n", - "2\n", - "3\n", - "4\n" - ] - } - ], - "source": [ - "count = 0\n", - "while count < 5:\n", - " print(count)\n", - " count += 1\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### break statement\n", - "break Statement: The break statement is used to prematurely exit a loop. When encountered, it terminates the loop and resumes execution at the next statement outside the loop. Here is a simple example of how to use a break statement:" - ] - }, - { - "cell_type": "code", - "execution_count": 76, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "apple\n" - ] - } - ], - "source": [ - "fruits = [\"apple\", \"banana\", \"orange\"]\n", - "for fruit in fruits:\n", - " if fruit == \"banana\":\n", - " break\n", - " print(fruit)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### continue statement\n", - "continue Statement: The continue statement is used to skip the remaining code inside a loop for the current iteration and move to the next iteration. Here is a simple example of how to use a continue statement:" - ] - }, - { - "cell_type": "code", - "execution_count": 77, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1\n", - "2\n", - "4\n", - "5\n" - ] - } - ], - "source": [ - "numbers = [1, 2, 3, 4, 5]\n", - "for num in numbers:\n", - " if num == 3:\n", - " continue\n", - " print(num)\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Break down of all examples**: In the first example, the for loop iterates over a list of fruits and prints each fruit. The while loop in the second example prints numbers from 0 to 4. The break statement in the third example terminates the loop when the condition is met. Lastly, the continue statement in the fourth example skips printing the number 3 and moves to the next iteration. These loop constructs provide powerful control flow mechanisms to repeat and control the execution of code blocks based on specific conditions." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [] } ], "metadata": { diff --git a/book/numpy/1d.ipynb b/book/numpy/1d.ipynb new file mode 100644 index 0000000..09d6008 --- /dev/null +++ b/book/numpy/1d.ipynb @@ -0,0 +1,794 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## One-Dimensional arrays" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ``np.array()``, ``np.asarray()``\n", + "So, how do you create a numpy 1-Dimensional (1D) array? There are a few ways to do it..." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* Option 1 - from scratch with ``np.array()`` similar to a list." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "arr1 = [1 2 3], its type is \n" + ] + } + ], + "source": [ + "arr1 = np.array([1,2,3])\n", + "print('arr1 = {}, its type is {}'.format(arr1,type(arr1)))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* Option 2 - from an existing list with ``np.array()``. \n", + "\n", + "Create the list first and check its type. Then create the array `A_1` from the list `L_1` and check its type." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "L_1 = [1, 2, 3, 5, 7, 11, 13] and its type is \n", + "\n", + "A_1 = [ 1 2 3 5 7 11 13] and its type is \n" + ] + } + ], + "source": [ + "L_1 = [1,2,3,5,7,11,13]\n", + "print('L_1 = {} and its type is {}\\n'.format(L_1,type(L_1)))\n", + "\n", + "A_1 = np.array(L_1)\n", + "print('A_1 = {} and its type is {}'.format(A_1, type(A_1)))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* Option 3 - from an existing list with ``np.asarray()``" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "L_1 = [1, 2, 3, 5, 7, 11, 13] and its type is \n", + "\n", + "A_1 = [ 1 2 3 5 7 11 13] and its type is \n" + ] + } + ], + "source": [ + "L_1 = [1,2,3,5,7,11,13]\n", + "print('L_1 = {} and its type is {}\\n'.format(L_1,type(L_1)))\n", + "\n", + "A_1 = np.asarray(L_1)\n", + "print('A_1 = {} and its type is {}'.format(A_1, type(A_1)))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "From the above examples, you can't really determine the difference between using np.array() or np.asarray(). Nonetheless, there is a very important one, similar to the = and copy conundrum discussed in Notebook 4. When generating an array from a list, both functions do pretty much the same. However, when generating an array from another array, their differences stand out.\n", + "\n", + "First, let's check the ID of arr1" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "arr1 ID is 3116429230896\n" + ] + } + ], + "source": [ + "print('arr1 ID is {}'.format(id(arr1)))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let's make two new arrays from arr1, using both functions" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "arr_array = [100 2 3] and its ID is 2342009211568\n", + "\n", + "arr_asarray = [100 2 3] and its ID is 2342276386128\n" + ] + } + ], + "source": [ + "arr_array = np.array(arr1)\n", + "arr_asarray = np.asarray(arr1)\n", + "\n", + "print('arr_array = {} and its ID is {}\\n'.format(arr_array,id(arr_array)))\n", + "print('arr_asarray = {} and its ID is {}'.format(arr_asarray, id(arr_asarray)))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Hmm... it seems that the ID of arr_asarray is the same as the original arr1. Which means they are the same variable! Altering one will alter the other one as well. Let's try it out." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "ename": "ValueError", + "evalue": "invalid literal for int() with base 10: 'hello'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[8], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m arr1[\u001b[39m0\u001b[39m] \u001b[39m=\u001b[39m \u001b[39m'\u001b[39m\u001b[39mhello\u001b[39m\u001b[39m'\u001b[39m\n\u001b[0;32m 2\u001b[0m \u001b[39mprint\u001b[39m(arr_asarray)\n", + "\u001b[1;31mValueError\u001b[0m: invalid literal for int() with base 10: 'hello'" + ] + } + ], + "source": [ + "arr1[0] = 'hello'\n", + "print(arr_asarray)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Oops... it didn't work. Why do you think it didn't work?" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Answer: . . .\n", + "\n", + "Change the first element of `arr1`. Then print `arr_array` and `arr_asarray` to see if the first element changed." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "arr1 = [100 2 3]\n", + "\n", + "arr_array = [100 2 3]\n", + "\n", + "arr_asarray = [100 2 3]\n" + ] + } + ], + "source": [ + "arr1[0] = 100\n", + "\n", + "print('arr1 = {}\\n'.format(arr1))\n", + "print('arr_array = {}\\n'.format(arr_array))\n", + "print('arr_asarray = {}'.format(arr_asarray))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Yep, our theory was right: arr1 and arr_asarray are indeed the same (but arr_array is not!). Therefore, altering arr1[0] will alter arr_asarray[0] in the same way.\n", + "\n", + "Final check that they are indeed the same" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "print(arr1 is arr_asarray)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### ``np.zeros()``\n", + "In case you already know the size of the array you will need, it is common to initialize it with zeros first using the np.zeros() function, as shown below." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set a limit when printing the huge arrays we will generate." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "tags": [ + "hide-input" + ] + }, + "outputs": [], + "source": [ + "np.set_printoptions(threshold=1) " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "I know I will need an array with 100000 elements so I create it full of zeros first. Then, I assign the values I need to each element.\n", + "in this example, I only wrote a `for` loop to assign random integer numbers between 0 and 9 to it. Note the use of `range(len(my_arr))`, we use this often to specify the range of the `for` loop to be of the same size as some array." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "my_arr with a bunch of zeros \n", + "[0. 0. 0. ... 0. 0. 0.]\n", + "\n", + "#######################\n", + "\n", + "my_arr with random numbers \n", + "[1. 0. 9. ... 7. 2. 4.]\n" + ] + } + ], + "source": [ + "\n", + "my_arr = np.zeros(100000)\n", + "print('my_arr with a bunch of zeros \\n{}\\n'.format(my_arr))\n", + "print('#######################')\n", + "\n", + "import random\n", + "\n", + "for i in range(len(my_arr)): \n", + " my_arr[i] = random.randint(0,9)\n", + " \n", + "print('\\nmy_arr with random numbers \\n{}'.format(my_arr))\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Note that these arrays still have $100000$ elements, but due to our first line of code we truncated the print function to not print it completely — otherwise you would have to scroll a lot. :P " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### ``np.min()``, ``np.max()`` and ``np.mean()``\n", + "\n", + "Numpy also provides various packages to help you process your data. You can, for instance, find out what is the minimum value of an array, or its mean. Your task is to find the minimum, maximum, and mean values of an array.\n", + "\n", + "Find the minimum, maximum and mean values of A_1 and print the results." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The minimum value of A_1 is 1 \n", + "\n", + "The maximum value of A_1 is 13 \n", + "\n", + "The mean value of A_1 is 6.0 \n", + "\n" + ] + } + ], + "source": [ + "A_1_min = np.min(A_1)\n", + "A_1_max = np.max(A_1)\n", + "A_1_mean = np.mean(A_1)\n", + "\n", + "print(f'The minimum value of A_1 is {A_1_min} \\n')\n", + "print(f'The maximum value of A_1 is {A_1_max} \\n')\n", + "print(f'The mean value of A_1 is {A_1_mean} \\n')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ``np.arange()``\n", + "\n", + "Another useful function of the numpy module is np.arange(). First, let's see in the documentation what it does." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It reads:

arange([start,] stop[, step,], dtype=None, *, like=None)

Return evenly spaced values within a given interval.


To make a number range you need to choose:
1) the starting point,
2) the endpoint,
3) the interval between each point

The reason why it reads [start,] stop[, step,] with square brackets, is that the start and the step can be omitted. If not specified, start = 0 and step = 1, by default." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "::: {warning}\n", + "Your endpoint is not included in the array. If you want to include the endpoint in the array, you have to specify the stop to be endpoint + step. This will be clearer in the following examples.\n", + ":::" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "omitted start and step" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "arr = [0 1 2 3 4]\n" + ] + } + ], + "source": [ + "arr = np.arange(5) \n", + "print('arr =', arr)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As mentioned, the endpoint (5) is omitted. If you would like to include it:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "arr = [0 1 2 3 4 5]\n" + ] + } + ], + "source": [ + "arr = np.arange(5 + 1)\n", + "print('arr =', arr)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, without omiting `start` nor `step`. Without endpoint." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "arr = [1. 1.01 1.02 ... 1.97 1.98 1.99]\n" + ] + } + ], + "source": [ + "arr = np.arange(1, 2, 0.01)\n", + "print('arr =', arr)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Including endpoint" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "arr = [1. 1.01 1.02 ... 1.98 1.99 2. ]\n" + ] + } + ], + "source": [ + "arr = np.arange(1, 2 + 0.01, 0.01) \n", + "print('arr =', arr)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also generate a descending array, by using negative steps" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "arr = [10 9 8 ... 3 2 1]\n" + ] + } + ], + "source": [ + "arr = np.arange(10,0,-1)\n", + "print('arr =', arr)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ``np.sort()``\n", + "\n", + "You can also sort an array in the crescent order using np.sort()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "sorted_arr = [ 1 2 3 ... 8 9 10]\n" + ] + } + ], + "source": [ + "sorted_arr = np.sort(arr)\n", + "print('sorted_arr =', sorted_arr)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ``np.sum()``\n", + "\n", + "As the name clearly states, np.sum() returns the sum of an array. Let's try it out:" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The sum of the array is 6\n" + ] + } + ], + "source": [ + "arr = ([1,2,3])\n", + "my_sum = np.sum(arr)\n", + "print(f'The sum of the array is {my_sum}')" + ] + } + ], + "metadata": { + "hide_input": false, + "kernelspec": { + "display_name": "mude", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/05/Theory/01.ipynb b/book/numpy/2d.ipynb similarity index 62% rename from book/05/Theory/01.ipynb rename to book/numpy/2d.ipynb index 7a0a991..dc92c74 100644 --- a/book/05/Theory/01.ipynb +++ b/book/numpy/2d.ipynb @@ -1,37 +1,5 @@ { "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "# 5. Numpy" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## 5.1. Introduction\n", - "\n", - "The numpy package is one of the main packages when it comes to working with arrays and matrices in Python, making it indispensable to process and visualize scientific data. Its assortment of routines facilitates operations such as mathematical, logical, linear algebra, Fourier transforms, and much more. In this section, you will learn some of the most used numpy functions to work with multidimensional array objects.\n", - "\n", - "As always, let's import the package we will use" - ] - }, { "cell_type": "code", "execution_count": 1, @@ -59,761 +27,7 @@ } }, "source": [ - "The following functions will be discussed in this Notebook:\n", - "- np.array() \n", - "- np.zeros() \n", - "- np.asarray() \n", - "- np.shape()\n", - "- np.min()\n", - "- np.max()\n", - "- np.mean()\n", - "- np.sort()\n", - "- np.linspace()\n", - "- np.arange()\n", - "- np.argmax()\n", - "- np.argmin()\n", - "- np.where()\n", - "- np.astype()\n", - "- np.dot()\n", - "- np.transpose()\n", - "- np.loadtxt()\n", - "- np.sum()\n", - "- np.cos()\n", - "- np.sin()\n", - "- np.sqrt()\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "In Section 2.3, of Notebook 2, you have already encountered lists, which are created with square brackets []. Arrays are the numpy equivalent of lists, with a few characteristic traits:

- numpy arrays can only store one type of element,
- numpy arrays take up much less memory than lists,
- numpy arrays have a much better runtime behavior,
- it is easier to work with multi-dimensional numpy arrays than with multi-dimensional lists

" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 5.2 One-Dimensional arrays" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### ``np.array()``, ``np.asarray()``\n", - "So, how do you create a numpy 1-Dimensional (1D) array? There are a few ways to do it..." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "* Option 1 - from scratch with ``np.array()`` similar to a list." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "arr1 = [1 2 3], its type is \n" - ] - } - ], - "source": [ - "arr1 = np.array([1,2,3])\n", - "print('arr1 = {}, its type is {}'.format(arr1,type(arr1)))" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "* Option 2 - from an existing list with ``np.array()``. \n", - "\n", - "Create the list first and check its type. Then create the array `A_1` from the list `L_1` and check its type." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "L_1 = [1, 2, 3, 5, 7, 11, 13] and its type is \n", - "\n", - "A_1 = [ 1 2 3 5 7 11 13] and its type is \n" - ] - } - ], - "source": [ - "L_1 = [1,2,3,5,7,11,13]\n", - "print('L_1 = {} and its type is {}\\n'.format(L_1,type(L_1)))\n", - "\n", - "A_1 = np.array(L_1)\n", - "print('A_1 = {} and its type is {}'.format(A_1, type(A_1)))" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "* Option 3 - from an existing list with ``np.asarray()``" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "L_1 = [1, 2, 3, 5, 7, 11, 13] and its type is \n", - "\n", - "A_1 = [ 1 2 3 5 7 11 13] and its type is \n" - ] - } - ], - "source": [ - "L_1 = [1,2,3,5,7,11,13]\n", - "print('L_1 = {} and its type is {}\\n'.format(L_1,type(L_1)))\n", - "\n", - "A_1 = np.asarray(L_1)\n", - "print('A_1 = {} and its type is {}'.format(A_1, type(A_1)))" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "From the above examples, you can't really determine the difference between using np.array() or np.asarray(). Nonetheless, there is a very important one, similar to the = and copy conundrum discussed in Notebook 4. When generating an array from a list, both functions do pretty much the same. However, when generating an array from another array, their differences stand out.\n", - "\n", - "First, let's check the ID of arr1" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "arr1 ID is 3116429230896\n" - ] - } - ], - "source": [ - "print('arr1 ID is {}'.format(id(arr1)))" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, let's make two new arrays from arr1, using both functions" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "arr_array = [100 2 3] and its ID is 2342009211568\n", - "\n", - "arr_asarray = [100 2 3] and its ID is 2342276386128\n" - ] - } - ], - "source": [ - "arr_array = np.array(arr1)\n", - "arr_asarray = np.asarray(arr1)\n", - "\n", - "print('arr_array = {} and its ID is {}\\n'.format(arr_array,id(arr_array)))\n", - "print('arr_asarray = {} and its ID is {}'.format(arr_asarray, id(arr_asarray)))" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Hmm... it seems that the ID of arr_asarray is the same as the original arr1. Which means they are the same variable! Altering one will alter the other one as well. Let's try it out." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "ename": "ValueError", - "evalue": "invalid literal for int() with base 10: 'hello'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[8], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m arr1[\u001b[39m0\u001b[39m] \u001b[39m=\u001b[39m \u001b[39m'\u001b[39m\u001b[39mhello\u001b[39m\u001b[39m'\u001b[39m\n\u001b[0;32m 2\u001b[0m \u001b[39mprint\u001b[39m(arr_asarray)\n", - "\u001b[1;31mValueError\u001b[0m: invalid literal for int() with base 10: 'hello'" - ] - } - ], - "source": [ - "arr1[0] = 'hello'\n", - "print(arr_asarray)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Oops... it didn't work. Why do you think it didn't work?" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Answer: . . .\n", - "\n", - "Change the first element of `arr1`. Then print `arr_array` and `arr_asarray` to see if the first element changed." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "arr1 = [100 2 3]\n", - "\n", - "arr_array = [100 2 3]\n", - "\n", - "arr_asarray = [100 2 3]\n" - ] - } - ], - "source": [ - "arr1[0] = 100\n", - "\n", - "print('arr1 = {}\\n'.format(arr1))\n", - "print('arr_array = {}\\n'.format(arr_array))\n", - "print('arr_asarray = {}'.format(arr_asarray))" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Yep, our theory was right: arr1 and arr_asarray are indeed the same (but arr_array is not!). Therefore, altering arr1[0] will alter arr_asarray[0] in the same way.\n", - "\n", - "Final check that they are indeed the same" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "True\n" - ] - } - ], - "source": [ - "print(arr1 is arr_asarray)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### ``np.zeros()``\n", - "In case you already know the size of the array you will need, it is common to initialize it with zeros first using the np.zeros() function, as shown below." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Set a limit when printing the huge arrays we will generate." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "tags": [ - "hide-input" - ] - }, - "outputs": [], - "source": [ - "np.set_printoptions(threshold=1) " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "I know I will need an array with 100000 elements so I create it full of zeros first. Then, I assign the values I need to each element.\n", - "in this example, I only wrote a `for` loop to assign random integer numbers between 0 and 9 to it. Note the use of `range(len(my_arr))`, we use this often to specify the range of the `for` loop to be of the same size as some array." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "my_arr with a bunch of zeros \n", - "[0. 0. 0. ... 0. 0. 0.]\n", - "\n", - "#######################\n", - "\n", - "my_arr with random numbers \n", - "[1. 0. 9. ... 7. 2. 4.]\n" - ] - } - ], - "source": [ - "\n", - "my_arr = np.zeros(100000)\n", - "print('my_arr with a bunch of zeros \\n{}\\n'.format(my_arr))\n", - "print('#######################')\n", - "\n", - "import random\n", - "\n", - "for i in range(len(my_arr)): \n", - " my_arr[i] = random.randint(0,9)\n", - " \n", - "print('\\nmy_arr with random numbers \\n{}'.format(my_arr))\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Note that these arrays still have $100000$ elements, but due to our first line of code we truncated the print function to not print it completely — otherwise you would have to scroll a lot. :P " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### ``np.min()``, ``np.max()`` and ``np.mean()``\n", - "\n", - "Numpy also provides various packages to help you process your data. You can, for instance, find out what is the minimum value of an array, or its mean. Your task is to find the minimum, maximum, and mean values of an array.\n", - "\n", - "Find the minimum, maximum and mean values of A_1 and print the results." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The minimum value of A_1 is 1 \n", - "\n", - "The maximum value of A_1 is 13 \n", - "\n", - "The mean value of A_1 is 6.0 \n", - "\n" - ] - } - ], - "source": [ - "A_1_min = np.min(A_1)\n", - "A_1_max = np.max(A_1)\n", - "A_1_mean = np.mean(A_1)\n", - "\n", - "print(f'The minimum value of A_1 is {A_1_min} \\n')\n", - "print(f'The maximum value of A_1 is {A_1_max} \\n')\n", - "print(f'The mean value of A_1 is {A_1_mean} \\n')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### ``np.arange()``\n", - "\n", - "Another useful function of the numpy module is np.arange(). First, let's see in the documentation what it does." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "It reads:

arange([start,] stop[, step,], dtype=None, *, like=None)

Return evenly spaced values within a given interval.


To make a number range you need to choose:
1) the starting point,
2) the endpoint,
3) the interval between each point

The reason why it reads [start,] stop[, step,] with square brackets, is that the start and the step can be omitted. If not specified, start = 0 and step = 1, by default." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "::: {warning}\n", - "Your endpoint is not included in the array. If you want to include the endpoint in the array, you have to specify the stop to be endpoint + step. This will be clearer in the following examples.\n", - ":::" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "omitted start and step" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "arr = [0 1 2 3 4]\n" - ] - } - ], - "source": [ - "arr = np.arange(5) \n", - "print('arr =', arr)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As mentioned, the endpoint (5) is omitted. If you would like to include it:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "arr = [0 1 2 3 4 5]\n" - ] - } - ], - "source": [ - "arr = np.arange(5 + 1)\n", - "print('arr =', arr)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, without omiting `start` nor `step`. Without endpoint." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "arr = [1. 1.01 1.02 ... 1.97 1.98 1.99]\n" - ] - } - ], - "source": [ - "arr = np.arange(1, 2, 0.01)\n", - "print('arr =', arr)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Including endpoint" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "arr = [1. 1.01 1.02 ... 1.98 1.99 2. ]\n" - ] - } - ], - "source": [ - "arr = np.arange(1, 2 + 0.01, 0.01) \n", - "print('arr =', arr)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can also generate a descending array, by using negative steps" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "arr = [10 9 8 ... 3 2 1]\n" - ] - } - ], - "source": [ - "arr = np.arange(10,0,-1)\n", - "print('arr =', arr)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### ``np.sort()``\n", - "\n", - "You can also sort an array in the crescent order using np.sort()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "sorted_arr = [ 1 2 3 ... 8 9 10]\n" - ] - } - ], - "source": [ - "sorted_arr = np.sort(arr)\n", - "print('sorted_arr =', sorted_arr)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### ``np.sum()``\n", - "\n", - "As the name clearly states, np.sum() returns the sum of an array. Let's try it out:" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The sum of the array is 6\n" - ] - } - ], - "source": [ - "arr = ([1,2,3])\n", - "my_sum = np.sum(arr)\n", - "print(f'The sum of the array is {my_sum}')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "## 5.3 Two-Dimensional arrays and matrices\n", + "## Two-Dimensional arrays and matrices\n", "\n", "As mentioned earlier, numpy is not solely built for 1D arrays $-$ it's built to work with multidimensional arrays! So, let's hop into 2D arrays and matrices, which you have already encountered in Linear Algebra. You can construct your own matrix using the np.array() function, as shown below." ] diff --git a/book/05/Exercises/01.ipynb b/book/numpy/Exercises/01.ipynb similarity index 100% rename from book/05/Exercises/01.ipynb rename to book/numpy/Exercises/01.ipynb diff --git a/book/05/Exercises/01.json b/book/numpy/Exercises/01.json similarity index 100% rename from book/05/Exercises/01.json rename to book/numpy/Exercises/01.json diff --git a/book/05/Exercises/02.ipynb b/book/numpy/Exercises/02.ipynb similarity index 100% rename from book/05/Exercises/02.ipynb rename to book/numpy/Exercises/02.ipynb diff --git a/book/05/Exercises/02.json b/book/numpy/Exercises/02.json similarity index 100% rename from book/05/Exercises/02.json rename to book/numpy/Exercises/02.json diff --git a/book/05/Exercises/02_01.csv b/book/numpy/Exercises/02_01.csv similarity index 100% rename from book/05/Exercises/02_01.csv rename to book/numpy/Exercises/02_01.csv diff --git a/book/05/Exercises/02_01.png b/book/numpy/Exercises/02_01.png similarity index 100% rename from book/05/Exercises/02_01.png rename to book/numpy/Exercises/02_01.png diff --git a/book/numpy/intro.md b/book/numpy/intro.md new file mode 100644 index 0000000..35afd56 --- /dev/null +++ b/book/numpy/intro.md @@ -0,0 +1,6 @@ +# Numpy + +This chapter is all about... + +% a short overview for this chapter + diff --git a/book/numpy/introduction.ipynb b/book/numpy/introduction.ipynb new file mode 100644 index 0000000..a45ea2d --- /dev/null +++ b/book/numpy/introduction.ipynb @@ -0,0 +1,156 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "## Introduction\n", + "\n", + "The numpy package is one of the main packages when it comes to working with arrays and matrices in Python, making it indispensable to process and visualize scientific data. Its assortment of routines facilitates operations such as mathematical, logical, linear algebra, Fourier transforms, and much more. In this section, you will learn some of the most used numpy functions to work with multidimensional array objects.\n", + "\n", + "As always, let's import the package we will use" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "The following functions will be discussed in this Notebook:\n", + "- np.array() \n", + "- np.zeros() \n", + "- np.asarray() \n", + "- np.shape()\n", + "- np.min()\n", + "- np.max()\n", + "- np.mean()\n", + "- np.sort()\n", + "- np.linspace()\n", + "- np.arange()\n", + "- np.argmax()\n", + "- np.argmin()\n", + "- np.where()\n", + "- np.astype()\n", + "- np.dot()\n", + "- np.transpose()\n", + "- np.loadtxt()\n", + "- np.sum()\n", + "- np.cos()\n", + "- np.sin()\n", + "- np.sqrt()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "In Section 2.3, of Notebook 2, you have already encountered lists, which are created with square brackets []. Arrays are the numpy equivalent of lists, with a few characteristic traits:

- numpy arrays can only store one type of element,
- numpy arrays take up much less memory than lists,
- numpy arrays have a much better runtime behavior,
- it is easier to work with multi-dimensional numpy arrays than with multi-dimensional lists

" + ] + } + ], + "metadata": { + "hide_input": false, + "kernelspec": { + "display_name": "mude", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/numpy/nutshell.md b/book/numpy/nutshell.md new file mode 100644 index 0000000..8ad5df1 --- /dev/null +++ b/book/numpy/nutshell.md @@ -0,0 +1,3 @@ +# Numpy: in a Nutshell + +Nutshell. \ No newline at end of file diff --git a/book/05/In_a_Nutshell/01.ipynb b/book/numpy/nutshell/numpy.ipynb similarity index 100% rename from book/05/In_a_Nutshell/01.ipynb rename to book/numpy/nutshell/numpy.ipynb diff --git a/book/04/Theory/01.png b/book/objects/01.png similarity index 100% rename from book/04/Theory/01.png rename to book/objects/01.png diff --git a/book/04/Theory/02.png b/book/objects/02.png similarity index 100% rename from book/04/Theory/02.png rename to book/objects/02.png diff --git a/book/04/Exercises/01.ipynb b/book/objects/Exercises/01.ipynb similarity index 100% rename from book/04/Exercises/01.ipynb rename to book/objects/Exercises/01.ipynb diff --git a/book/objects/intro.md b/book/objects/intro.md new file mode 100644 index 0000000..77dceb3 --- /dev/null +++ b/book/objects/intro.md @@ -0,0 +1,6 @@ +# Objects and References + +This chapter ... + +% a short overview for this chapter + diff --git a/book/objects/nutshell.md b/book/objects/nutshell.md new file mode 100644 index 0000000..cf26184 --- /dev/null +++ b/book/objects/nutshell.md @@ -0,0 +1,3 @@ +# Objects: in a Nutshell + +Nutshell. \ No newline at end of file diff --git a/book/04/In_a_Nutshell/01.ipynb b/book/objects/nutshell/object.ipynb similarity index 99% rename from book/04/In_a_Nutshell/01.ipynb rename to book/objects/nutshell/object.ipynb index ecc4511..660eb0a 100644 --- a/book/04/In_a_Nutshell/01.ipynb +++ b/book/objects/nutshell/object.ipynb @@ -5,7 +5,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# 4. Objects and References" + "# Objects and References" ] }, { diff --git a/book/04/Theory/01.ipynb b/book/objects/object.ipynb similarity index 99% rename from book/04/Theory/01.ipynb rename to book/objects/object.ipynb index 7fc5b5e..087b991 100644 --- a/book/04/Theory/01.ipynb +++ b/book/objects/object.ipynb @@ -11,7 +11,7 @@ } }, "source": [ - "# 4. Objects and References" + "# Objects and References" ] }, { diff --git a/book/pandas/.DS_Store b/book/pandas/.DS_Store new file mode 100644 index 0000000..9c5649e Binary files /dev/null and b/book/pandas/.DS_Store differ diff --git a/book/06/Theory/01.png b/book/pandas/01.png similarity index 100% rename from book/06/Theory/01.png rename to book/pandas/01.png diff --git a/book/06/Exercises/01.ipynb b/book/pandas/Exercises/01.ipynb similarity index 100% rename from book/06/Exercises/01.ipynb rename to book/pandas/Exercises/01.ipynb diff --git a/book/06/Exercises/01.png b/book/pandas/Exercises/01.png similarity index 100% rename from book/06/Exercises/01.png rename to book/pandas/Exercises/01.png diff --git a/book/06/Exercises/mountains_above_7000m.csv b/book/pandas/Exercises/mountains_above_7000m.csv similarity index 100% rename from book/06/Exercises/mountains_above_7000m.csv rename to book/pandas/Exercises/mountains_above_7000m.csv diff --git a/book/06/Exercises/tallest_mountains.csv b/book/pandas/Exercises/tallest_mountains.csv similarity index 100% rename from book/06/Exercises/tallest_mountains.csv rename to book/pandas/Exercises/tallest_mountains.csv diff --git a/book/pandas/attributes.ipynb b/book/pandas/attributes.ipynb new file mode 100644 index 0000000..45a7b36 --- /dev/null +++ b/book/pandas/attributes.ipynb @@ -0,0 +1,388 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "## Importing data into DataFrames and exploring its attributes\n", + "\n", + "pandas provides many functions to import data into dataframes, such as read_csv() to read delimited text files, or read_excel() for Excel or OpenDocument spreadsheets. read_csv() provides options that allow you to filter the data, such as specifying the separator/delimiter, the lines that form the headers, which rows to skip, etc. Let's analyze the mineral_properties.txt. Below a screenshot of it:

\n", + " \n", + "```{image} 01.png\n", + ":alt: rectangle\n", + ":width: 400px\n", + ":align: center\n", + "```" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "below we import the `.txt`: \n", + "* we indicate that the separator is the comma `\"sep=','\"`\n", + "* we indicate the header (what should be the columns names) is in the second line `\"header=[1]\"`\n", + "* we indicate to not skip any rows `\"skiprows=None\"`\n", + "* we indicate the first column should be the index of the rows `\"index_col=0\"`\n" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
hardnesssp. gr.cleavage
name
Amphibole5.502.800Two
Biotite2.753.000One
Calcite3.002.720Three
Dolomite3.002.850Three
Feldspars6.002.645Two
Garnet7.003.900Fracture
Graphite1.502.300One
Kyanite6.004.010One
Muscovite2.252.930One
Pyroxene5.503.325Two
Quartz7.002.650Fracture
Sillimanite6.503.230One
\n", + "
" + ], + "text/plain": [ + " hardness sp. gr. cleavage\n", + "name \n", + "Amphibole 5.50 2.800 Two\n", + "Biotite 2.75 3.000 One\n", + "Calcite 3.00 2.720 Three\n", + "Dolomite 3.00 2.850 Three\n", + "Feldspars 6.00 2.645 Two\n", + "Garnet 7.00 3.900 Fracture\n", + "Graphite 1.50 2.300 One\n", + "Kyanite 6.00 4.010 One\n", + "Muscovite 2.25 2.930 One\n", + "Pyroxene 5.50 3.325 Two\n", + "Quartz 7.00 2.650 Fracture\n", + "Sillimanite 6.50 3.230 One" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "file_location = (\"mineral_properties.txt\")\n", + "df4 = pd.read_csv(file_location, sep=',', header=[1],\n", + " skiprows=None, index_col=0)\n", + "df4" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that if we try to call any of the columns from `df4` we will get an error." + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "ename": "KeyError", + "evalue": "'hardness'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", + "File \u001b[1;32mc:\\Users\\gui-win10\\AppData\\Local\\pypoetry\\Cache\\virtualenvs\\learn-python-rwbttIgo-py3.11\\Lib\\site-packages\\pandas\\core\\indexes\\base.py:3805\u001b[0m, in \u001b[0;36mIndex.get_loc\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m 3804\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m-> 3805\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_engine\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcasted_key\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 3806\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m err:\n", + "File \u001b[1;32mindex.pyx:167\u001b[0m, in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[1;34m()\u001b[0m\n", + "File \u001b[1;32mindex.pyx:196\u001b[0m, in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[1;34m()\u001b[0m\n", + "File \u001b[1;32mpandas\\\\_libs\\\\hashtable_class_helper.pxi:7081\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[1;34m()\u001b[0m\n", + "File \u001b[1;32mpandas\\\\_libs\\\\hashtable_class_helper.pxi:7089\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[1;34m()\u001b[0m\n", + "\u001b[1;31mKeyError\u001b[0m: 'hardness'", + "\nThe above exception was the direct cause of the following exception:\n", + "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[67], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mdf4\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mhardness\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\n", + "File \u001b[1;32mc:\\Users\\gui-win10\\AppData\\Local\\pypoetry\\Cache\\virtualenvs\\learn-python-rwbttIgo-py3.11\\Lib\\site-packages\\pandas\\core\\frame.py:4090\u001b[0m, in \u001b[0;36mDataFrame.__getitem__\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m 4088\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcolumns\u001b[38;5;241m.\u001b[39mnlevels \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[0;32m 4089\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_getitem_multilevel(key)\n\u001b[1;32m-> 4090\u001b[0m indexer \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcolumns\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 4091\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m is_integer(indexer):\n\u001b[0;32m 4092\u001b[0m indexer \u001b[38;5;241m=\u001b[39m [indexer]\n", + "File \u001b[1;32mc:\\Users\\gui-win10\\AppData\\Local\\pypoetry\\Cache\\virtualenvs\\learn-python-rwbttIgo-py3.11\\Lib\\site-packages\\pandas\\core\\indexes\\base.py:3812\u001b[0m, in \u001b[0;36mIndex.get_loc\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m 3807\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(casted_key, \u001b[38;5;28mslice\u001b[39m) \u001b[38;5;129;01mor\u001b[39;00m (\n\u001b[0;32m 3808\u001b[0m \u001b[38;5;28misinstance\u001b[39m(casted_key, abc\u001b[38;5;241m.\u001b[39mIterable)\n\u001b[0;32m 3809\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28many\u001b[39m(\u001b[38;5;28misinstance\u001b[39m(x, \u001b[38;5;28mslice\u001b[39m) \u001b[38;5;28;01mfor\u001b[39;00m x \u001b[38;5;129;01min\u001b[39;00m casted_key)\n\u001b[0;32m 3810\u001b[0m ):\n\u001b[0;32m 3811\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m InvalidIndexError(key)\n\u001b[1;32m-> 3812\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(key) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01merr\u001b[39;00m\n\u001b[0;32m 3813\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m:\n\u001b[0;32m 3814\u001b[0m \u001b[38;5;66;03m# If we have a listlike key, _check_indexing_error will raise\u001b[39;00m\n\u001b[0;32m 3815\u001b[0m \u001b[38;5;66;03m# InvalidIndexError. Otherwise we fall through and re-raise\u001b[39;00m\n\u001b[0;32m 3816\u001b[0m \u001b[38;5;66;03m# the TypeError.\u001b[39;00m\n\u001b[0;32m 3817\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_check_indexing_error(key)\n", + "\u001b[1;31mKeyError\u001b[0m: 'hardness'" + ] + } + ], + "source": [ + "df4['hardness']" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Do you know why?" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Answer ..." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "In case you were not able to answer the above question, let's look into df4.columns" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Index([' hardness', ' sp. gr.', ' cleavage'], dtype='object')" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df4.columns" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "You see there are spaces at the beginning of each column name... this happens because that's how people usually type, with commas followed by a space. We could use the skipinitialspace = True from the pd.read_csv() function to avoid this. Let's try it out:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Index(['hardness', 'sp. gr.', 'cleavage'], dtype='object')\n" + ] + } + ], + "source": [ + "df4 = pd.read_csv(file_location + 'mineral_properties.txt',sep=',',header=[1], \n", + " skiprows=None, index_col=0, skipinitialspace=True)\n", + "print(df4.columns)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Ok, much better!" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "Copy of Python_2_3.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 [3.7]", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + }, + "vscode": { + "interpreter": { + "hash": "1fe2f2b718b1108b9c4176932db8a0ead471245140baaa21ea96a4066683e6b2" + } + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/book/06/Theory/01.ipynb b/book/pandas/frame.ipynb similarity index 69% rename from book/06/Theory/01.ipynb rename to book/pandas/frame.ipynb index 560d97f..ec94da5 100644 --- a/book/06/Theory/01.ipynb +++ b/book/pandas/frame.ipynb @@ -8,34 +8,38 @@ "grade": false, "locked": true, "solution": false + }, + "pycharm": { + "name": "#%% md\n" } }, "source": [ - "# 6. Pandas" + "## ``DataFrame``\n", + "A DataFrame is a data structure used to represent two-dimensional data. A common example of data organized in two dimensions are tables or two-dimensional arrays." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { - "id": "fHmKWsUSKuj4", "nbgrader": { "grade": false, "locked": true, "solution": false + }, + "pycharm": { + "name": "#%% md\n" } }, "source": [ - "## 6.1 Introduction \n", - "\n", - "With the standard Python functions and the numpy library, you already have access to powerful tools to process data. However, you'll find that organizing data using them might still be confusing and messy... so let us introduce you to pandas: a Python library specialized in data organization. Its functions are simple to use, and they achieve a lot. Furthermore, pandas was built on top of the numpy library, using some of their functions and data structures. This makes pandas fast. The pandas library is often used in Data Science and Machine Learning to organize data that are used as input in other functions, of other libraries. For example, you store and organize an Excel file using pandas data structures, apply statistical analysis using SciPy, and then plot the result using matplotlib.

In this section, we'll introduce you to the basic pandas data structures: the Series and DataFrame objects; and how to store data in them. In pandas, a Series represents a list, and DataFrame represents a table.\n", + "Usually, DataFrames are made out of Series. However, its constructor accepts other types.\n", "\n", - "As always, let's import some libraries. We'll use numpy only for comparison." + "First, we define a few series to represent individual rows with data from [here](https://www.researchgate.net/figure/Selected-physical-properties-of-minerals-common-to-NYC-bedrock_tbl1_228544586)." ] }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 38, "metadata": { "collapsed": true, "nbgrader": { @@ -49,8 +53,10 @@ }, "outputs": [], "source": [ - "import pandas as pd \n", - "import numpy as np" + "row_1 = pd.Series(['Garnet', 7.0, 'Fracture', 3.9 ])\n", + "row_2 = pd.Series(['Graphite', 1.5, 'One', 2.3 ])\n", + "row_3 = pd.Series(['Kyanite', 6, 'One', 4.01 ])\n", + "row_4 = pd.Series(['test', 'bad', '@#$%^', False, \"asdf\"])" ] }, { @@ -64,61 +70,104 @@ } }, "source": [ - "## 6.2 ``Series``\n", - "\n", - "We start with pandas Series, since a DataFrame is made out of Series; retrieving a row or a column from a DataFrame results in a Series. A Series object is a numpy ndarray used to hold one-dimensional data, like a list. We create a Series object using its constructor pd.Series(). It can be called by using a list that you want to convert into a pandas series. Unlike numpy arrays, a Series may hold data of different types.\n", + "By default, the DataFrame constructor creates rows with the elements of each Series\n", "\n", - "First we create a list containing elements of various types. Then we construct a `Series` and a `numpy.array` using our list. Finally we compare the type of each element in `my_series` and `my_nparray`." + "Create DataFrame using multiple Series as rows. The name \"df\" is often used as a name for a dataframe object.\n" ] }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 39, "metadata": { "collapsed": true, "nbgrader": { "grade": false, "locked": true, "solution": false - }, - "pycharm": { - "name": "#%%\n" } }, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "----type of each element----\n", - "my_series element #0 => \n", - "my_nparray element #0 => \n", - "\n", - "----type of each element----\n", - "my_series element #1 => \n", - "my_nparray element #1 => \n", - "\n", - "----type of each element----\n", - "my_series element #2 => \n", - "my_nparray element #2 => \n", - "\n", - "----type of each element----\n", - "my_series element #3 => \n", - "my_nparray element #3 => \n", - "\n" - ] + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
01234
0Garnet7.0Fracture3.9NaN
1Graphite1.5One2.3NaN
2Kyanite6One4.01NaN
3testbad@#$%^Falseasdf
\n", + "
" + ], + "text/plain": [ + " 0 1 2 3 4\n", + "0 Garnet 7.0 Fracture 3.9 NaN\n", + "1 Graphite 1.5 One 2.3 NaN\n", + "2 Kyanite 6 One 4.01 NaN\n", + "3 test bad @#$%^ False asdf" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "my_list = ['begin', 2, 3/4, \"end\"]\n", - "\n", - "my_series = pd.Series(data=my_list)\n", - "my_nparray = np.array(my_list)\n", - "\n", - "for i in range(len(my_list)):\n", - " print('----type of each element----')\n", - " print(f'my_series element #{i} => {type(my_series[i])}')\n", - " print(f'my_nparray element #{i} => {type(my_nparray[i])}\\n')" + "df2 = pd.DataFrame(data=[row_1, row_2, row_3, row_4]) \n", + "df2" ] }, { @@ -132,39 +181,36 @@ } }, "source": [ - "As expected, the numpy array changed all elements to one type; in this case, strings. As mentioned in Section 5.1, in Notebook 5, a numpy array cannot hold data of different types. Note that a pandas series is, by default, printed more elaborately." + "We can also create a DataFrame using Series as columns:\n", + "\n", + "Define series representing columns and convert each series to a dataframe." ] }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 40, "metadata": { "collapsed": true, "nbgrader": { "grade": false, "locked": true, "solution": false + }, + "pycharm": { + "name": "#%%\n" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0 begin\n", - "1 2\n", - "2 0.75\n", - "3 end\n", - "dtype: object\n", - "-----------------\n", - "['begin' '2' '0.75' 'end']\n" - ] - } - ], + "outputs": [], "source": [ - "print(my_series)\n", - "print('-----------------')\n", - "print(my_nparray)" + "name = pd.Series(['Amphibole', 'Biotite', 'Calcite', 'Dolomite', 'Feldspars'])\n", + "hardness = pd.Series([5.5, 2.75, 3, 3, 6])\n", + "specific_gravity = pd.Series([2.8, 3.0, 2.72, 2.85, 2.645])\n", + "test = pd.Series(['A', 12j, True, 9, 11.00000])\n", + "\n", + "col_1 = name.to_frame(name='name') \n", + "col_2 = hardness.to_frame(name='hardness')\n", + "col_3 = specific_gravity.to_frame(name='sp. gr.')\n", + "col_4 = test.to_frame(name='test')\n" ] }, { @@ -178,42 +224,14 @@ } }, "source": [ - "The values of a series can be accessed and sliced using the **``iloc()``** function: " - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "1 2\n", - "2 0.75\n", - "3 end\n", - "dtype: object" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "my_series.iloc[1:]" + "After creating each column, we can concatenate them together into one DataFrame table using the pd.concat() function. There are two axes in a DataFrame: '0' (or 'index') for the rows, and '1' (or 'columns') for the columns. We want to concatenate the series along their columns, so use axis=1 (or axis='columns').\n", + "\n", + "Concatenate the series into one dataframe:" ] }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 41, "metadata": { "collapsed": true, "nbgrader": { @@ -225,19 +243,88 @@ "outputs": [ { "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
namehardnesssp. gr.test
0Amphibole5.502.800A
1Biotite2.753.00012j
2Calcite3.002.720True
3Dolomite3.002.8509
4Feldspars6.002.64511.0
\n", + "
" + ], "text/plain": [ - "2 0.75\n", - "3 end\n", - "dtype: object" + " name hardness sp. gr. test\n", + "0 Amphibole 5.50 2.800 A\n", + "1 Biotite 2.75 3.000 12j\n", + "2 Calcite 3.00 2.720 True\n", + "3 Dolomite 3.00 2.850 9\n", + "4 Feldspars 6.00 2.645 11.0" ] }, - "execution_count": 34, + "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "my_series.iloc[[2,len(my_series)-1]]" + "df1 = pd.concat([col_1, col_2, col_3, col_4], axis=1)\n", + "df1" ] }, { @@ -251,1218 +338,12 @@ } }, "source": [ - "### Labeling ``Series``\n", - "\n", - "So far we have referred to values within a list or array using indexing, but that might be confusing. With pandas Series, you can refer to your values by labeling their indices. Labels allow you to access the values in a more informative way, similar to dictionaries; depicted in Section 2.3, in Notebook 2.\n", - "\n", - "We create the indices of the same size as the list since we want to construct our Series object with and use the index option in the Series constructor. Note that our entries can be called both ways" + "Alternatively, you could use the np.transpose() or `.T` function to generate the DataFrame using a Series as columns and then label the columns." ] }, { "cell_type": "code", - "execution_count": 35, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "True\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Users\\gui-win10\\AppData\\Local\\Temp\\ipykernel_24848\\1771852785.py:4: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", - " print(my_labeled_Series[0] == my_labeled_Series[\"My first entry\"])\n" - ] - } - ], - "source": [ - "my_index_labels = [\"My first entry\", \"1\",\"2\",\"END\"]\n", - "my_labeled_Series = pd.Series(data=my_list, index=my_index_labels)\n", - "\n", - "print(my_labeled_Series[0] == my_labeled_Series[\"My first entry\"])" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "pandas can automatically create labels of indices if we construct a Series using a dictionary with labeled entries." - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "a list [420, 10]\n", - "a float 126.666667\n", - "a list of strings [first word, Second Word, 3rd w0rd]\n", - "dtype: object\n" - ] - } - ], - "source": [ - "my_dictionary = {\"a list\": [420, 10],\"a float\": 380/3, \n", - " \"a list of strings\": [\"first word\", \"Second Word\", \"3rd w0rd\"] }\n", - "my_Series = pd.Series(my_dictionary)\n", - "print(my_Series)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can access an element within the list labeled `\"a list of strings\"` by using its label followed by the desired index" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'Second Word'" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "my_Series[\"a list of strings\"][1]" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "::: {warning}\n", - "When using pandas, it's a good idea to try and avoid for loops or iterative solutions; pandas usually has a faster solution than iterating through its elements.\n", - "::: " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "## 6.3 ``DataFrame``\n", - "A DataFrame is a data structure used to represent two-dimensional data. A common example of data organized in two dimensions are tables or two-dimensional arrays." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "Usually, DataFrames are made out of Series. However, its constructor accepts other types.\n", - "\n", - "First, we define a few series to represent individual rows with data from [here](https://www.researchgate.net/figure/Selected-physical-properties-of-minerals-common-to-NYC-bedrock_tbl1_228544586)." - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [], - "source": [ - "row_1 = pd.Series(['Garnet', 7.0, 'Fracture', 3.9 ])\n", - "row_2 = pd.Series(['Graphite', 1.5, 'One', 2.3 ])\n", - "row_3 = pd.Series(['Kyanite', 6, 'One', 4.01 ])\n", - "row_4 = pd.Series(['test', 'bad', '@#$%^', False, \"asdf\"])" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "By default, the DataFrame constructor creates rows with the elements of each Series\n", - "\n", - "Create DataFrame using multiple Series as rows. The name \"df\" is often used as a name for a dataframe object.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
01234
0Garnet7.0Fracture3.9NaN
1Graphite1.5One2.3NaN
2Kyanite6One4.01NaN
3testbad@#$%^Falseasdf
\n", - "
" - ], - "text/plain": [ - " 0 1 2 3 4\n", - "0 Garnet 7.0 Fracture 3.9 NaN\n", - "1 Graphite 1.5 One 2.3 NaN\n", - "2 Kyanite 6 One 4.01 NaN\n", - "3 test bad @#$%^ False asdf" - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df2 = pd.DataFrame(data=[row_1, row_2, row_3, row_4]) \n", - "df2" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "We can also create a DataFrame using Series as columns:\n", - "\n", - "Define series representing columns and convert each series to a dataframe." - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - }, - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [], - "source": [ - "name = pd.Series(['Amphibole', 'Biotite', 'Calcite', 'Dolomite', 'Feldspars'])\n", - "hardness = pd.Series([5.5, 2.75, 3, 3, 6])\n", - "specific_gravity = pd.Series([2.8, 3.0, 2.72, 2.85, 2.645])\n", - "test = pd.Series(['A', 12j, True, 9, 11.00000])\n", - "\n", - "col_1 = name.to_frame(name='name') \n", - "col_2 = hardness.to_frame(name='hardness')\n", - "col_3 = specific_gravity.to_frame(name='sp. gr.')\n", - "col_4 = test.to_frame(name='test')\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "After creating each column, we can concatenate them together into one DataFrame table using the pd.concat() function. There are two axes in a DataFrame: '0' (or 'index') for the rows, and '1' (or 'columns') for the columns. We want to concatenate the series along their columns, so use axis=1 (or axis='columns').\n", - "\n", - "Concatenate the series into one dataframe:" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
namehardnesssp. gr.test
0Amphibole5.502.800A
1Biotite2.753.00012j
2Calcite3.002.720True
3Dolomite3.002.8509
4Feldspars6.002.64511.0
\n", - "
" - ], - "text/plain": [ - " name hardness sp. gr. test\n", - "0 Amphibole 5.50 2.800 A\n", - "1 Biotite 2.75 3.000 12j\n", - "2 Calcite 3.00 2.720 True\n", - "3 Dolomite 3.00 2.850 9\n", - "4 Feldspars 6.00 2.645 11.0" - ] - }, - "execution_count": 41, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df1 = pd.concat([col_1, col_2, col_3, col_4], axis=1)\n", - "df1" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Alternatively, you could use the np.transpose() or `.T` function to generate the DataFrame using a Series as columns and then label the columns." - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
namehardnesssp. gr.test
0Amphibole5.52.8A
1Biotite2.753.012j
2Calcite3.02.72True
3Dolomite3.02.859
4Feldspars6.02.64511.0
\n", - "
" - ], - "text/plain": [ - " name hardness sp. gr. test\n", - "0 Amphibole 5.5 2.8 A\n", - "1 Biotite 2.75 3.0 12j\n", - "2 Calcite 3.0 2.72 True\n", - "3 Dolomite 3.0 2.85 9\n", - "4 Feldspars 6.0 2.645 11.0" - ] - }, - "execution_count": 42, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_T = pd.DataFrame(data=[name,hardness,specific_gravity,test]).T\n", - "df_T.columns=['name', 'hardness', 'sp. gr.', 'test']\n", - "\n", - "df_T" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "To create a new column, simply do:" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
namehardnesssp. gr.testnew_column
0Amphibole5.502.800ANaN
1Biotite2.753.00012jNaN
2Calcite3.002.720TrueNaN
3Dolomite3.002.8509NaN
4Feldspars6.002.64511.0NaN
\n", - "
" - ], - "text/plain": [ - " name hardness sp. gr. test new_column\n", - "0 Amphibole 5.50 2.800 A NaN\n", - "1 Biotite 2.75 3.000 12j NaN\n", - "2 Calcite 3.00 2.720 True NaN\n", - "3 Dolomite 3.00 2.850 9 NaN\n", - "4 Feldspars 6.00 2.645 11.0 NaN" - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df1['new_column'] = np.nan\n", - "df1" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### Labeling ``DataFrames``\n", - "\n", - "You can also rename your columns' and rows' index names by changing your DataFrame's columns and index attributes, respectively. Recall our df2:" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
01234
0Garnet7.0Fracture3.9NaN
1Graphite1.5One2.3NaN
2Kyanite6One4.01NaN
3testbad@#$%^Falseasdf
\n", - "
" - ], - "text/plain": [ - " 0 1 2 3 4\n", - "0 Garnet 7.0 Fracture 3.9 NaN\n", - "1 Graphite 1.5 One 2.3 NaN\n", - "2 Kyanite 6 One 4.01 NaN\n", - "3 test bad @#$%^ False asdf" - ] - }, - "execution_count": 44, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df2" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Now let's rename its columns' and rows' index names." - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
namehardnesscleavagesp. gr.test
row0Garnet7.0Fracture3.9NaN
row1Graphite1.5One2.3NaN
row2Kyanite6One4.01NaN
row3testbad@#$%^Falseasdf
\n", - "
" - ], - "text/plain": [ - " name hardness cleavage sp. gr. test\n", - "row0 Garnet 7.0 Fracture 3.9 NaN\n", - "row1 Graphite 1.5 One 2.3 NaN\n", - "row2 Kyanite 6 One 4.01 NaN\n", - "row3 test bad @#$%^ False asdf" - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df2.columns = ['name', 'hardness', 'cleavage', 'sp. gr.','test']\n", - "df2.index = ['row0','row1','row2','row3']\n", - "\n", - "df2" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "### Concatenating ``DataFrames``\n", - "\n", - "We can also concatenate DataFrames to each other, even if they are of different sizes." - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " name hardness sp. gr. test new_column cleavage\n", - "0 Amphibole 5.5 2.8 A NaN NaN\n", - "1 Biotite 2.75 3.0 12j NaN NaN\n", - "2 Calcite 3.0 2.72 True NaN NaN\n", - "3 Dolomite 3.0 2.85 9 NaN NaN\n", - "4 Feldspars 6.0 2.645 11.0 NaN NaN\n", - "row0 Garnet 7.0 3.9 NaN NaN Fracture\n", - "row1 Graphite 1.5 2.3 NaN NaN One\n", - "row2 Kyanite 6 4.01 NaN NaN One\n", - "row3 test bad False asdf NaN @#$%^\n" - ] - } - ], - "source": [ - "df3 = pd.concat([df1, df2])\n", - "print(df3)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "In the resulting table, we notice that pandas automatically added NaN (\"Not a Number\") values to the missing entries of either table. Very convenient!" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Removing rows and columns\n", - "\n", - "Our table looks a bit messy though... let's make it better by removing the 'test' row and column. We can drop them by using the pd.drop() function. By default, the pd.drop() function outputs a copy of the inserted DataFrame without the dropped items. The original data will then be preserved if you give a new name to the dataframe (i.e., the copy) with dropped items.\n", - "\n", - "Example of how you could use `pd.drop()` to remove a row or column. Note that we used that row's index name and column's index name." - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " name hardness sp. gr. new_column cleavage\n", - "0 Amphibole 5.5 2.8 NaN NaN\n", - "1 Biotite 2.75 3.0 NaN NaN\n", - "2 Calcite 3.0 2.72 NaN NaN\n", - "3 Dolomite 3.0 2.85 NaN NaN\n", - "4 Feldspars 6.0 2.645 NaN NaN\n", - "row0 Garnet 7.0 3.9 NaN Fracture\n", - "row1 Graphite 1.5 2.3 NaN One\n", - "row2 Kyanite 6 4.01 NaN One\n" - ] - } - ], - "source": [ - "new_df3 = df3.drop('row3', axis=0) \n", - "new_df3 = new_df3.drop('test', axis=1) \n", - "print(new_df3)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Recall that `df3` is unchanged" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
namehardnesssp. gr.testnew_columncleavage
0Amphibole5.52.8ANaNNaN
1Biotite2.753.012jNaNNaN
2Calcite3.02.72TrueNaNNaN
3Dolomite3.02.859NaNNaN
4Feldspars6.02.64511.0NaNNaN
row0Garnet7.03.9NaNNaNFracture
row1Graphite1.52.3NaNNaNOne
row2Kyanite64.01NaNNaNOne
row3testbadFalseasdfNaN@#$%^
\n", - "
" - ], - "text/plain": [ - " name hardness sp. gr. test new_column cleavage\n", - "0 Amphibole 5.5 2.8 A NaN NaN\n", - "1 Biotite 2.75 3.0 12j NaN NaN\n", - "2 Calcite 3.0 2.72 True NaN NaN\n", - "3 Dolomite 3.0 2.85 9 NaN NaN\n", - "4 Feldspars 6.0 2.645 11.0 NaN NaN\n", - "row0 Garnet 7.0 3.9 NaN NaN Fracture\n", - "row1 Graphite 1.5 2.3 NaN NaN One\n", - "row2 Kyanite 6 4.01 NaN NaN One\n", - "row3 test bad False asdf NaN @#$%^" - ] - }, - "execution_count": 48, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df3" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "In case you would like to edit the original df3; you would apply the drop-operation 'inplace'. For this, we use the inplace=True option. To avoid dropping rows and columns with the same index name, you could use the pd.reset_index() function. With drop=True, the new DataFrame will have dropped the old indexes; keeping the new reset ones.\n", - "\n", - "Reset the index to the default integer index and drop the old indexes." - ] - }, - { - "cell_type": "code", - "execution_count": 49, + "execution_count": 42, "metadata": { "collapsed": true, "nbgrader": { @@ -1497,8 +378,6 @@ " hardness\n", " sp. gr.\n", " test\n", - " new_column\n", - " cleavage\n", " \n", " \n", " \n", @@ -1508,8 +387,6 @@ " 5.5\n", " 2.8\n", " A\n", - " NaN\n", - " NaN\n", " \n", " \n", " 1\n", @@ -1517,169 +394,51 @@ " 2.75\n", " 3.0\n", " 12j\n", - " NaN\n", - " NaN\n", - " \n", - " \n", - " 2\n", - " Calcite\n", - " 3.0\n", - " 2.72\n", - " True\n", - " NaN\n", - " NaN\n", - " \n", - " \n", - " 3\n", - " Dolomite\n", - " 3.0\n", - " 2.85\n", - " 9\n", - " NaN\n", - " NaN\n", - " \n", - " \n", - " 4\n", - " Feldspars\n", - " 6.0\n", - " 2.645\n", - " 11.0\n", - " NaN\n", - " NaN\n", " \n", " \n", - " 5\n", - " Garnet\n", - " 7.0\n", - " 3.9\n", - " NaN\n", - " NaN\n", - " Fracture\n", - " \n", - " \n", - " 6\n", - " Graphite\n", - " 1.5\n", - " 2.3\n", - " NaN\n", - " NaN\n", - " One\n", - " \n", - " \n", - " 7\n", - " Kyanite\n", - " 6\n", - " 4.01\n", - " NaN\n", - " NaN\n", - " One\n", - " \n", - " \n", - " 8\n", - " test\n", - " bad\n", - " False\n", - " asdf\n", - " NaN\n", - " @#$%^\n", - " \n", - " \n", - "\n", - "
" - ], - "text/plain": [ - " name hardness sp. gr. test new_column cleavage\n", - "0 Amphibole 5.5 2.8 A NaN NaN\n", - "1 Biotite 2.75 3.0 12j NaN NaN\n", - "2 Calcite 3.0 2.72 True NaN NaN\n", - "3 Dolomite 3.0 2.85 9 NaN NaN\n", - "4 Feldspars 6.0 2.645 11.0 NaN NaN\n", - "5 Garnet 7.0 3.9 NaN NaN Fracture\n", - "6 Graphite 1.5 2.3 NaN NaN One\n", - "7 Kyanite 6 4.01 NaN NaN One\n", - "8 test bad False asdf NaN @#$%^" - ] - }, - "execution_count": 49, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df3_cleaned = df3.reset_index(drop=True) \n", - "df3_cleaned" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's drop row 8 and column 'test' (remember to add axis=1 when dropping a column)." - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " name hardness sp. gr. new_column cleavage\n", - "0 Amphibole 5.5 2.8 NaN NaN\n", - "1 Biotite 2.75 3.0 NaN NaN\n", - "2 Calcite 3.0 2.72 NaN NaN\n", - "3 Dolomite 3.0 2.85 NaN NaN\n", - "4 Feldspars 6.0 2.645 NaN NaN\n", - "5 Garnet 7.0 3.9 NaN Fracture\n", - "6 Graphite 1.5 2.3 NaN One\n", - "7 Kyanite 6 4.01 NaN One\n" - ] + " 2\n", + " Calcite\n", + " 3.0\n", + " 2.72\n", + " True\n", + " \n", + " \n", + " 3\n", + " Dolomite\n", + " 3.0\n", + " 2.85\n", + " 9\n", + " \n", + " \n", + " 4\n", + " Feldspars\n", + " 6.0\n", + " 2.645\n", + " 11.0\n", + " \n", + " \n", + "\n", + "
" + ], + "text/plain": [ + " name hardness sp. gr. test\n", + "0 Amphibole 5.5 2.8 A\n", + "1 Biotite 2.75 3.0 12j\n", + "2 Calcite 3.0 2.72 True\n", + "3 Dolomite 3.0 2.85 9\n", + "4 Feldspars 6.0 2.645 11.0" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "df3_cleaned.drop(8,inplace=True)\n", - "df3_cleaned.drop('test',inplace=True, axis=1)\n", - "print(df3_cleaned)\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Note that if you try to re-run the above cell without re-running the previous one, you will get an error. This happens because after running the above cell once, you drop row '8' and the 'test' column from df3_cleaned, trying to run again will attempt to re-drop something that doesn't exist. Re-running the previous cell 'fixes' this issue since you re-assign df3_cleaned as df3.reset_index(drop=True)." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "::: {warning}\n", - "If one or more rows (or columns) have the same index name, pd.drop() will drop all of them.\n", - "::: " + "df_T = pd.DataFrame(data=[name,hardness,specific_gravity,test]).T\n", + "df_T.columns=['name', 'hardness', 'sp. gr.', 'test']\n", + "\n", + "df_T" ] }, { @@ -1693,16 +452,12 @@ } }, "source": [ - "### Accessing and modifying DataFrame values\n", - "\n", - "Now that we created our table, we want to be able to access and modify the individual values within it. This way we could add the missing values to the 'cleavage' column. There are many ways to do this because numpy and standard Python functions are often still applicable on pandas data structures. However, there is a difference in processing speed. Therefore, when accessing or modifying data, try to use pandas functions, such as: .iat(), .at(), .iloc(), and .loc() instead of using the common [] square bracket syntax, as they might raise some warnings:\n", - "\n", - "Note that the value still changed, but avoid doing so." + "To create a new column, simply do:" ] }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 43, "metadata": { "collapsed": true, "nbgrader": { @@ -1712,28 +467,6 @@ } }, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Users\\gui-win10\\AppData\\Local\\Temp\\ipykernel_24848\\54782356.py:1: FutureWarning: ChainedAssignmentError: behaviour will change in pandas 3.0!\n", - "You are setting values through chained assignment. Currently this works in certain cases, but when using Copy-on-Write (which will become the default behaviour in pandas 3.0) this will never work to update the original DataFrame or Series, because the intermediate object on which we are setting values will behave as a copy.\n", - "A typical example is when you are setting values in a column of a DataFrame, like:\n", - "\n", - "df[\"col\"][row_indexer] = value\n", - "\n", - "Use `df.loc[row_indexer, \"col\"] = values` instead, to perform the assignment in a single step and ensure this keeps updating the original `df`.\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - "\n", - " df3_cleaned.cleavage[1]='One'\n", - "C:\\Users\\gui-win10\\AppData\\Local\\Temp\\ipykernel_24848\\54782356.py:1: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " df3_cleaned.cleavage[1]='One'\n" - ] - }, { "data": { "text/html": [ @@ -1758,99 +491,182 @@ " name\n", " hardness\n", " sp. gr.\n", + " test\n", " new_column\n", - " cleavage\n", " \n", " \n", " \n", " \n", " 0\n", " Amphibole\n", - " 5.5\n", - " 2.8\n", - " NaN\n", + " 5.50\n", + " 2.800\n", + " A\n", " NaN\n", " \n", " \n", " 1\n", " Biotite\n", " 2.75\n", - " 3.0\n", + " 3.000\n", + " 12j\n", " NaN\n", - " One\n", " \n", " \n", " 2\n", " Calcite\n", - " 3.0\n", - " 2.72\n", - " NaN\n", + " 3.00\n", + " 2.720\n", + " True\n", " NaN\n", " \n", " \n", " 3\n", " Dolomite\n", - " 3.0\n", - " 2.85\n", - " NaN\n", + " 3.00\n", + " 2.850\n", + " 9\n", " NaN\n", " \n", " \n", " 4\n", " Feldspars\n", - " 6.0\n", + " 6.00\n", " 2.645\n", + " 11.0\n", " NaN\n", - " NaN\n", " \n", + " \n", + "\n", + "
" + ], + "text/plain": [ + " name hardness sp. gr. test new_column\n", + "0 Amphibole 5.50 2.800 A NaN\n", + "1 Biotite 2.75 3.000 12j NaN\n", + "2 Calcite 3.00 2.720 True NaN\n", + "3 Dolomite 3.00 2.850 9 NaN\n", + "4 Feldspars 6.00 2.645 11.0 NaN" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df1['new_column'] = np.nan\n", + "df1" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### Labeling ``DataFrames``\n", + "\n", + "You can also rename your columns' and rows' index names by changing your DataFrame's columns and index attributes, respectively. Recall our df2:" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", + " \n", " \n", " \n", + " \n", " \n", " \n", - " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", + " \n", " \n", " \n", - " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", + " \n", " \n", " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", "
01234
50Garnet7.0Fracture3.9NaNFracture
61Graphite1.5One2.3NaNOne
72Kyanite6One4.01NaNOne
3testbad@#$%^Falseasdf
\n", "
" ], "text/plain": [ - " name hardness sp. gr. new_column cleavage\n", - "0 Amphibole 5.5 2.8 NaN NaN\n", - "1 Biotite 2.75 3.0 NaN One\n", - "2 Calcite 3.0 2.72 NaN NaN\n", - "3 Dolomite 3.0 2.85 NaN NaN\n", - "4 Feldspars 6.0 2.645 NaN NaN\n", - "5 Garnet 7.0 3.9 NaN Fracture\n", - "6 Graphite 1.5 2.3 NaN One\n", - "7 Kyanite 6 4.01 NaN One" + " 0 1 2 3 4\n", + "0 Garnet 7.0 Fracture 3.9 NaN\n", + "1 Graphite 1.5 One 2.3 NaN\n", + "2 Kyanite 6 One 4.01 NaN\n", + "3 test bad @#$%^ False asdf" ] }, - "execution_count": 51, + "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "df3_cleaned.cleavage[1]='One' \n", - "df3_cleaned " + "df2" ] }, { @@ -1864,16 +680,12 @@ } }, "source": [ - "### .iat() vs .at() vs .iloc() vs .loc()\n", - "\n", - "In this discussion in stackoverflow, they point out some differences between these methods. To keep in mind, .iat() and .at() are the fastest ones, but they only return scalars (one element), while .loc() and .iloc() can access several elements at the same time. Lastly, .iat() and .iloc use indexes (numbers), while .at() and .loc() use labels. For more information, check the stackoverflow discussion.\n", - "\n", - "Acessing values using arrays as index with `.iloc()`, only method that allows arrays in both rows and cols." + "Now let's rename its columns' and rows' index names." ] }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 45, "metadata": { "collapsed": true, "nbgrader": { @@ -1906,42 +718,130 @@ " \n", " name\n", " hardness\n", + " cleavage\n", " sp. gr.\n", + " test\n", " \n", " \n", " \n", " \n", - " 0\n", - " Amphibole\n", - " 5.5\n", - " 2.8\n", + " row0\n", + " Garnet\n", + " 7.0\n", + " Fracture\n", + " 3.9\n", + " NaN\n", " \n", " \n", - " 1\n", - " Biotite\n", - " 2.75\n", - " 3.0\n", + " row1\n", + " Graphite\n", + " 1.5\n", + " One\n", + " 2.3\n", + " NaN\n", + " \n", + " \n", + " row2\n", + " Kyanite\n", + " 6\n", + " One\n", + " 4.01\n", + " NaN\n", + " \n", + " \n", + " row3\n", + " test\n", + " bad\n", + " @#$%^\n", + " False\n", + " asdf\n", " \n", " \n", "\n", "
" ], "text/plain": [ - " name hardness sp. gr.\n", - "0 Amphibole 5.5 2.8\n", - "1 Biotite 2.75 3.0" + " name hardness cleavage sp. gr. test\n", + "row0 Garnet 7.0 Fracture 3.9 NaN\n", + "row1 Graphite 1.5 One 2.3 NaN\n", + "row2 Kyanite 6 One 4.01 NaN\n", + "row3 test bad @#$%^ False asdf" ] }, - "execution_count": 52, + "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "indx_array_row = np.array([0,1,2])\n", - "indx_array_col = np.array([0,1,2,3])\n", + "df2.columns = ['name', 'hardness', 'cleavage', 'sp. gr.','test']\n", + "df2.index = ['row0','row1','row2','row3']\n", "\n", - "df3_cleaned.iloc[indx_array_row[:2],indx_array_col[:3]]" + "df2" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### Concatenating ``DataFrames``\n", + "\n", + "We can also concatenate DataFrames to each other, even if they are of different sizes." + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " name hardness sp. gr. test new_column cleavage\n", + "0 Amphibole 5.5 2.8 A NaN NaN\n", + "1 Biotite 2.75 3.0 12j NaN NaN\n", + "2 Calcite 3.0 2.72 True NaN NaN\n", + "3 Dolomite 3.0 2.85 9 NaN NaN\n", + "4 Feldspars 6.0 2.645 11.0 NaN NaN\n", + "row0 Garnet 7.0 3.9 NaN NaN Fracture\n", + "row1 Graphite 1.5 2.3 NaN NaN One\n", + "row2 Kyanite 6 4.01 NaN NaN One\n", + "row3 test bad False asdf NaN @#$%^\n" + ] + } + ], + "source": [ + "df3 = pd.concat([df1, df2])\n", + "print(df3)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "In the resulting table, we notice that pandas automatically added NaN (\"Not a Number\") values to the missing entries of either table. Very convenient!" ] }, { @@ -1949,12 +849,16 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Accessing values with `.loc()`, only rows are allowed to be arrays" + "### Removing rows and columns\n", + "\n", + "Our table looks a bit messy though... let's make it better by removing the 'test' row and column. We can drop them by using the pd.drop() function. By default, the pd.drop() function outputs a copy of the inserted DataFrame without the dropped items. The original data will then be preserved if you give a new name to the dataframe (i.e., the copy) with dropped items.\n", + "\n", + "Example of how you could use `pd.drop()` to remove a row or column. Note that we used that row's index name and column's index name." ] }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 47, "metadata": { "collapsed": true, "nbgrader": { @@ -1965,20 +869,25 @@ }, "outputs": [ { - "data": { - "text/plain": [ - "0 5.5\n", - "1 2.75\n", - "Name: hardness, dtype: object" - ] - }, - "execution_count": 53, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + " name hardness sp. gr. new_column cleavage\n", + "0 Amphibole 5.5 2.8 NaN NaN\n", + "1 Biotite 2.75 3.0 NaN NaN\n", + "2 Calcite 3.0 2.72 NaN NaN\n", + "3 Dolomite 3.0 2.85 NaN NaN\n", + "4 Feldspars 6.0 2.645 NaN NaN\n", + "row0 Garnet 7.0 3.9 NaN Fracture\n", + "row1 Graphite 1.5 2.3 NaN One\n", + "row2 Kyanite 6 4.01 NaN One\n" + ] } ], "source": [ - "df3_cleaned.loc[indx_array_row[:2],'hardness']" + "new_df3 = df3.drop('row3', axis=0) \n", + "new_df3 = new_df3.drop('test', axis=1) \n", + "print(new_df3)" ] }, { @@ -1986,12 +895,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Or multiple columns with `.loc()`:" + "Recall that `df3` is unchanged" ] }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 48, "metadata": { "collapsed": true, "nbgrader": { @@ -2022,103 +931,141 @@ " \n", " \n", " \n", + " name\n", " hardness\n", + " sp. gr.\n", + " test\n", + " new_column\n", " cleavage\n", " \n", " \n", " \n", " \n", " 0\n", + " Amphibole\n", " 5.5\n", + " 2.8\n", + " A\n", + " NaN\n", " NaN\n", " \n", " \n", " 1\n", + " Biotite\n", " 2.75\n", - " One\n", + " 3.0\n", + " 12j\n", + " NaN\n", + " NaN\n", " \n", - " \n", - "\n", - "
" - ], - "text/plain": [ - " hardness cleavage\n", - "0 5.5 NaN\n", - "1 2.75 One" - ] - }, - "execution_count": 54, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df3_cleaned.loc[indx_array_row[:2],['hardness', 'cleavage']]" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Accessing values with `.at()`, no arrays allowed, only labels. Note that using 0 will work since we do not have labels for the rows so their labels are their index." - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "data": { + " \n", + " 2\n", + " Calcite\n", + " 3.0\n", + " 2.72\n", + " True\n", + " NaN\n", + " NaN\n", + " \n", + " \n", + " 3\n", + " Dolomite\n", + " 3.0\n", + " 2.85\n", + " 9\n", + " NaN\n", + " NaN\n", + " \n", + " \n", + " 4\n", + " Feldspars\n", + " 6.0\n", + " 2.645\n", + " 11.0\n", + " NaN\n", + " NaN\n", + " \n", + " \n", + " row0\n", + " Garnet\n", + " 7.0\n", + " 3.9\n", + " NaN\n", + " NaN\n", + " Fracture\n", + " \n", + " \n", + " row1\n", + " Graphite\n", + " 1.5\n", + " 2.3\n", + " NaN\n", + " NaN\n", + " One\n", + " \n", + " \n", + " row2\n", + " Kyanite\n", + " 6\n", + " 4.01\n", + " NaN\n", + " NaN\n", + " One\n", + " \n", + " \n", + " row3\n", + " test\n", + " bad\n", + " False\n", + " asdf\n", + " NaN\n", + " @#$%^\n", + " \n", + " \n", + "\n", + "" + ], "text/plain": [ - "5.5" + " name hardness sp. gr. test new_column cleavage\n", + "0 Amphibole 5.5 2.8 A NaN NaN\n", + "1 Biotite 2.75 3.0 12j NaN NaN\n", + "2 Calcite 3.0 2.72 True NaN NaN\n", + "3 Dolomite 3.0 2.85 9 NaN NaN\n", + "4 Feldspars 6.0 2.645 11.0 NaN NaN\n", + "row0 Garnet 7.0 3.9 NaN NaN Fracture\n", + "row1 Graphite 1.5 2.3 NaN NaN One\n", + "row2 Kyanite 6 4.01 NaN NaN One\n", + "row3 test bad False asdf NaN @#$%^" ] }, - "execution_count": 55, + "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "df3_cleaned.at[0, 'hardness']" + "df3" ] }, { "attachments": {}, "cell_type": "markdown", - "metadata": {}, - "source": [ - "If we were to change the index of this df to their names and delete column 'name'..." - ] - }, - { - "cell_type": "code", - "execution_count": 56, "metadata": { - "collapsed": true, "nbgrader": { "grade": false, "locked": true, "solution": false } }, - "outputs": [], "source": [ - "df3_cleaned.index = df3_cleaned.name\n", - "df3_cleaned.drop('name',axis=1,inplace=True)" + "In case you would like to edit the original df3; you would apply the drop-operation 'inplace'. For this, we use the inplace=True option. To avoid dropping rows and columns with the same index name, you could use the pd.reset_index() function. With drop=True, the new DataFrame will have dropped the old indexes; keeping the new reset ones.\n", + "\n", + "Reset the index to the default integer index and drop the old indexes." ] }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 49, "metadata": { "collapsed": true, "nbgrader": { @@ -2149,99 +1096,120 @@ " \n", " \n", " \n", + " name\n", " hardness\n", " sp. gr.\n", + " test\n", " new_column\n", " cleavage\n", " \n", - " \n", - " name\n", - " \n", - " \n", - " \n", - " \n", - " \n", " \n", " \n", " \n", - " Amphibole\n", + " 0\n", + " Amphibole\n", " 5.5\n", " 2.8\n", + " A\n", " NaN\n", " NaN\n", " \n", " \n", - " Biotite\n", + " 1\n", + " Biotite\n", " 2.75\n", " 3.0\n", + " 12j\n", + " NaN\n", " NaN\n", - " One\n", " \n", " \n", - " Calcite\n", + " 2\n", + " Calcite\n", " 3.0\n", " 2.72\n", + " True\n", " NaN\n", " NaN\n", " \n", " \n", - " Dolomite\n", + " 3\n", + " Dolomite\n", " 3.0\n", " 2.85\n", + " 9\n", " NaN\n", " NaN\n", " \n", " \n", - " Feldspars\n", + " 4\n", + " Feldspars\n", " 6.0\n", " 2.645\n", + " 11.0\n", " NaN\n", " NaN\n", " \n", " \n", - " Garnet\n", + " 5\n", + " Garnet\n", " 7.0\n", " 3.9\n", " NaN\n", + " NaN\n", " Fracture\n", " \n", " \n", - " Graphite\n", + " 6\n", + " Graphite\n", " 1.5\n", " 2.3\n", " NaN\n", + " NaN\n", " One\n", " \n", " \n", - " Kyanite\n", + " 7\n", + " Kyanite\n", " 6\n", " 4.01\n", " NaN\n", + " NaN\n", " One\n", " \n", + " \n", + " 8\n", + " test\n", + " bad\n", + " False\n", + " asdf\n", + " NaN\n", + " @#$%^\n", + " \n", " \n", "\n", "" ], "text/plain": [ - " hardness sp. gr. new_column cleavage\n", - "name \n", - "Amphibole 5.5 2.8 NaN NaN\n", - "Biotite 2.75 3.0 NaN One\n", - "Calcite 3.0 2.72 NaN NaN\n", - "Dolomite 3.0 2.85 NaN NaN\n", - "Feldspars 6.0 2.645 NaN NaN\n", - "Garnet 7.0 3.9 NaN Fracture\n", - "Graphite 1.5 2.3 NaN One\n", - "Kyanite 6 4.01 NaN One" + " name hardness sp. gr. test new_column cleavage\n", + "0 Amphibole 5.5 2.8 A NaN NaN\n", + "1 Biotite 2.75 3.0 12j NaN NaN\n", + "2 Calcite 3.0 2.72 True NaN NaN\n", + "3 Dolomite 3.0 2.85 9 NaN NaN\n", + "4 Feldspars 6.0 2.645 11.0 NaN NaN\n", + "5 Garnet 7.0 3.9 NaN NaN Fracture\n", + "6 Graphite 1.5 2.3 NaN NaN One\n", + "7 Kyanite 6 4.01 NaN NaN One\n", + "8 test bad False asdf NaN @#$%^" ] }, - "execution_count": 57, + "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "df3_cleaned = df3.reset_index(drop=True) \n", "df3_cleaned" ] }, @@ -2250,12 +1218,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Now using `df.at[0,'hardness']` doesn't work since there's no row with label 0.\n" + "Now let's drop row 8 and column 'test' (remember to add axis=1 when dropping a column)." ] }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 50, "metadata": { "collapsed": true, "nbgrader": { @@ -2266,135 +1234,55 @@ }, "outputs": [ { - "ename": "KeyError", - "evalue": "0", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", - "File \u001b[1;32mc:\\Users\\gui-win10\\AppData\\Local\\pypoetry\\Cache\\virtualenvs\\learn-python-rwbttIgo-py3.11\\Lib\\site-packages\\pandas\\core\\indexes\\base.py:3805\u001b[0m, in \u001b[0;36mIndex.get_loc\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m 3804\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m-> 3805\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_engine\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcasted_key\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 3806\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m err:\n", - "File \u001b[1;32mindex.pyx:167\u001b[0m, in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[1;34m()\u001b[0m\n", - "File \u001b[1;32mindex.pyx:196\u001b[0m, in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[1;34m()\u001b[0m\n", - "File \u001b[1;32mpandas\\\\_libs\\\\hashtable_class_helper.pxi:7081\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[1;34m()\u001b[0m\n", - "File \u001b[1;32mpandas\\\\_libs\\\\hashtable_class_helper.pxi:7089\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[1;34m()\u001b[0m\n", - "\u001b[1;31mKeyError\u001b[0m: 0", - "\nThe above exception was the direct cause of the following exception:\n", - "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[58], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mdf3_cleaned\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mat\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mhardness\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\n", - "File \u001b[1;32mc:\\Users\\gui-win10\\AppData\\Local\\pypoetry\\Cache\\virtualenvs\\learn-python-rwbttIgo-py3.11\\Lib\\site-packages\\pandas\\core\\indexing.py:2575\u001b[0m, in \u001b[0;36m_AtIndexer.__getitem__\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m 2572\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInvalid call for scalar access (getting)!\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 2573\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mobj\u001b[38;5;241m.\u001b[39mloc[key]\n\u001b[1;32m-> 2575\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__getitem__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[1;32mc:\\Users\\gui-win10\\AppData\\Local\\pypoetry\\Cache\\virtualenvs\\learn-python-rwbttIgo-py3.11\\Lib\\site-packages\\pandas\\core\\indexing.py:2527\u001b[0m, in \u001b[0;36m_ScalarAccessIndexer.__getitem__\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m 2524\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInvalid call for scalar access (getting)!\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 2526\u001b[0m key \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_convert_key(key)\n\u001b[1;32m-> 2527\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mobj\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_get_value\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkey\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtakeable\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_takeable\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[1;32mc:\\Users\\gui-win10\\AppData\\Local\\pypoetry\\Cache\\virtualenvs\\learn-python-rwbttIgo-py3.11\\Lib\\site-packages\\pandas\\core\\frame.py:4209\u001b[0m, in \u001b[0;36mDataFrame._get_value\u001b[1;34m(self, index, col, takeable)\u001b[0m\n\u001b[0;32m 4203\u001b[0m engine \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mindex\u001b[38;5;241m.\u001b[39m_engine\n\u001b[0;32m 4205\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mindex, MultiIndex):\n\u001b[0;32m 4206\u001b[0m \u001b[38;5;66;03m# CategoricalIndex: Trying to use the engine fastpath may give incorrect\u001b[39;00m\n\u001b[0;32m 4207\u001b[0m \u001b[38;5;66;03m# results if our categories are integers that dont match our codes\u001b[39;00m\n\u001b[0;32m 4208\u001b[0m \u001b[38;5;66;03m# IntervalIndex: IntervalTree has no get_loc\u001b[39;00m\n\u001b[1;32m-> 4209\u001b[0m row \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mindex\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mindex\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 4210\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m series\u001b[38;5;241m.\u001b[39m_values[row]\n\u001b[0;32m 4212\u001b[0m \u001b[38;5;66;03m# For MultiIndex going through engine effectively restricts us to\u001b[39;00m\n\u001b[0;32m 4213\u001b[0m \u001b[38;5;66;03m# same-length tuples; see test_get_set_value_no_partial_indexing\u001b[39;00m\n", - "File \u001b[1;32mc:\\Users\\gui-win10\\AppData\\Local\\pypoetry\\Cache\\virtualenvs\\learn-python-rwbttIgo-py3.11\\Lib\\site-packages\\pandas\\core\\indexes\\base.py:3812\u001b[0m, in \u001b[0;36mIndex.get_loc\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m 3807\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(casted_key, \u001b[38;5;28mslice\u001b[39m) \u001b[38;5;129;01mor\u001b[39;00m (\n\u001b[0;32m 3808\u001b[0m \u001b[38;5;28misinstance\u001b[39m(casted_key, abc\u001b[38;5;241m.\u001b[39mIterable)\n\u001b[0;32m 3809\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28many\u001b[39m(\u001b[38;5;28misinstance\u001b[39m(x, \u001b[38;5;28mslice\u001b[39m) \u001b[38;5;28;01mfor\u001b[39;00m x \u001b[38;5;129;01min\u001b[39;00m casted_key)\n\u001b[0;32m 3810\u001b[0m ):\n\u001b[0;32m 3811\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m InvalidIndexError(key)\n\u001b[1;32m-> 3812\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(key) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01merr\u001b[39;00m\n\u001b[0;32m 3813\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m:\n\u001b[0;32m 3814\u001b[0m \u001b[38;5;66;03m# If we have a listlike key, _check_indexing_error will raise\u001b[39;00m\n\u001b[0;32m 3815\u001b[0m \u001b[38;5;66;03m# InvalidIndexError. Otherwise we fall through and re-raise\u001b[39;00m\n\u001b[0;32m 3816\u001b[0m \u001b[38;5;66;03m# the TypeError.\u001b[39;00m\n\u001b[0;32m 3817\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_check_indexing_error(key)\n", - "\u001b[1;31mKeyError\u001b[0m: 0" + "name": "stdout", + "output_type": "stream", + "text": [ + " name hardness sp. gr. new_column cleavage\n", + "0 Amphibole 5.5 2.8 NaN NaN\n", + "1 Biotite 2.75 3.0 NaN NaN\n", + "2 Calcite 3.0 2.72 NaN NaN\n", + "3 Dolomite 3.0 2.85 NaN NaN\n", + "4 Feldspars 6.0 2.645 NaN NaN\n", + "5 Garnet 7.0 3.9 NaN Fracture\n", + "6 Graphite 1.5 2.3 NaN One\n", + "7 Kyanite 6 4.01 NaN One\n" ] } ], "source": [ - "df3_cleaned.at[0, 'hardness']" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Accessing values with `.iat()`, no arrays allowed, no labels allowed only indexes." - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "nan" - ] - }, - "execution_count": 59, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df3_cleaned.iat[1, 2]" + "df3_cleaned.drop(8,inplace=True)\n", + "df3_cleaned.drop('test',inplace=True, axis=1)\n", + "print(df3_cleaned)\n" ] }, { "attachments": {}, "cell_type": "markdown", - "metadata": {}, - "source": [ - "In case you want to know the index number of a column or row:" - ] - }, - { - "cell_type": "code", - "execution_count": 60, "metadata": { - "collapsed": true, "nbgrader": { "grade": false, "locked": true, "solution": false } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2\n", - "3\n" - ] - } - ], "source": [ - "print(df3_cleaned.columns.get_loc('new_column')) \n", - "print(df3_cleaned.index.get_loc('Dolomite')) " + "Note that if you try to re-run the above cell without re-running the previous one, you will get an error. This happens because after running the above cell once, you drop row '8' and the 'test' column from df3_cleaned, trying to run again will attempt to re-drop something that doesn't exist. Re-running the previous cell 'fixes' this issue since you re-assign df3_cleaned as df3.reset_index(drop=True)." ] }, { "attachments": {}, "cell_type": "markdown", - "metadata": {}, - "source": [ - "Since the above lines return the index of a column and row you can use them directly with `.iat()`." - ] - }, - { - "cell_type": "code", - "execution_count": 61, "metadata": { - "collapsed": true, "nbgrader": { "grade": false, "locked": true, "solution": false } }, - "outputs": [ - { - "data": { - "text/plain": [ - "nan" - ] - }, - "execution_count": 61, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ - "df3_cleaned.iat[df3_cleaned.index.get_loc('Dolomite'), df3_cleaned.columns.get_loc('new_column')]" + "::: {warning}\n", + "If one or more rows (or columns) have the same index name, pd.drop() will drop all of them.\n", + "::: " ] }, { @@ -2408,12 +1296,16 @@ } }, "source": [ - "Selecting multiple columns:" + "### Accessing and modifying DataFrame values\n", + "\n", + "Now that we created our table, we want to be able to access and modify the individual values within it. This way we could add the missing values to the 'cleavage' column. There are many ways to do this because numpy and standard Python functions are often still applicable on pandas data structures. However, there is a difference in processing speed. Therefore, when accessing or modifying data, try to use pandas functions, such as: .iat(), .at(), .iloc(), and .loc() instead of using the common [] square bracket syntax, as they might raise some warnings:\n", + "\n", + "Note that the value still changed, but avoid doing so." ] }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 51, "metadata": { "collapsed": true, "nbgrader": { @@ -2423,6 +1315,28 @@ } }, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\gui-win10\\AppData\\Local\\Temp\\ipykernel_24848\\54782356.py:1: FutureWarning: ChainedAssignmentError: behaviour will change in pandas 3.0!\n", + "You are setting values through chained assignment. Currently this works in certain cases, but when using Copy-on-Write (which will become the default behaviour in pandas 3.0) this will never work to update the original DataFrame or Series, because the intermediate object on which we are setting values will behave as a copy.\n", + "A typical example is when you are setting values in a column of a DataFrame, like:\n", + "\n", + "df[\"col\"][row_indexer] = value\n", + "\n", + "Use `df.loc[row_indexer, \"col\"] = values` instead, to perform the assignment in a single step and ensure this keeps updating the original `df`.\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + "\n", + " df3_cleaned.cleavage[1]='One'\n", + "C:\\Users\\gui-win10\\AppData\\Local\\Temp\\ipykernel_24848\\54782356.py:1: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " df3_cleaned.cleavage[1]='One'\n" + ] + }, { "data": { "text/html": [ @@ -2444,80 +1358,102 @@ " \n", " \n", " \n", + " name\n", " hardness\n", + " sp. gr.\n", " new_column\n", - " \n", - " \n", - " name\n", - " \n", - " \n", + " cleavage\n", " \n", " \n", " \n", " \n", - " Amphibole\n", + " 0\n", + " Amphibole\n", " 5.5\n", + " 2.8\n", + " NaN\n", " NaN\n", " \n", " \n", - " Biotite\n", + " 1\n", + " Biotite\n", " 2.75\n", + " 3.0\n", " NaN\n", + " One\n", " \n", " \n", - " Calcite\n", + " 2\n", + " Calcite\n", " 3.0\n", + " 2.72\n", + " NaN\n", " NaN\n", " \n", " \n", - " Dolomite\n", + " 3\n", + " Dolomite\n", " 3.0\n", + " 2.85\n", + " NaN\n", " NaN\n", " \n", " \n", - " Feldspars\n", + " 4\n", + " Feldspars\n", " 6.0\n", + " 2.645\n", + " NaN\n", " NaN\n", " \n", " \n", - " Garnet\n", + " 5\n", + " Garnet\n", " 7.0\n", + " 3.9\n", " NaN\n", + " Fracture\n", " \n", " \n", - " Graphite\n", + " 6\n", + " Graphite\n", " 1.5\n", + " 2.3\n", " NaN\n", + " One\n", " \n", " \n", - " Kyanite\n", + " 7\n", + " Kyanite\n", " 6\n", + " 4.01\n", " NaN\n", + " One\n", " \n", " \n", "\n", "" ], "text/plain": [ - " hardness new_column\n", - "name \n", - "Amphibole 5.5 NaN\n", - "Biotite 2.75 NaN\n", - "Calcite 3.0 NaN\n", - "Dolomite 3.0 NaN\n", - "Feldspars 6.0 NaN\n", - "Garnet 7.0 NaN\n", - "Graphite 1.5 NaN\n", - "Kyanite 6 NaN" + " name hardness sp. gr. new_column cleavage\n", + "0 Amphibole 5.5 2.8 NaN NaN\n", + "1 Biotite 2.75 3.0 NaN One\n", + "2 Calcite 3.0 2.72 NaN NaN\n", + "3 Dolomite 3.0 2.85 NaN NaN\n", + "4 Feldspars 6.0 2.645 NaN NaN\n", + "5 Garnet 7.0 3.9 NaN Fracture\n", + "6 Graphite 1.5 2.3 NaN One\n", + "7 Kyanite 6 4.01 NaN One" ] }, - "execution_count": 62, + "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "df3_cleaned[['hardness','new_column']]" + "df3_cleaned.cleavage[1]='One' \n", + "df3_cleaned " ] }, { @@ -2531,12 +1467,16 @@ } }, "source": [ - "Finally, removing a column by making a copy and re-assigning the original variable as its copy. (Alternative to inplace=True)" + "### .iat() vs .at() vs .iloc() vs .loc()\n", + "\n", + "In this discussion in stackoverflow, they point out some differences between these methods. To keep in mind, .iat() and .at() are the fastest ones, but they only return scalars (one element), while .loc() and .iloc() can access several elements at the same time. Lastly, .iat() and .iloc use indexes (numbers), while .at() and .loc() use labels. For more information, check the stackoverflow discussion.\n", + "\n", + "Acessing values using arrays as index with `.iloc()`, only method that allows arrays in both rows and cols." ] }, { "cell_type": "code", - "execution_count": 63, + "execution_count": 52, "metadata": { "collapsed": true, "nbgrader": { @@ -2567,64 +1507,137 @@ " \n", " \n", " \n", + " name\n", " hardness\n", " sp. gr.\n", - " cleavage\n", - " \n", - " \n", - " name\n", - " \n", - " \n", - " \n", " \n", " \n", " \n", " \n", - " Amphibole\n", + " 0\n", + " Amphibole\n", " 5.5\n", " 2.8\n", - " NaN\n", " \n", " \n", - " Biotite\n", + " 1\n", + " Biotite\n", " 2.75\n", " 3.0\n", - " One\n", - " \n", - " \n", - " Calcite\n", - " 3.0\n", - " 2.72\n", - " NaN\n", " \n", - " \n", - " Dolomite\n", - " 3.0\n", - " 2.85\n", - " NaN\n", + " \n", + "\n", + "" + ], + "text/plain": [ + " name hardness sp. gr.\n", + "0 Amphibole 5.5 2.8\n", + "1 Biotite 2.75 3.0" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "indx_array_row = np.array([0,1,2])\n", + "indx_array_col = np.array([0,1,2,3])\n", + "\n", + "df3_cleaned.iloc[indx_array_row[:2],indx_array_col[:3]]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Accessing values with `.loc()`, only rows are allowed to be arrays" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0 5.5\n", + "1 2.75\n", + "Name: hardness, dtype: object" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df3_cleaned.loc[indx_array_row[:2],'hardness']" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or multiple columns with `.loc()`:" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -2632,48 +1645,53 @@ "" ], "text/plain": [ - " hardness sp. gr. cleavage\n", - "name \n", - "Amphibole 5.5 2.8 NaN\n", - "Biotite 2.75 3.0 One\n", - "Calcite 3.0 2.72 NaN\n", - "Dolomite 3.0 2.85 NaN\n", - "Feldspars 6.0 2.645 NaN\n", - "Garnet 7.0 3.9 Fracture\n", - "Graphite 1.5 2.3 One\n", - "Kyanite 6 4.01 One" + " hardness cleavage\n", + "0 5.5 NaN\n", + "1 2.75 One" ] }, - "execution_count": 63, + "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "df3_cleaned = df3_cleaned.drop('new_column', axis=1)\n", - "df3_cleaned" + "df3_cleaned.loc[indx_array_row[:2],['hardness', 'cleavage']]" ] }, { "attachments": {}, "cell_type": "markdown", + "metadata": {}, + "source": [ + "Accessing values with `.at()`, no arrays allowed, only labels. Note that using 0 will work since we do not have labels for the rows so their labels are their index." + ] + }, + { + "cell_type": "code", + "execution_count": 55, "metadata": { + "collapsed": true, "nbgrader": { "grade": false, "locked": true, "solution": false } }, + "outputs": [ + { + "data": { + "text/plain": [ + "5.5" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "## 6.4 Importing data into DataFrames and exploring its attributes\n", - "\n", - "pandas provides many functions to import data into dataframes, such as read_csv() to read delimited text files, or read_excel() for Excel or OpenDocument spreadsheets. read_csv() provides options that allow you to filter the data, such as specifying the separator/delimiter, the lines that form the headers, which rows to skip, etc. Let's analyze the mineral_properties.txt. Below a screenshot of it:

\n", - " \n", - "```{image} 01.png\n", - ":alt: rectangle\n", - ":width: 400px\n", - ":align: center\n", - "```" + "df3_cleaned.at[0, 'hardness']" ] }, { @@ -2681,16 +1699,29 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "below we import the `.txt`: \n", - "* we indicate that the separator is the comma `\"sep=','\"`\n", - "* we indicate the header (what should be the columns names) is in the second line `\"header=[1]\"`\n", - "* we indicate to not skip any rows `\"skiprows=None\"`\n", - "* we indicate the first column should be the index of the rows `\"index_col=0\"`\n" + "If we were to change the index of this df to their names and delete column 'name'..." + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [], + "source": [ + "df3_cleaned.index = df3_cleaned.name\n", + "df3_cleaned.drop('name',axis=1,inplace=True)" ] }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 57, "metadata": { "collapsed": true, "nbgrader": { @@ -2723,6 +1754,7 @@ " \n", " \n", " \n", + " \n", " \n", " \n", " \n", @@ -2730,79 +1762,64 @@ " \n", " \n", " \n", + " \n", " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", + " \n", " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -2810,32 +1827,25 @@ "" ], "text/plain": [ - " hardness sp. gr. cleavage\n", - "name \n", - "Amphibole 5.50 2.800 Two\n", - "Biotite 2.75 3.000 One\n", - "Calcite 3.00 2.720 Three\n", - "Dolomite 3.00 2.850 Three\n", - "Feldspars 6.00 2.645 Two\n", - "Garnet 7.00 3.900 Fracture\n", - "Graphite 1.50 2.300 One\n", - "Kyanite 6.00 4.010 One\n", - "Muscovite 2.25 2.930 One\n", - "Pyroxene 5.50 3.325 Two\n", - "Quartz 7.00 2.650 Fracture\n", - "Sillimanite 6.50 3.230 One" + " hardness sp. gr. new_column cleavage\n", + "name \n", + "Amphibole 5.5 2.8 NaN NaN\n", + "Biotite 2.75 3.0 NaN One\n", + "Calcite 3.0 2.72 NaN NaN\n", + "Dolomite 3.0 2.85 NaN NaN\n", + "Feldspars 6.0 2.645 NaN NaN\n", + "Garnet 7.0 3.9 NaN Fracture\n", + "Graphite 1.5 2.3 NaN One\n", + "Kyanite 6 4.01 NaN One" ] }, - "execution_count": 66, + "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "file_location = (\"mineral_properties.txt\")\n", - "df4 = pd.read_csv(file_location, sep=',', header=[1],\n", - " skiprows=None, index_col=0)\n", - "df4" + "df3_cleaned" ] }, { @@ -2843,12 +1853,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note that if we try to call any of the columns from `df4` we will get an error." + "Now using `df.at[0,'hardness']` doesn't work since there's no row with label 0.\n" ] }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 58, "metadata": { "collapsed": true, "nbgrader": { @@ -2860,7 +1870,7 @@ "outputs": [ { "ename": "KeyError", - "evalue": "'hardness'", + "evalue": "0", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", @@ -2870,162 +1880,33 @@ "File \u001b[1;32mindex.pyx:196\u001b[0m, in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[1;34m()\u001b[0m\n", "File \u001b[1;32mpandas\\\\_libs\\\\hashtable_class_helper.pxi:7081\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[1;34m()\u001b[0m\n", "File \u001b[1;32mpandas\\\\_libs\\\\hashtable_class_helper.pxi:7089\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[1;34m()\u001b[0m\n", - "\u001b[1;31mKeyError\u001b[0m: 'hardness'", + "\u001b[1;31mKeyError\u001b[0m: 0", "\nThe above exception was the direct cause of the following exception:\n", "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[67], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mdf4\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mhardness\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\n", - "File \u001b[1;32mc:\\Users\\gui-win10\\AppData\\Local\\pypoetry\\Cache\\virtualenvs\\learn-python-rwbttIgo-py3.11\\Lib\\site-packages\\pandas\\core\\frame.py:4090\u001b[0m, in \u001b[0;36mDataFrame.__getitem__\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m 4088\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcolumns\u001b[38;5;241m.\u001b[39mnlevels \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[0;32m 4089\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_getitem_multilevel(key)\n\u001b[1;32m-> 4090\u001b[0m indexer \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcolumns\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 4091\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m is_integer(indexer):\n\u001b[0;32m 4092\u001b[0m indexer \u001b[38;5;241m=\u001b[39m [indexer]\n", + "Cell \u001b[1;32mIn[58], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mdf3_cleaned\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mat\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mhardness\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\n", + "File \u001b[1;32mc:\\Users\\gui-win10\\AppData\\Local\\pypoetry\\Cache\\virtualenvs\\learn-python-rwbttIgo-py3.11\\Lib\\site-packages\\pandas\\core\\indexing.py:2575\u001b[0m, in \u001b[0;36m_AtIndexer.__getitem__\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m 2572\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInvalid call for scalar access (getting)!\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 2573\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mobj\u001b[38;5;241m.\u001b[39mloc[key]\n\u001b[1;32m-> 2575\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__getitem__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[1;32mc:\\Users\\gui-win10\\AppData\\Local\\pypoetry\\Cache\\virtualenvs\\learn-python-rwbttIgo-py3.11\\Lib\\site-packages\\pandas\\core\\indexing.py:2527\u001b[0m, in \u001b[0;36m_ScalarAccessIndexer.__getitem__\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m 2524\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInvalid call for scalar access (getting)!\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 2526\u001b[0m key \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_convert_key(key)\n\u001b[1;32m-> 2527\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mobj\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_get_value\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkey\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtakeable\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_takeable\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[1;32mc:\\Users\\gui-win10\\AppData\\Local\\pypoetry\\Cache\\virtualenvs\\learn-python-rwbttIgo-py3.11\\Lib\\site-packages\\pandas\\core\\frame.py:4209\u001b[0m, in \u001b[0;36mDataFrame._get_value\u001b[1;34m(self, index, col, takeable)\u001b[0m\n\u001b[0;32m 4203\u001b[0m engine \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mindex\u001b[38;5;241m.\u001b[39m_engine\n\u001b[0;32m 4205\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mindex, MultiIndex):\n\u001b[0;32m 4206\u001b[0m \u001b[38;5;66;03m# CategoricalIndex: Trying to use the engine fastpath may give incorrect\u001b[39;00m\n\u001b[0;32m 4207\u001b[0m \u001b[38;5;66;03m# results if our categories are integers that dont match our codes\u001b[39;00m\n\u001b[0;32m 4208\u001b[0m \u001b[38;5;66;03m# IntervalIndex: IntervalTree has no get_loc\u001b[39;00m\n\u001b[1;32m-> 4209\u001b[0m row \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mindex\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mindex\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 4210\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m series\u001b[38;5;241m.\u001b[39m_values[row]\n\u001b[0;32m 4212\u001b[0m \u001b[38;5;66;03m# For MultiIndex going through engine effectively restricts us to\u001b[39;00m\n\u001b[0;32m 4213\u001b[0m \u001b[38;5;66;03m# same-length tuples; see test_get_set_value_no_partial_indexing\u001b[39;00m\n", "File \u001b[1;32mc:\\Users\\gui-win10\\AppData\\Local\\pypoetry\\Cache\\virtualenvs\\learn-python-rwbttIgo-py3.11\\Lib\\site-packages\\pandas\\core\\indexes\\base.py:3812\u001b[0m, in \u001b[0;36mIndex.get_loc\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m 3807\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(casted_key, \u001b[38;5;28mslice\u001b[39m) \u001b[38;5;129;01mor\u001b[39;00m (\n\u001b[0;32m 3808\u001b[0m \u001b[38;5;28misinstance\u001b[39m(casted_key, abc\u001b[38;5;241m.\u001b[39mIterable)\n\u001b[0;32m 3809\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28many\u001b[39m(\u001b[38;5;28misinstance\u001b[39m(x, \u001b[38;5;28mslice\u001b[39m) \u001b[38;5;28;01mfor\u001b[39;00m x \u001b[38;5;129;01min\u001b[39;00m casted_key)\n\u001b[0;32m 3810\u001b[0m ):\n\u001b[0;32m 3811\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m InvalidIndexError(key)\n\u001b[1;32m-> 3812\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(key) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01merr\u001b[39;00m\n\u001b[0;32m 3813\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m:\n\u001b[0;32m 3814\u001b[0m \u001b[38;5;66;03m# If we have a listlike key, _check_indexing_error will raise\u001b[39;00m\n\u001b[0;32m 3815\u001b[0m \u001b[38;5;66;03m# InvalidIndexError. Otherwise we fall through and re-raise\u001b[39;00m\n\u001b[0;32m 3816\u001b[0m \u001b[38;5;66;03m# the TypeError.\u001b[39;00m\n\u001b[0;32m 3817\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_check_indexing_error(key)\n", - "\u001b[1;31mKeyError\u001b[0m: 'hardness'" - ] - } - ], - "source": [ - "df4['hardness']" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Do you know why?" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Answer ..." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "In case you were not able to answer the above question, let's look into df4.columns" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "Index([' hardness', ' sp. gr.', ' cleavage'], dtype='object')" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df4.columns" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "You see there are spaces at the beginning of each column name... this happens because that's how people usually type, with commas followed by a space. We could use the skipinitialspace = True from the pd.read_csv() function to avoid this. Let's try it out:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true, - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Index(['hardness', 'sp. gr.', 'cleavage'], dtype='object')\n" + "\u001b[1;31mKeyError\u001b[0m: 0" ] } ], "source": [ - "df4 = pd.read_csv(file_location + 'mineral_properties.txt',sep=',',header=[1], \n", - " skiprows=None, index_col=0, skipinitialspace=True)\n", - "print(df4.columns)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, - "source": [ - "Ok, much better!" + "df3_cleaned.at[0, 'hardness']" ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, "source": [ - "## 6.5 Statistics with pandas\n", - "\n", - "Recall some functions such as np.mean() and np.max(); these functions can be used to calculate a row's or column's statistics. Say you want to know what's the average hardness of the different minerals:" + "Accessing values with `.iat()`, no arrays allowed, no labels allowed only indexes." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 59, "metadata": { "collapsed": true, "nbgrader": { @@ -3038,37 +1919,29 @@ { "data": { "text/plain": [ - "4.666666666666667" + "nan" ] }, - "execution_count": 11, + "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "df4['hardness'].mean()" + "df3_cleaned.iat[1, 2]" ] }, { "attachments": {}, "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false - } - }, + "metadata": {}, "source": [ - "Often we don't know much about the data, and printing all the values is inconvenient. In that case, it's wise to take a look at some of its attributes first.\n", - "\n", - "See the labels of the columns and rows." + "In case you want to know the index number of a column or row:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 60, "metadata": { "collapsed": true, "nbgrader": { @@ -3082,19 +1955,14 @@ "name": "stdout", "output_type": "stream", "text": [ - "Index(['hardness', 'sp. gr.', 'cleavage'], dtype='object')\n", - "----------------------\n", - "Index(['Amphibole', 'Biotite', 'Calcite', 'Dolomite', 'Feldspars', 'Garnet',\n", - " 'Graphite', 'Kyanite', 'Muscovite', 'Pyroxene', 'Quartz',\n", - " 'Sillimanite'],\n", - " dtype='object', name='name')\n" + "2\n", + "3\n" ] } ], "source": [ - "print(df4.columns)\n", - "print('----------------------')\n", - "print(df4.index)" + "print(df3_cleaned.columns.get_loc('new_column')) \n", + "print(df3_cleaned.index.get_loc('Dolomite')) " ] }, { @@ -3102,12 +1970,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "`df4.info` is similar to `print(df4.info)`." + "Since the above lines return the index of a column and row you can use them directly with `.iat()`." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 61, "metadata": { "collapsed": true, "nbgrader": { @@ -3120,29 +1988,16 @@ { "data": { "text/plain": [ - "" + "nan" ] }, - "execution_count": 13, + "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "df4.info" + "df3_cleaned.iat[df3_cleaned.index.get_loc('Dolomite'), df3_cleaned.columns.get_loc('new_column')]" ] }, { @@ -3156,14 +2011,12 @@ } }, "source": [ - "### Deep copying a DataFrame\n", - "\n", - "As you have seen in Notebook 4, shallow copies can be troublesome if you're not aware of it. In pandas, it's the same story.

To make a deep copy use the DataFrame.copy(deep=True) function." + "Selecting multiple columns:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 62, "metadata": { "collapsed": true, "nbgrader": { @@ -3172,30 +2025,108 @@ "solution": false } }, - "outputs": [], - "source": [ - "df_deep = df4.copy(deep=True)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": { - "nbgrader": { - "grade": false, - "locked": true, - "solution": false + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "
hardnesscleavage
Feldspars6.02.64505.5NaN
Garnet7.03.9Fracture
Graphite1.52.3One
Kyanite64.0112.75One
hardnesssp. gr.new_columncleavage
Amphibole5.502.800Two5.52.8NaNNaN
Biotite2.753.0003.0NaNOne
Calcite3.002.720Three3.02.72NaNNaN
Dolomite3.002.850Three3.02.85NaNNaN
Feldspars6.006.02.645TwoNaNNaN
Garnet7.003.9007.03.9NaNFracture
Graphite1.502.3001.52.3NaNOne
Kyanite6.004.010One
Muscovite2.252.930One
Pyroxene5.503.325Two
Quartz7.002.650Fracture
Sillimanite6.503.23064.01NaNOne
\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
hardnessnew_column
name
Amphibole5.5NaN
Biotite2.75NaN
Calcite3.0NaN
Dolomite3.0NaN
Feldspars6.0NaN
Garnet7.0NaN
Graphite1.5NaN
Kyanite6NaN
\n", + "
" + ], + "text/plain": [ + " hardness new_column\n", + "name \n", + "Amphibole 5.5 NaN\n", + "Biotite 2.75 NaN\n", + "Calcite 3.0 NaN\n", + "Dolomite 3.0 NaN\n", + "Feldspars 6.0 NaN\n", + "Garnet 7.0 NaN\n", + "Graphite 1.5 NaN\n", + "Kyanite 6 NaN" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" } - }, + ], "source": [ - "Now, altering df_deep will not alter df4; and vice-versa." + "df3_cleaned[['hardness','new_column']]" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { - "id": "PQbf2l1kAOWu", "nbgrader": { "grade": false, "locked": true, @@ -3203,36 +2134,127 @@ } }, "source": [ - "## Additional study material:\n", - "\n", - "* [Official pandas Documentation (Series)](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.html#pandas.Series)\n", - "* [Official pandas Documentation (DataFrame)](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html#pandas.DataFrame)\n", - "* [Note on processing speed](https://ggbaker.ca/732/content/pandas-speed.html)\n", - "* [Real Python](https://realpython.com/pandas-python-explore-dataset/)\n" + "Finally, removing a column by making a copy and re-assigning the original variable as its copy. (Alternative to inplace=True)" ] }, { - "attachments": {}, - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 63, "metadata": { - "id": "zoaTN8gZB_H4", + "collapsed": true, "nbgrader": { "grade": false, "locked": true, "solution": false } }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
hardnesssp. gr.cleavage
name
Amphibole5.52.8NaN
Biotite2.753.0One
Calcite3.02.72NaN
Dolomite3.02.85NaN
Feldspars6.02.645NaN
Garnet7.03.9Fracture
Graphite1.52.3One
Kyanite64.01One
\n", + "
" + ], + "text/plain": [ + " hardness sp. gr. cleavage\n", + "name \n", + "Amphibole 5.5 2.8 NaN\n", + "Biotite 2.75 3.0 One\n", + "Calcite 3.0 2.72 NaN\n", + "Dolomite 3.0 2.85 NaN\n", + "Feldspars 6.0 2.645 NaN\n", + "Garnet 7.0 3.9 Fracture\n", + "Graphite 1.5 2.3 One\n", + "Kyanite 6 4.01 One" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "

After this Notebook you should be able to:

\n", - "\n", - "\n", - "- understand Series and DataFrames\n", - "- concatenate DataFrames\n", - "- work with different labels of a DataFrame\n", - "- drop unwanted rows and columns\n", - "- access and modify values within your DataFrame\n", - "- import data into a pandas DataFrame\n", - "- manipulate a DataFrame in several important ways" + "df3_cleaned = df3_cleaned.drop('new_column', axis=1)\n", + "df3_cleaned" ] } ], diff --git a/book/pandas/intro.md b/book/pandas/intro.md new file mode 100644 index 0000000..ca4095d --- /dev/null +++ b/book/pandas/intro.md @@ -0,0 +1,5 @@ +# Pandas + +This chapter .. +% a short overview for this chapter + diff --git a/book/pandas/introduction.ipynb b/book/pandas/introduction.ipynb new file mode 100644 index 0000000..c39a54d --- /dev/null +++ b/book/pandas/introduction.ipynb @@ -0,0 +1,52 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "fHmKWsUSKuj4", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "## Introduction \n", + "\n", + "With the standard Python functions and the numpy library, you already have access to powerful tools to process data. However, you'll find that organizing data using them might still be confusing and messy... so let us introduce you to pandas: a Python library specialized in data organization. Its functions are simple to use, and they achieve a lot. Furthermore, pandas was built on top of the numpy library, using some of their functions and data structures. This makes pandas fast. The pandas library is often used in Data Science and Machine Learning to organize data that are used as input in other functions, of other libraries. For example, you store and organize an Excel file using pandas data structures, apply statistical analysis using SciPy, and then plot the result using matplotlib.

In this section, we'll introduce you to the basic pandas data structures: the Series and DataFrame objects; and how to store data in them. In pandas, a Series represents a list, and DataFrame represents a table.\n" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "Copy of Python_2_3.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 [3.7]", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + }, + "vscode": { + "interpreter": { + "hash": "1fe2f2b718b1108b9c4176932db8a0ead471245140baaa21ea96a4066683e6b2" + } + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/book/06/Theory/mineral_properties.txt b/book/pandas/mineral_properties.txt similarity index 100% rename from book/06/Theory/mineral_properties.txt rename to book/pandas/mineral_properties.txt diff --git a/book/pandas/nutshell.md b/book/pandas/nutshell.md new file mode 100644 index 0000000..ec3ab6b --- /dev/null +++ b/book/pandas/nutshell.md @@ -0,0 +1,3 @@ +# Pandas: in a Nutshell + +Nutshell. \ No newline at end of file diff --git a/book/pandas/nutshell/attributes.ipynb b/book/pandas/nutshell/attributes.ipynb new file mode 100644 index 0000000..898936b --- /dev/null +++ b/book/pandas/nutshell/attributes.ipynb @@ -0,0 +1,56 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Importing data into DataFrames and exploring its attributes\n", + "\n", + "You can also make a `dataframes` from any csv file (excel files, delimited text files, etc). The table below summarizes the important functions you need to remember when applying the `pd.read_csv()` command.\n", + "\n", + "| Aspect | Description | Function |\n", + "|--------------|---------------------------------------------------|------------------------------------|\n", + "| File Path | Specify the path or filename of the CSV file | pd.read_csv('file_path.csv') |\n", + "| Delimiter | Define the delimiter used in the CSV file | pd.read_csv('file.csv', delimiter=',') |\n", + "| Header | Specify whether the CSV file has a header row | pd.read_csv('file.csv', header=0) |\n", + "| Columns | Select specific columns from the CSV file | pd.read_csv('file.csv', usecols=['col1', 'col2']) |\n", + "| Index Column | Set a specific column as the index of the DataFrame | pd.read_csv('file.csv', index_col='column') |\n", + "| Data Types | Specify data types for columns in the DataFrame | pd.read_csv('file.csv', dtype={'col1': int, 'col2': float}) |\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```{note}\n", + ":class: Collapsed \n", + "The excel file needs to be in the same place in the folder that the python file is at for this to work!\n", + "```" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/pandas/nutshell/frame.ipynb b/book/pandas/nutshell/frame.ipynb new file mode 100644 index 0000000..0b3474d --- /dev/null +++ b/book/pandas/nutshell/frame.ipynb @@ -0,0 +1,257 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ``DataFrame``\n", + "In the example below, we start by creating a dictionary data that contains information about names, ages, and cities. We then use this dictionary to create a `dataframe` df using pd.DataFrame( ). " + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Original DataFrame:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NameAgeCity
0John25London
1Alice28Paris
2Bob22Berlin
\n", + "
" + ], + "text/plain": [ + " Name Age City\n", + "0 John 25 London\n", + "1 Alice 28 Paris\n", + "2 Bob 22 Berlin" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data2 = {'Name': ['John', 'Alice', 'Bob'],\n", + " 'Age': [25, 28, 22],\n", + " 'City': ['London', 'Paris', 'Berlin']}\n", + "\n", + "df = pd.DataFrame(data2)\n", + "\n", + "print(\"Original DataFrame:\")\n", + "df " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can then use the `loc[ ]` and `loc[ ]` functions to locate specific data from your `dataframe`. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Using iloc[]:\n", + "Name John\n", + "Age 25\n", + "City London\n", + "Name: 0, dtype: object\n", + " Name Age City\n", + "1 Alice 28 Paris\n", + "2 Bob 22 Berlin\n", + "25\n", + "\n", + "Using loc[]:\n", + "Name John\n", + "Age 25\n", + "City London\n", + "Name: 0, dtype: object\n", + " Name Age City\n", + "1 Alice 28 Paris\n", + "2 Bob 22 Berlin\n", + "25\n" + ] + } + ], + "source": [ + "print(\"\\nUsing iloc[]:\")\n", + "print(df.iloc[0]) \n", + "print(df.iloc[1:3]) \n", + "print(df.iloc[0, 1]) \n", + "\n", + "print(\"\\nUsing loc[]:\")\n", + "print(df.loc[0]) \n", + "print(df.loc[1:2]) \n", + "print(df.loc[0, 'Age']) " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We then add and remove some data from the created `dataframe`. You can remove rows and columns from a datafram by using the Yourdataframename.drop() function." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Updated DataFrame:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NameCitySalary
0JohnNew York5000
2BobBerlin4500
\n", + "
" + ], + "text/plain": [ + " Name City Salary\n", + "0 John New York 5000\n", + "2 Bob Berlin 4500" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.loc[0, 'City'] = 'New York'\n", + "df['Salary'] = [5000, 6000, 4500]\n", + "\n", + "df = df.drop(1) \n", + "df = df.drop('Age', axis=1) \n", + "\n", + "print(\"\\nUpdated DataFrame:\")\n", + "df" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/pandas/nutshell/introduction.ipynb b/book/pandas/nutshell/introduction.ipynb new file mode 100644 index 0000000..d572a9e --- /dev/null +++ b/book/pandas/nutshell/introduction.ipynb @@ -0,0 +1,40 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## Introduction \n", + "\n", + "`Pandas` offers a wide range of functions to read data from various sources, such as CSV files, Excel files, SQL databases, and more. You can perform operations like filtering, sorting, grouping, merging, reshaping, and aggregating data using Pandas. It also integrates well with other popular libraries in the Python ecosystem, such as `numpy` and `matplotlib`.\n", + "\n", + "It provides powerful data structures and functions to efficiently work with structured data, such as tabular data, time series, and more. With `pandas`, you can easily load, manipulate, analyze, and visualize data for tasks like data cleaning, exploration, transformation, and modeling.\n", + "\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/pandas/nutshell/series.ipynb b/book/pandas/nutshell/series.ipynb new file mode 100644 index 0000000..d03926f --- /dev/null +++ b/book/pandas/nutshell/series.ipynb @@ -0,0 +1,171 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To start using `pandas`, you need to import it into your Python script or Jupyter Notebook. The standard way to import Pandas is as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The two primary data structures provided by Pandas are:\n", + "\n", + "1. `Series`: A Series in Pandas is a one-dimensional labeled array that can hold any data type. It is similar to a column in a spreadsheet or a single column of a SQL table. Each element in a Series is associated with a unique label called an `index`.\n", + "\n", + "2. `DataFrame`: A two-dimensional labeled data structure with columns of potentially different types. It is similar to a spreadsheet or a SQL table." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ``Series``\n", + "\n", + "Here is an example where we create a list of data containing some numbers and an index list with corresponding labels. We then use these lists to create a Series using pd.Series() function. " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Original series:\n", + "A 10\n", + "B 20\n", + "C 30\n", + "D 40\n", + "E 50\n", + "dtype: int64\n" + ] + } + ], + "source": [ + "data = [10, 20, 30, 40, 50]\n", + "index = ['A', 'B', 'C', 'D', 'E']\n", + "\n", + "s = pd.Series(data, index=index)\n", + "print(\"\\nOriginal series:\")\n", + "print (s)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We also change the created labels without having any effect on the data as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Updated series:\n", + "X 10\n", + "Y 20\n", + "Zebra 30\n", + "W 40\n", + "V 50\n", + "dtype: int64\n" + ] + } + ], + "source": [ + "s.index = ['X', 'Y', 'Zebra', 'W', 'V']\n", + "print(\"\\nUpdated series:\")\n", + "print(s)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Two helpful functions when working with pandas are the `iloc[ ]` and `loc[ ]` functions. For more information see the table below:" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| Function | Description | Example |\n", + "|----------|---------------------------------------------|----------------------------------------------------|\n", + "| `iloc[ ]` | Integer-based indexing and selection | s.iloc[0] accesses the first row of a DataFrame |\n", + "| | | s.iloc[2:4] accesses a slice of rows in a DataFrame |\n", + "| `loc[ ]` | Label-based indexing and selection | s.loc['X'] accesses a row labeled 'A' in a DataFrame |\n", + "| | | s.loc[['X', 'W']] accesses multiple rows in a DataFrame |\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Zebra 30\n", + "W 40\n", + "dtype: int64" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s.iloc[2:4] " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/pandas/series.ipynb b/book/pandas/series.ipynb new file mode 100644 index 0000000..e76c246 --- /dev/null +++ b/book/pandas/series.ipynb @@ -0,0 +1,399 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "import pandas as pd \n", + "import numpy as np" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "## ``Series``\n", + "\n", + "We start with pandas Series, since a DataFrame is made out of Series; retrieving a row or a column from a DataFrame results in a Series. A Series object is a numpy ndarray used to hold one-dimensional data, like a list. We create a Series object using its constructor pd.Series(). It can be called by using a list that you want to convert into a pandas series. Unlike numpy arrays, a Series may hold data of different types.\n", + "\n", + "First we create a list containing elements of various types. Then we construct a `Series` and a `numpy.array` using our list. Finally we compare the type of each element in `my_series` and `my_nparray`." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "----type of each element----\n", + "my_series element #0 => \n", + "my_nparray element #0 => \n", + "\n", + "----type of each element----\n", + "my_series element #1 => \n", + "my_nparray element #1 => \n", + "\n", + "----type of each element----\n", + "my_series element #2 => \n", + "my_nparray element #2 => \n", + "\n", + "----type of each element----\n", + "my_series element #3 => \n", + "my_nparray element #3 => \n", + "\n" + ] + } + ], + "source": [ + "my_list = ['begin', 2, 3/4, \"end\"]\n", + "\n", + "my_series = pd.Series(data=my_list)\n", + "my_nparray = np.array(my_list)\n", + "\n", + "for i in range(len(my_list)):\n", + " print('----type of each element----')\n", + " print(f'my_series element #{i} => {type(my_series[i])}')\n", + " print(f'my_nparray element #{i} => {type(my_nparray[i])}\\n')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "As expected, the numpy array changed all elements to one type; in this case, strings. As mentioned in Section 5.1, in Notebook 5, a numpy array cannot hold data of different types. Note that a pandas series is, by default, printed more elaborately." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 begin\n", + "1 2\n", + "2 0.75\n", + "3 end\n", + "dtype: object\n", + "-----------------\n", + "['begin' '2' '0.75' 'end']\n" + ] + } + ], + "source": [ + "print(my_series)\n", + "print('-----------------')\n", + "print(my_nparray)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "The values of a series can be accessed and sliced using the **``iloc()``** function: " + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1 2\n", + "2 0.75\n", + "3 end\n", + "dtype: object" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "my_series.iloc[1:]" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2 0.75\n", + "3 end\n", + "dtype: object" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "my_series.iloc[[2,len(my_series)-1]]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### Labeling ``Series``\n", + "\n", + "So far we have referred to values within a list or array using indexing, but that might be confusing. With pandas Series, you can refer to your values by labeling their indices. Labels allow you to access the values in a more informative way, similar to dictionaries; depicted in Section 2.3, in Notebook 2.\n", + "\n", + "We create the indices of the same size as the list since we want to construct our Series object with and use the index option in the Series constructor. Note that our entries can be called both ways" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\gui-win10\\AppData\\Local\\Temp\\ipykernel_24848\\1771852785.py:4: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + " print(my_labeled_Series[0] == my_labeled_Series[\"My first entry\"])\n" + ] + } + ], + "source": [ + "my_index_labels = [\"My first entry\", \"1\",\"2\",\"END\"]\n", + "my_labeled_Series = pd.Series(data=my_list, index=my_index_labels)\n", + "\n", + "print(my_labeled_Series[0] == my_labeled_Series[\"My first entry\"])" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "pandas can automatically create labels of indices if we construct a Series using a dictionary with labeled entries." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + }, + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a list [420, 10]\n", + "a float 126.666667\n", + "a list of strings [first word, Second Word, 3rd w0rd]\n", + "dtype: object\n" + ] + } + ], + "source": [ + "my_dictionary = {\"a list\": [420, 10],\"a float\": 380/3, \n", + " \"a list of strings\": [\"first word\", \"Second Word\", \"3rd w0rd\"] }\n", + "my_Series = pd.Series(my_dictionary)\n", + "print(my_Series)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can access an element within the list labeled `\"a list of strings\"` by using its label followed by the desired index" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'Second Word'" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "my_Series[\"a list of strings\"][1]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "::: {warning}\n", + "When using pandas, it's a good idea to try and avoid for loops or iterative solutions; pandas usually has a faster solution than iterating through its elements.\n", + "::: " + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "Copy of Python_2_3.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 [3.7]", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + }, + "vscode": { + "interpreter": { + "hash": "1fe2f2b718b1108b9c4176932db8a0ead471245140baaa21ea96a4066683e6b2" + } + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/book/pandas/statistics.ipynb b/book/pandas/statistics.ipynb new file mode 100644 index 0000000..6166b3f --- /dev/null +++ b/book/pandas/statistics.ipynb @@ -0,0 +1,263 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "## Statistics with pandas\n", + "\n", + "Recall some functions such as np.mean() and np.max(); these functions can be used to calculate a row's or column's statistics. Say you want to know what's the average hardness of the different minerals:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "4.666666666666667" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df4['hardness'].mean()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Often we don't know much about the data, and printing all the values is inconvenient. In that case, it's wise to take a look at some of its attributes first.\n", + "\n", + "See the labels of the columns and rows." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Index(['hardness', 'sp. gr.', 'cleavage'], dtype='object')\n", + "----------------------\n", + "Index(['Amphibole', 'Biotite', 'Calcite', 'Dolomite', 'Feldspars', 'Garnet',\n", + " 'Graphite', 'Kyanite', 'Muscovite', 'Pyroxene', 'Quartz',\n", + " 'Sillimanite'],\n", + " dtype='object', name='name')\n" + ] + } + ], + "source": [ + "print(df4.columns)\n", + "print('----------------------')\n", + "print(df4.index)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`df4.info` is similar to `print(df4.info)`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df4.info" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "### Deep copying a DataFrame\n", + "\n", + "As you have seen in Notebook 4, shallow copies can be troublesome if you're not aware of it. In pandas, it's the same story.

To make a deep copy use the DataFrame.copy(deep=True) function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true, + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "outputs": [], + "source": [ + "df_deep = df4.copy(deep=True)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "Now, altering df_deep will not alter df4; and vice-versa." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "PQbf2l1kAOWu", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "## Additional study material:\n", + "\n", + "* [Official pandas Documentation (Series)](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.html#pandas.Series)\n", + "* [Official pandas Documentation (DataFrame)](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html#pandas.DataFrame)\n", + "* [Note on processing speed](https://ggbaker.ca/732/content/pandas-speed.html)\n", + "* [Real Python](https://realpython.com/pandas-python-explore-dataset/)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "zoaTN8gZB_H4", + "nbgrader": { + "grade": false, + "locked": true, + "solution": false + } + }, + "source": [ + "

After this Notebook you should be able to:

\n", + "\n", + "\n", + "- understand Series and DataFrames\n", + "- concatenate DataFrames\n", + "- work with different labels of a DataFrame\n", + "- drop unwanted rows and columns\n", + "- access and modify values within your DataFrame\n", + "- import data into a pandas DataFrame\n", + "- manipulate a DataFrame in several important ways" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [], + "name": "Copy of Python_2_3.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 [3.7]", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + }, + "vscode": { + "interpreter": { + "hash": "1fe2f2b718b1108b9c4176932db8a0ead471245140baaa21ea96a4066683e6b2" + } + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/book/python.md b/book/python.md new file mode 100644 index 0000000..729f684 --- /dev/null +++ b/book/python.md @@ -0,0 +1,60 @@ +# Programming and Python + +## Why do you need Python? + +Python is a computer programming language that is widely used in both academia and industries related to Civil Engineering, Environmental Engineering and Applied Earth Sciences. Being skilled in Python will help you on multiple occasions, including in your master courses. + +## What can computers do for us? +As an engineer or scientist, you will deal with units of information which are called data. The most important tasks that a computer can do for us are: + +1. Reading data +2. Processing data +3. Visualizing data + +These are tasks that require many repetitions and high precision. + +_1. Reading data_ +Reading data means the computer acquires data from a source and places it into its volatile memory for processing. Volatile memory keeps the data stored until the power supply is interrupted. The way data is stored in a computer determines how the computer will be able to use it. + +_2. Processing data_ +Data processing is the manipulation of the stored data in a system. After processing data by performing transformations, calculations, and more, you get an output; results. + +_3. Visualizing data_ +We map data (original or found) to graphic elements to communicate clearly and efficiently the information contained in the data. A graphic element is an element of a chart, such as a line or a point in the chart. + +## What is programming? + +Programming is giving your computer a list of instructions for computations in a language it can understand. In your case, this language is Python. A computation is a series of arithmetical ("math") and non-arithmetical ("non-math") steps that transform input to output (result). +There are five different kinds of instructions for computations you use. By ordering and combining them, the computer can achieve results that fulfill the three tasks described earlier. The five kinds of instructions are: + +input: + Insert data from a file, the network, other devices, or simply by typing it in. + +output: + Display data on the screen, save them in a file, send it over the network, etc. + +math: + Perform basic mathematical operations like addition and multiplication. + +conditional execution: + Check for certain conditions before further instruction. + +repetition: + Perform instructions repeatedly, usually with some variation. + + +## Introduction to Python + +The features of Python are what make it so popular. From the definition available on the corresponding Wiki page: "Python is an interpreted high-level general-purpose programming language. Its design philosophy emphasizes code readability with its use of significant indentation. Its language constructs, as well as its object-oriented approach aim to help programmers write clear, logical code for small and large-scale projects.". Quite a simple, yet concise description due to the meaning hidden behind each buzzword: + +
    +
  • Interpreted means that there is an interpreter, a software tool, which reads and performs instructions written in Python. If your laptop, phone, or refrigerator has the interpreter, it can run most of the Python scripts! +
  • High-level means that the programming language operates with abstract and more easily understandable concepts. In other words, you don't have to write or understand, code related to the hardware part of your machine (like binary code or assembly). +
  • General-purpose means that the amount of Python application fields are endless. You can write Python scripts to manage and automate some primitive tasks for yourself, you can use it for data science, create your own machine / deep learning project, write your personal web application or even develop a game. +
  • Programming language means a set of specific predefined semantics, instructions, and syntax rules, which are used for writing necessary instructions. It is strictly defined, meaning that 99.99% of all errors in the code are made by the coder, not by the computer. +
+ +Python scripts run with the help of a Python interpreter, but they can be written by using different software tools. Just like as you write your essay (you can type it in Word, Google Docs, Overleaf, or even on plain paper) you can write your Python code with different editors. You could use the default notepad, notepad++, find a proper website with an inbuilt code editor & interpreter (IDEone, for example), or use specialized Python code editors (Spyder, PyCharm, Visual Studio, etc). In all cases you will produce a set of instructions, which are stored in a file with the *.py extension and the interpreter will run it completely (from top to bottom). + +For this course we will use a slightly different approach to developing a Python script: IPython and Jupyter Notebooks. Think of these as two freely-available tools that add extra functionality to the basic Python programming language. As an example, imagine the camera built into your phone: on it's own it can take pictures, but there are many apps that add filters or sharing via social media that make the impact of your photos much more powerful. This is exactly what IPython and Jupyter Notebooks do for Python, and why they are such important tools in the toolbox of modern engineers. The next Chapter will introduce you to your Python Toolbox for this course! + diff --git a/book/sympy/expressions.ipynb b/book/sympy/expressions.ipynb new file mode 100644 index 0000000..9808fc5 --- /dev/null +++ b/book/sympy/expressions.ipynb @@ -0,0 +1,621 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluating expressions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "SymPy expressions can be evaluated numerically in several ways. Let's say you have an expression defined as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/latex": [ + "$\\displaystyle a \\sin{\\left(\\omega \\right)} + \\frac{\\left|{f{\\left(t \\right)}}\\right|}{\\sqrt{b}}$" + ], + "text/plain": [ + " │f(t)│\n", + "a⋅sin(ω) + ──────\n", + " √b " + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a, omega, b, t = sym.symbols('a, omega, b, t')\n", + "f = sym.Function('f')\n", + "expr3 = a*sym.sin(omega) + sym.Abs(f(t))/sym.sqrt(b)\n", + "expr3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And you have some values for which you want to evaluate of the expression:" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [], + "source": [ + "values = {omega: sym.pi/4, a: 2, f(t): -12, b: 25}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can evalute the expression using `sym.subs`:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAEwAAAArCAYAAADSZm7JAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEL0lEQVRoBe2a7VHcMBCGj0wKYEgH0AEkHVw6gBagg2Tyj39M6ABSQQIdQDoIdAAlEDogz2Mk4Q/Z+O5gcj6jGbHSamVr31utdmXWHh4eJmMph4eH2+h6Rt2hfV/XG94mvK+B/xF6Zx/+deBN3sfGqlKUXUe3H1SVFwRBaZQA1gn0cxyk/Z32lTzqpfx3cXBVKYreU/eoB+j4s0NPwVEmFeZobVqiVlmUlQcsKtqDTpG5ASQtsly0rHX4hWW+AfYEjcDcAkzDtwWRAsiV92FPeHS3AGqvRcKDYsJ44fjfLKwFpQCSYLkV48m5+k6/A48+Qzr7c6zrOAq/WVhEokYB6QSWPq2yVRfyYTxMk72qvau1i/xa6+ASDbDOfZazAU0xWVzeQoDxEGMXo+YUCccHD5Wiyy5r34Imy6KtH5tAb+fekkyunB5DBai87qDTJ2hy8mFcEM0UFkqNvjFfCxtS+RAWuwGtxFuApBXp5C9p67/KZQqvcPxzbcnw8E1okV+Vn7yMbdYZU5tpWN8ZvFvaF9DTwLuACpr+q16Sy1mb57aCl/gL+NIEGG1fFk05m+nXVzHE/syAAYwpwm/oTlQ4gJXL9L8gkzL9KD9kOo/T128d1ZTulenX5nR2+RH0G7nt0TnvtQdnAgwFtC4VOa8tTN/wbKZfm/Nc13dZl6rMBBgrbzsZe2X6S6X5nItJpyRWY6zhZVty5Jln7jK+VefDS0FebWzlYrUCMBTWOWs9HrXJmZeVDzL1+KQsUmkjL1ib1HhyVsaH2nkXFDMWsW6Hfk6fA8ZS1p4TqPEamX5tfJDdFFYAhg72L9XrjMoWo+9p5TVtL8CQ0xINbBvJK/xKCbIxoCyPGY1bipTksZn+XjOvssY08sqNBJjvCYsXHJNPt2dRaN/QyH6aCiKJIOt8Y6+FFGK+PlXQe/1IaQGlBnNf/BticvrhPcZTKqzfKb6ghIVrdfdBppUE2dZMv3XiKw2wnhe/TqqEFbxAq/KU3KcdYyAPg3qg2lAReZ18Z6bfmDRARt3CVEEr06cImgD+gXZaF+Oehs9m+sgMvjQAQ3mvN8zOY5jRxxf1yvQHjxYKNAALSrkFtRjvtJPzD2MNgkwjmG0ILRmDNRtCpWsbl0dfN+TVdKvOWcCYoJP3Yf8z6NQNdLoCxhcp3rgIUATNtiUbuD8OTSaVsCIyx0ABy1DJWE+gtCgvFI7gd/5IWQtj4hjKXMFvJawYA0qL6vgG2IwIjnlLTvBXRY4MZn5NMpbUh8VDIAvlmC1MZ/8LgI6pRgNW/9twmkUqMEd7SuZAAawiAIe2xpVjtrAcZoYX3pC4PbNllIBpSdSuf6KJQWwDtFECBgp+aM6BUlxaAmar4x8rYKeAkvNTOvyuj0Cj/Q9Ev9JXPujQ90OQpfN2ZrSnJADp2OPlglvxzj78zlzyH4sLenMo1kg5AAAAAElFTkSuQmCC", + "text/latex": [ + "$\\displaystyle \\sqrt{2} + \\frac{12}{5}$" + ], + "text/plain": [ + "√2 + 12/5" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expr3.subs(values)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice how the square root and fraction do not automatically reduce to their decimal equivalents. To do so, you must use the `evalf()` method:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/latex": [ + "$\\displaystyle 3.8142135623731$" + ], + "text/plain": [ + "3.81421356237310" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expr3.subs(values).evalf()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To obtain machine precision floating point numbers directly and with more flexibility, it is better to use the `sym.lambdify()` function to convert the expression to a Python function. When using `sym.lambdify()`, all symbols and functions should be converted to numbers, so first identify what symbols and functions make up the expression." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [], + "source": [ + "eval_expr3 = sym.lambdify((omega, a, f(t), b), expr3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`sym.lambdify()` generates a Python function and, in this case, we store that function in the variable `eval_expr3`. You can see what the inputs and outputs of the function are with `help()`:" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on function _lambdifygenerated:\n", + "\n", + "_lambdifygenerated(omega, a, _Dummy_38, b)\n", + " Created with lambdify. Signature:\n", + " \n", + " func(omega, a, f, b)\n", + " \n", + " Expression:\n", + " \n", + " a*sin(omega) + Abs(f(t))/sqrt(b)\n", + " \n", + " Source code:\n", + " \n", + " def _lambdifygenerated(omega, a, _Dummy_38, b):\n", + " return a*sin(omega) + abs(_Dummy_38)/sqrt(b)\n", + " \n", + " \n", + " Imported modules:\n", + "\n" + ] + } + ], + "source": [ + "help(eval_expr3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This function operates on and returns floating point values. However, it also support arrays of floats. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([3.81365036, 3.76704398, 3.72305144])" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "eval_expr3(3.14/4, 2, -12, [25, 26, 27])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ":::{card} Test yourself!\n", + "\n", + "Create a symbolic expression representing [Newton's Law of Universal Gravitation](https://en.wikipedia.org/wiki/Newton's_law_of_universal_gravitation). Use `sym.lambdify()` to evaluate the expression for two mass of 5.972E24 kg and 80 kg at a distance of 6371 km apart to find the gravitational force in Newtons. $G$ equals $6.67430\\cdot 10 ^{-11}$\n", + "\n", + "All variables have been defined with:\n", + "```python\n", + "G, m_1, m_2, r = sym.symbols('G, m_1, m_2, r')\n", + "```\n", + "\n", + "Click {fa}`rocket` --> {guilabel}`Live Code` to activate live coding!\n", + ":::\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "tags": [ + "thebe-remove-input-init" + ] + }, + "outputs": [], + "source": [ + "from math import isclose\n", + "G, m_1, m_2, r = sym.symbols('G, m_1, m_2, r')\n", + "F = G*m_1*m_2/r**2\n", + "eval_F = sym.lambdify((G, m_1, m_2, r), F)\n", + "answer_correct = eval_F(6.67430E-11, 5.972E24, 80, 6371E3)\n", + "answer = 0\n", + "\n", + "tolerance = 0.001\n", + "check_float = lambda a, b: isclose(a, b, rel_tol=0, abs_tol=tolerance)" + ] + }, + { + "cell_type": "code", + "execution_count": 104, + "metadata": {}, + "outputs": [], + "source": [ + "answer = " + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "tags": [ + "thebe-remove-input-init" + ] + }, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "040de5c97c9c4ee6a710f9315e5f3c43", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Button(description='Check answer', style=ButtonStyle())" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "86269cba2b8947e6a04c4a452678f51a", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "check_answer(\"answer\",answer_correct, check_float)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Some examples\n", + "\n", + "SymPy has many possibilities. Check out the [documentation](https://docs.sympy.org/latest/index.html) if you're curious. Some examples are shown below." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Take the derivative of $\\sin\\left({x}\\right) e ^ x$" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/latex": [ + "$\\displaystyle e^{x} \\sin{\\left(x \\right)} + e^{x} \\cos{\\left(x \\right)}$" + ], + "text/plain": [ + " x x \n", + "ℯ ⋅sin(x) + ℯ ⋅cos(x)" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sym.diff(sym.sin(x)*sym.exp(x),x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Compute $\\int(e^x\\sin{(x)} + e^x\\cos{(x)})dx$." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAE8AAAAVCAYAAAAHIbMXAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAD6ElEQVRYCeWY61EcMQyA95gUQKADrgMgHUAHPCoAOgjDP/5loANIB0AH0AGPDkIHgeuAfJ9j7/g2u8vt7sEwRDM6+SHJsiTL3hu9vLwUXeD4+Ph75B9DT8AtMLSZe4xzH5Jg30pfG+tkF7rsEgU67gp6Cl0Cz2J7nfYq+GEh2j7ERh2fEifss5PzkJigIGXXIv3r6K09xq9iuzNBVsOewf3OwjMIoNfTsQwdYuONS+U2dnIegueZrRu0gzGMP2TjfZorCBmMtT7CbTLYpt4j6GEb3yxz6PDEHUSdRSfnpQUQNv3LLKTv5nsD8kb1K/Sgt5JmQevyWfN05xl1qXN25+kg8DkutQtNx9eheUR1EnXPm+xgd35iBumPutS5+GVWTTA/ghegRTPUuthWxWDnzWpHFz7ss9blQe4i3sarzp0p57FYqA9M/I6SPkEOGQ9ZAc2PVSigka+VIOcxt0aqxzWEXcbXQI/8JSi9ob8NLaDK/AQdvwDTs4hm8Q28hcca1AabTDbaiby2pEtKnXug63myBNeou2TUuVk6DyY353neph0uAKgbOAJ7ZxY6NPAE6kZKoB8CATWKOvG+nKRBXxsc/wVdAldpB2dBtese6rOpLbN8QrXVO+1KdniiDJYOM2FSbatznjZtLPBTwKi3PYoqy29OHRqOKLQvuIF19KaMS3qqm3pKExWqczaQLzeR2ah9beCatXrRYcaFwh8VTKAe81QfDVg+H9kCUedKyry0kUWUpofgMgzX9BvTPtfW1FYedDHfceoyGOmh3SRWHb+rDsR+NSBVNh2gU+rgDnvyrPWZ9MBY4IeG8lEnyJhy5YVhBLtuqEFv7bCGHYFG1mia4edgXkMZfj9g7YfKajv0f1TGmrohKOHYRo7bJs4h4xhpSSig1pExOKKr0/ZpW7veEsz417KzwA6TR768NHgKm2Qdf0rOMw09pv8ACsyWIaCD0o0W9KDTuqKh1sO3BPcVgpcvolNAS1KqmQazfPRHXr9KJrlc1jbzHpPzPEpJUeCJC1gLq+kd5jv+aEg1ivar9bTK4zIa2he03SdIFdyr+BTtMkNLYMy5tpMY6uMo/SWFgBeF2ec1LBid195RfzlbfqMhPlPS21Fu1wmXEfNmpvUwBU+HpvdWqpNmgOPWJDPJTJE/jKOjtrhH3ZdQ36sl0DdIJkzYK/1T0BOmnT6ZdGp5hOlPAXPKHZTOm5r9RJ240fLtOnRr6DN4Bn6cju1QnR9Z3gwzU+cFfjCoc/Y/Bua18nvrIUO8nPxTw4wZBFGHusJD+n/IPB1mTfTyGwrqKLP409e85K2YNVvQXpcgcl6oU9/SfwDp3X1UGYYoPQAAAABJRU5ErkJggg==", + "text/latex": [ + "$\\displaystyle e^{x} \\sin{\\left(x \\right)}$" + ], + "text/plain": [ + " x \n", + "ℯ ⋅sin(x)" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sym.integrate(sym.exp(x)*sym.sin(x) + sym.exp(x)*sym.cos(x), x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Compute $\\int_{-\\infty}^\\infty \\sin{(x^2)}dx$." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAADoAAAAuCAYAAAB5/AqlAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAER0lEQVRoBe2a7VHcMBCG7zIpgKSEowM+KgjpACYdcB2EyS/4l0k6ACpIQgehgwQ6gBIydEDeRyd5ZEu2JVs2zIBmhKTVandf7WrPtlg+Pj4uxpSzs7Mdrf+k+jlVjtYsU3lL8b0tIOibZJzI+JMCsiYTMQqo9eZC7e1kFjYEW503DXLvcBRQSf+iikfnLOjbzd3cwUClaCWFK7XXPkpLd2G8p7l/qoT2aK9LBvlgMUTWYKAYbyu6TZEBgD9X+9GSMAoP3EBTrW2K48loB0fQmwwlFasM3tJgL2I4oNYVozriYUMeVH/59Ny+5EQjKFXOIKASDqCvESUHot3JKDbCL3hyyxrr03P6QQTlLM4GakEcqL2KKALQvebwYKw0NyDGE9CszlgEBbxthCFntPWcyKCjFkWDk4iVF40g6YN+rNq1gRfiW9eAinCoRQ9qu5LGoea3rQG9jXgByflymbh3jc+g9YAggppnH5AUNheefdUfqmR6xgaD1plsXwEVgUc4vHWvuqsaFMtzHkx0E0hCV1r7vZutdTaIIMli8/6oNcfH2aWWY0OeuFZb+zkzZ1REFl7YumPHGgZlrblkg8XLpqA8GtKiEx0Y1lXgwbaqaHyr6ucIfrpwEAXPur4h8McBZeGDxi6Tsou1onnOQrI3Lf97tdVvqi9QdCLoUtWFoD9t+panU6d4cBK2u4Kj/LGhG6COwzKwe+ziytFtyxmr7WxjvhpqLWd9W23lSeQ5mWpLRhBn93elfJMPvOGmWwNqZ90OV8lDhmE45yzYqaZEC2JfbbXe8iCDx8GF5opEkORsSRyR9hO5rogeHIcAqJiIbzLWsRXEekLZhTXjaBE/UUDy4eGAR8Gqisb5rm2UHY+JIEDGfreD41JlXS3wC15lVwAL8L9NI31mr08IARYDmqWWBb1JdMFPBJifEOlKjSAANSPHT1Ka3pRl2xcGKeOdD6MBemQBb1YV/ivZbBAb+059fsfR/YF+KVVB6HqCCVXOAKERpGuPr0TX5QUiCG+mRlCy7lagUkgIEG7N0EgWnsooXeQEdJELqA64umVK2xk10mVA9AmpjOpAChFEIpskglo9GpgxMWHqCGpNRhPjml38s/Ho1MhfDNDl6enpuE/1U7uikPzXM1poI5+NmBdzRl+BPpuYK2RI5yNgIR1GjJ58Vuq45+Y99XkJL3InYxT0/Jkl61qQsTsZvhuVuJPpgWk/jvVyjWfgbcS8VDtRAo93ed8cdSfj5PW1cyUjXqqnupPpw2jm5wLK+2bs244zkhf8ScssZ7QNgcL3TnN8Bp38nzfm8miAVeD4tutn4oCnJOHJgArE2DuZrH14ktCVN7lmIGSD769Z1mcwz+5RgeMbbuudTIbtWayzAhVIPmW23slkWZ7JPBtQgST5dN7JZNqexT7LGRXIlazia7y5hW5YyG128g16Y23ycK6H+iF3MskgUhj/A8zGmJ7B12wmAAAAAElFTkSuQmCC", + "text/latex": [ + "$\\displaystyle \\frac{\\sqrt{2} \\sqrt{\\pi}}{2}$" + ], + "text/plain": [ + "√2⋅√π\n", + "─────\n", + " 2 " + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sym.integrate(sym.sin(x**2), (x, -sym.oo, sym.oo))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Find $\\lim_{x\\to 0}\\frac{\\sin{(x)}}{x}$." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAOCAYAAAASVl2WAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAZElEQVQYGWP8//8/Aww0NDQYAdmrgdgYyP4AEmcBMgSA9GwgfgfEJkCsBMRwAFIAUhkKEgGyy4AUyBQ4YIKzcDBGFUACBj0chKHhJQQLN0ZQZAGDGBRBIOACxKC4OQfE94B4NwDm+hiAOyllRAAAAABJRU5ErkJggg==", + "text/latex": [ + "$\\displaystyle 1$" + ], + "text/plain": [ + "1" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sym.limit(sym.sin(x)/x, x, 0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Solve $x^2 - 2 = 0$." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAGMAAAAlCAYAAABWOlfkAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADa0lEQVRoBe2b4VEbMRCF7UwKIOkg0AGQDpwOYOgAOgiTX/a/TNKB0wJ0ENIB0EHoIIEOkvcxuoss3110trR3ZrQzGsnSWrv3nnb37gzT+Xx+MplMrtR8uVgsFt/8iTJOh4CwXWq382DHN1NHxpkUToPF8tEIAWH/KFPvXhnZK2YiEChkRIBkpVLIsEI6ws7rCJ1BVJRHD2X4Lta49Kexujn0Uvg7WjIE2Be1I13kfQ7wMuy5tb+jTFPulE12hYhU/o6SDJ3aT2qctF2RJP6Ojgydsn0xsK/+ZheYSOnvGGvGpUig1eIuuJo71sJvtUvNj6GeJPN3VGQI3D2BfKz+omLCEbFU/8GbI4XdMac2WATJdlJ/x5amAPlzBbrrmavJYU4gcBqf1MJ3aixbSlJ/R0OGO2Uz9dcBmjN9/unW/SUiYk/z1BhzyeHvaMgQmm13JID+oIsnEpqEVDGEJPfXpGYISF7TP6nvyu8nWj8IUdVc29tkntAnWk9exLXnIP5mJ0MX9lGYcYoe1I7U1sTpLNcWWiakDxGkp+oOq0Wz//SQ/mZNUw40fqSiHbrPTQjxY9bXpoWWOQr3dc/vtGz1b3pofzsjQ86Rj3+o9cnLp/rec+rweu6QqghZSTvS4RevPlGBLjVkZR/NbS1D+/s/Miiajamlz5XrIqkXRMe5ep6uSVmVkGqibOh7EPdWff3MUW2Sstf+g/ibNU0FAHFPjtR5XhdNoSTdQHqnON0D9XVEaAyx1I4cYu6vGRkCjWjgboroqNIehT18yFsDVvoU7PfqayKdEmTyaqQWb+96bpOB9jHx1/etM035ionGnLaZGoRwsbfqO6NC65x8CvaNxmFt4SGxLvwaQ/Kj+nu1qNQn/S7J6m9o2CwyMCyAiAyKOxFBq1KBhq3yXSsQQr0I2wqR2p/PkMyTOcRsJbn9DZ2zjgzsk5Y46dwRAVynSGftQbDrC+irkb5SSVZ/fSdNIwPDAop3T0RHmP9ZTiXUl5Wo2XRjI3+f3RsiMiAkRT5vxFd7k55+NS5uOJnTX98l88jwjWcac3NQF/VMNrJs++LI2FUiYPfFkZHlyBptWsgwAjrGTCEjBiUjnUKGEdAxZgoZMSgZ6RQyjICOMVPIiEHJSKd6AuePAf54Nsv/9HlgpB4Ka94+89JzRf4COMGPgdTQUmMAAAAASUVORK5CYII=", + "text/latex": [ + "$\\displaystyle \\left[ - \\sqrt{2}, \\ \\sqrt{2}\\right]$" + ], + "text/plain": [ + "[-√2, √2]" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sym.solve(sym.Eq(x**2 - 2,0), x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Find the eigenvalues of $\\left[\\begin{smallmatrix}1 & 2\\\\2 & 2\\end{smallmatrix}\\right]$." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/latex": [ + "$\\displaystyle \\left\\{ \\frac{3}{2} - \\frac{\\sqrt{17}}{2} : 1, \\ \\frac{3}{2} + \\frac{\\sqrt{17}}{2} : 1\\right\\}$" + ], + "text/plain": [ + "⎧3 √17 3 √17 ⎫\n", + "⎨─ - ───: 1, ─ + ───: 1⎬\n", + "⎩2 2 2 2 ⎭" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sym.Matrix([[1, 2], [2, 2]]).eigenvals()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Print $\\int_{0}^{\\pi} \\cos^{2}{\\left (x \\right )} dx$ using $\\mathrm{LaTeX}$." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'\\\\int\\\\limits_{0}^{\\\\pi} \\\\cos^{2}{\\\\left(x \\\\right)}\\\\, dx'" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sym.latex(sym.Integral(sym.cos(x)**2, (x, 0, sym.pi)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Gotchas\n", + "Trial and error is an approach for many programmers, but you may want to prevent frequently made mistakes. Take a look at SymPy's documentation on [gotchas](https://docs.sympy.org/latest/tutorials/intro-tutorial/gotchas.html) to accelerate your learning!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## References\n", + "```{bibliography}" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "mude", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/sympy/intro.md b/book/sympy/intro.md new file mode 100644 index 0000000..fbc9057 --- /dev/null +++ b/book/sympy/intro.md @@ -0,0 +1,6 @@ +# SymPy + + +This chapter .. +% a short overview for this chapter + diff --git a/book/sympy/introduction.ipynb b/book/sympy/introduction.ipynb new file mode 100644 index 0000000..a0b82c0 --- /dev/null +++ b/book/sympy/introduction.ipynb @@ -0,0 +1,272 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "tags": [ + "thebe-remove-input-init" + ] + }, + "outputs": [], + "source": [ + "import sympy as sym\n", + "import numpy as np\n", + "from sympy import pi, latex\n", + "from sympy.printing.mathml import mathml\n", + "\n", + "import operator\n", + "import ipywidgets as widgets\n", + "from IPython.display import display, Latex, display_jpeg, Math, Markdown\n", + "sym.init_printing(use_latex=True) \n", + "\n", + "check_equation = lambda eq1, eq2: sym.simplify(eq1-eq2) == 0\n", + "\n", + "def check_answer(variable_name, expected, comparison = operator.eq):\n", + " output = widgets.Output()\n", + " button = widgets.Button(description=\"Check answer\")\n", + " def _inner_check(button):\n", + " with output:\n", + " if comparison(globals()[variable_name], expected):\n", + " output.outputs = [{'name': 'stdout', 'text': 'Correct!',\n", + " 'output_type': 'stream'}]\n", + " else:\n", + " output.outputs = [{'name': 'stdout', 'text': 'Incorrect!',\n", + " 'output_type': 'stream'}]\n", + " button.on_click(_inner_check)\n", + " display(button, output)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# SymPy\n", + "\n", + "SymPy is a Python library for symbolic mathematics. You can use it as a tool to evaluate basic and complicated math operations, whenever they become tedious or error prone.\n", + "\n", + "```{custom_download_link} ./sympy_stripped.ipynb\n", + ":replace_default: \"True\"\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For example, SymPy is able to solve the differential equation $y'' - y = e^t$ for you!" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQEAAAAyCAYAAABcdW5KAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAMSElEQVR4Ae2d7ZXdNBCGb/ZsARAqIHQQoIKQDvioIKEDOPmXf3ugA0gFIekAqICQDoAKCNtBeB9F48i+/pBkW9f3WjrHa1keSTOvRqPRx/Xeefv27aGGikAJBJ4+ffqr6vle99cl6ttyHcLgA/H3QtdXit+ekterU1Ze694PAlJ0FP5FNQDv2tx3/O/19KfiGISThWoETgb9fir2BuBv3X/ej9TTkgoPPCJnCKap16O4U6cD64FbSz4cpOiPhcO3un+6FzwkKyP7n7oeKv73lNyi+UE093T/aop2jffVE1gD1VqmQ0BKfU8RFPwkyn3CZvhCdSP7mxgehBPewH3dMZjFQzUCxSHfVYUsBN5IuSdHwwtD5aHkYfqTsuCHIfhBeYqvD1QjcGHatxVx/Kh2V/cft8JTQT7wBF6m1CecoMdY4jkVDddFa6uV7QkBlHk3C4HqxHT8b3UxkjMVwL1nR+SPBEOIN/Cr6PEIinlPdWFQqNewLAJS4O9UIkbgQ8VTXOJlGTlBaZL3S1XLVuidnOqVjwVFphLF1lHqdCCnpWqeKQQYEV9KkXdlADworAfMOQx1o/xfCrtiawPVCPiWq7dlEJDy3ldJuMMo8x4D04LfZghueYvtFFQjMKO1atZeBJ4o9VbGYM5o2Fvw1hP96I0BZFckK6gMvCcMAd5UkVCNQBGY16tESsOxUxRvK2HuSLgVOXL4QPaD2sNGc+I5bj0LihweWq1dVXajN9UI5DT1RvJ4BWMVuthK8pjo4oOpAEqfPRKOlX8G71rrAcKDRcKcjvyLl9UZlaXl7urNIkZAhUYJGku3tNAXXB5KsiW325S2GQkvGPs+0e4q0Rlk39EYzZPbR3mYEnBhVNYILb25nluDGGY7CMFjRiNAYeVzjwdI5kLd5Bd+GF3mjIw0zL/Zjnuue7LCKd+SAaWFnxhdWLLerZTFPv9Pkt8t6uk+R89fqSw8q8WC+OnVm1nnBFQoSvi57ggfFUSL0UBRNnmQRHzhztKITqEDoTjE8bMuB6Tu0TIHZSwaFQ/sKXMsN+l02qJMBIWJj//0+Er3rBFM+c4G+0DsVaLCAsP+ne5Z5w3GmFKZLb25GiMee+cb7InuvZ2B97r+0kWnaYKesY78qowG31QQTxiofzxTfOyhuZT2Rs8/6c589y9Pc+obI8UmXG/fnrRplhdwhtiv3fZOx4SLTbGWrK+lN3OmA1gqOsVQgHkMwJseAvKRv9g2SA8PTZJXYLciq8QHej5yq5XG4RdGOGRatOOpXBoFPKYCxtN1Mt3BF4/qdirT2HtfDtO0uZ6ZGfskA6l6MRwnwx5sFsRgDOrUd0wHCK0O+y4p/6+XtaU3c4zA1ypwrBPTYXp/SaV8uNX/6eJTU7OUOB+OVs7f9YQSfzzBD8qK3FmjXavG4EHlYXRSXehGOZSfjpS1CKV85OWaG8wIpGJzUuy90EthMBfDML/h+EmYuED8SG+ucgqV0rEWYEwOFcFINTZXJf/XQ5lLpUsWRmCAeaT47US9eDW2fTNBuvprlOMPXwsHdKbaY22G7voKovk4Y+zXxvIQ6KLhulSdR3rjPAFViCVkMQwCDhE0rqF/90z38AcNjFpHLrFo6Ph4B5THyDD2SyryU05Tl+JFg/iFR7e7ofiYwTK+UPCxKZDRte4qGzzoqP/6F+A81wuCD6YHtBs7A1MGzFe92g0ZCVF8iN8i2L9j6az/Gq5RQkTo2pHe2HTALfCpAEb4Z7rCjsloTXoYPtPDUWdQfjr2b76cL3Qfc3GZO2I0JoPKoa4o2qCw18oXGq7gVRO16cyRLA1FEFF5KPjRekFAchRVHvimfBYZXV7d8Tye6OpdVFX6ZPBlGf+T9AUIPvJ14C3FBON9NexjmNg4DfoW7QnE6Fqf3lx7hTS3kk7bbcS+UR/r1KUL8SSPU/gwsRMnP6PBZBCPpjCTtIkEZtxivIBW0eIJDOjIBJOjNaUQDensJjBih3hgGC7tVB14pIRs7KnE488ABbaX+v1C+kgUrsIgW9euVQmLd6aggHqjKwwobDcN63QbEnXi5JnqWLjWUQJ2yl7y0VlZyR81jxUd254mNx9+aIyT4oxo7L/i6luwUY58TDsIjJicOTiaTrm3K/3x/NEu3WAYNLIEBDHelJFbOYaPpQ/djT4Ze8lyX4WaLNE6tBYGKjf6n3eINnXf3+E0BGKQnq1reAKu0XQHVABtpgJKA2zSohVWeaA3q6ToYEA4V/cgxfovUiwtIxcKawbzsWTl4xGGDQuMpLEOYjTOGOp5zsmxRVAQD32d/KB05GJnoTSP2diLV/DFQJk3EYWR6FfBQOWmduwofhOJsnXtOqiI+TPAhh2TgtlTNKU28rEGJM9BeaxzEA9HUCsDY0E5k0H5sXKu3Eni9wQxoxg80nHpBFMjEicjQ+8GhXr1vrrBmE21Bgku5IVrS2HU19Z9Is7Bvq+8S02L6iNe+CxdC40Ao3e3I/StB1AfdND3hdZ6gJSiO4JaHjyBbn32rnVXGb0WvEWU9+BGb2WFx8GRUPVDdxNWobTGY/Lp8BhOrUhGPlsw47kJ4KIrNCrNuzON2OAR6+FlY3+m+OSwHd1HVHi2rl0FnLU6pBSUkZerbwHrtdI/D/KG0YZxlcFoP3SIhcUcyjlZEH/IjAfE/N796CNkBgx0OQOguyl5SOLiendfEQxJd4GKvC0PRrSMlHg2J5Vd9S8dbPuTNp8MwmAR7CcrOn+CVr8cESdb10JPgO0qzgNQGA1qC1yNWx8w8FzxF8FzGKWcmF9S0TnWGuFDfkbjkpfjwB+KCEOAwbPOjhvGnH90G0/v8YjA7FPFLa8e3ZSIk5F0et7bcVqeTy63Y3DZPy3ZY4oWDrOwj6njzGkwqOjhZBCW2brWGAEVQiM2++p6RnGZVx9ZIqWRftAVLoI5RpUGPVOCwSAaN5XQvc/ADOZb64X4QPbkjunl4NCPk9c/H3RvMFN8cJqxljwnKteUFU8wOgifLOyjKyhIKFnQaxs0PlMcTLL+C7PKwgAQwCcq5OqaMwLKTIfH9XXurGcA9/jRSO3koeMkdx7lASjyn20QRjQ4bj2NzHSAABamBC7hDP6gZNGKNiKPGT5n4EfotvhqNgamD7o3A6Di6DgncPmfhKkDnuFo06zVcLvyJTOffR7U8kxx3IvBhSu9Y2GM+b4xG2Qfjnp68nUX1oYzbfMNZwKY0nC367HkWqJDFZNY/HLCc3ZbqIzXnunuusjisqgu9IcO9kSXi+vZzmEk16e8S2AAP60BUeUyIKAPQ1PnMV6tX5lxHaOd9c6mAzB71wPJWgBz+hjLxfQBARvrp/hUYPRsgTWVYYvvhQ/rCDW0EUBhcYNXDcKeerbmcTEg8P2M7j9coR+xE4SxSunQZgTMuK6GqU0HBkf8sZol1K0ujm3yBZTJuS90Kg/6FDDGWKjvtoUACktn2GOgs7NGNuQJfpAIitt9K9FXZn1eLFGoSn7hCEhhWUfC0+uOhhcu+bB4woRdIbyApFOFop/1qbZhjo7f2JrA8ZuaUhFIR8BOUO7VG2ghpo7MgjFufdLURfnIg+fQd0ZHycuGagSWxXPXpUl5mQ7gDn+zayDeC896GWchJqfK77O4mBnRrGl6p6zJx2oEJiGqBIkI/CJ6U+LErJdDro7PtCj3vwuz0E7eImtn1Qhcjt5tRRJGP05F7tYQSHbWRthtS9k1C9uPLXuMSJFQjUARmPdTiRSfVXJGsOb06X6kd0fF6cCfCIdGfsVZGLwXg4Po7Dcss89uxNQHTTUCsUhVuhQEODjDwanUbbGUOjZHK3lZCOQn592FQAzDm0iGycs6AmsrRULdIiwC8/4qkRKzxcWp026HuEgwJCcjPav5fYfsOJJvP8gblF80TKEoA0+iyHoAzFRPABRqWAMBOj+HyPbiDdB5MQS4890rdlQ3L6CYARCvh+oJgEINqyAgA8BvKjiXvwtvYA6Iwsi8gOIHraonMKflat4pBB6JgLUBRsgaxhFgN4DP0sd6DeOlJbytRiABrEqahoAUmsNDN7qKbXelcbgNauHEQirf6ChyOKgrdTUCXUTq86IISLE5LccPzVD0GjoICBemASwcNluKHZLVH6sRWB3iWoFXcBSdrbIaPALCgy1FjOODU4JSjcAp0d9R3VJ4PjbCz8jtK0w7kv5YVOHArskzXQ8UL74OEHL0P+6Kn033potbAAAAAElFTkSuQmCC", + "text/latex": [ + "$\\displaystyle y{\\left(t \\right)} = C_{2} e^{- t} + \\left(C_{1} + \\frac{t}{2}\\right) e^{t}$" + ], + "text/plain": [ + " -t ⎛ t⎞ t\n", + "y(t) = C₂⋅ℯ + ⎜C₁ + ─⎟⋅ℯ \n", + " ⎝ 2⎠ " + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import sympy as sym\n", + "y = sym.Function('y')\n", + "t = sym.symbols('t')\n", + "sym.dsolve(sym.Eq(y(t).diff(t, t) - y(t), sym.exp(t)), y(t))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On this page, you'll get an introduction of the SymPy-basics. This introduction is derived from the introduction into SymPy from Jason Moore (CC-BY licensed) {cite}`jason_moore` and the SymPy Tutorial (Copyright (c) 2006-2023 SymPy Development Team) {cite}`sympy_why`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## Why SymPy?\n", + "... and not Wolfram Alpha, Mathematica, Maple, GeoGebra, your fancy calculator, or ...?\n", + "\n", + "> First off, SymPy is completely free. It is open source, and licensed under the liberal BSD license, so you can modify the source code and even sell it if you want to. This contrasts with popular commercial systems like Maple or Mathematica that cost hundreds of dollars in licenses.\n", + ">\n", + "> Second, SymPy uses Python. Most computer algebra systems invent their own language. Not SymPy. SymPy is written entirely in Python, and is executed entirely in Python. This means that if you already know Python, it is much easier to get started with SymPy, because you already know the syntax (and if you don’t know Python, it is really easy to learn). We already know that Python is a well-designed, battle-tested language. The SymPy developers are confident in their abilities in writing mathematical software, but programming language design is a completely different thing. By reusing an existing language, we are able to focus on those things that matter: the mathematics.\n", + ">\n", + "> Another computer algebra system, Sage also uses Python as its language. But Sage is large, with a download of over a gigabyte. An advantage of SymPy is that it is lightweight. In addition to being relatively small, it has no dependencies other than Python, so it can be used almost anywhere easily. Furthermore, the goals of Sage and the goals of SymPy are different. Sage aims to be a full featured system for mathematics, and aims to do so by compiling all the major open source mathematical systems together into one. When you call some function in Sage, such as integrate, it calls out to one of the open source packages that it includes. In fact, SymPy is included in Sage. SymPy on the other hand aims to be an independent system, with all the features implemented in SymPy itself.\n", + ">\n", + "> A final important feature of SymPy is that it can be used as a library. Many computer algebra systems focus on being usable in interactive environments, but if you wish to automate or extend them, it is difficult to do. With SymPy, you can just as easily use it in an interactive Python environment or import it in your own Python application. SymPy also provides APIs to make it easy to extend it with your own custom functions.\n", + "{cite}`sympy_why`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First steps" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let’s take an example. Say we wanted to use the built-in Python functions to compute square roots. We might do something like this:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/latex": [ + "$\\displaystyle 2.82842712474619$" + ], + "text/plain": [ + "2.8284271247461903" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import math\n", + "math.sqrt(8)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we got an approximate result, which is not the exact square root of 8. If all we cared about was the decimal form of the square root of 8, we would be done.\n", + "\n", + "But suppose we want to go further. Recall that $\\sqrt{8} = \\sqrt{ 4 \\cdot 2} = 2 \\sqrt{2}$\n", + ". We would have a hard time deducing this from the above result. This is where symbolic computation comes in. With a symbolic computation system like SymPy, square roots of numbers that are not perfect squares are left unevaluated by default" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We'll import SymPy as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [], + "source": [ + "import sympy as sym" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Since SymPy works with mathematical symbols it's nice to view SymPy objects in\n", + "a format that is similar to the math in a textbook. Executing\n", + "`sym.init_printing()` at the beginning\n", + "of your Jupyter Notebook will ensure that SymPy objects render as typeset\n", + "mathematics." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [], + "source": [ + "sym.init_printing() " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can apply SymPy to our simple root problem:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAACYAAAAVCAYAAAAq05ytAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACJ0lEQVRIDbWV4VFbMQzHCccAXEeADWjZIGyQXjeADcr1U/KtRzeAFWAD0hXYAEbosUH6+wX7ne04oBcuutPzky3pL0uyPVmtVgf7psVicQbGD/hnFOsoqvhJvRvsrwnwOurnMKq4q17K1gHj0xgfew+MYH7BZmwU7TUwsnRCNCeMy1FRobzuseQg1/8b8/9ge2JU+jvg+sx+h+UI3mQ+n7urW5QvsiX/pt4TdMH/6N3qB7tjhr+MX5UzIYfwLKVBXGVDR4zd5St8r7wj6fd3xzaEZ2BT+Jlg3GFJZuo47bCc//A/+ZoyPnSUQ3gGZgAvODFDPWoD7um0c++dxBieN3+P6b1nmKV6nbkZPG3nS1nbUo78awOj+obXvfnJnk+ITVqdKOY9EGbjBa6aGnlNSec2y5Gxh2cpe2TTP2DwJy8m4ztk+SzJebkcr0q7cuGd/w28jcBw6m7tue+lI+Qn2D7MJ83MVcT6JRNjs9XFqwJLjr8wDndahYzAmsGZtRn/lrskS+9aiLB3I128ITCUZiidMg6ZEljuoHgXSUMPJnvLv+10v1mkb9LfircODCWb/ZxxAEr2BuvzVBF6Nr/H/pL/fJ1Y2lzmSr8VInj5SXrEWKCWvCRP20ll5r0otXMzBurzVb0gzG0QOlbgQzyvC5VUtt4tbX3EAVjCrpspAxtaoHXSyCG8iRfarkRgljof9WhgIbh1j4U0O0oE5lto1tre7GiPm/oP0h9EhCxiygUAAAAASUVORK5CYII=", + "text/latex": [ + "$\\displaystyle 2 \\sqrt{2}$" + ], + "text/plain": [ + "2⋅√2" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sym.sqrt(8)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "mude", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/08/sympy_stripped.ipynb b/book/sympy/sympy_stripped.ipynb similarity index 100% rename from book/08/sympy_stripped.ipynb rename to book/sympy/sympy_stripped.ipynb diff --git a/book/sympy/variables.ipynb b/book/sympy/variables.ipynb new file mode 100644 index 0000000..d461d72 --- /dev/null +++ b/book/sympy/variables.ipynb @@ -0,0 +1,699 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## Variables\n", + "The use of computer algebra systems like SymPy is much more powerful, as they're able to compute expressions with variables.\n", + "\n", + "We need to define variable explicitly, so that the correct object is created. For example, let's create two variables `x` and `y` representing $x$ and $y$:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [], + "source": [ + "x, y = sym.symbols('x y')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ":::{card} Test yourself!\n", + "Review the [SymPy documentation](https://docs.sympy.org/latest/modules/core.html#sympy.core.symbol.var) and create symbols `q1`, `q2`, ... `q10` using `sym.var()` without providing a full list of `q1, q2, q3, q4, q5, q6, q7, q8, q9, q10`. Tip: `sym.var()` is an extension to `sym.symbols`.\n", + "\n", + "Click {fa}`rocket` --> {guilabel}`Live Code` to activate live coding!\n", + ":::" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sym.var( )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "````{admonition} Answer\n", + ":class: tip, dropdown\n", + "```python\n", + "sym.var('q1:11')\n", + "```\n", + "````" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Expressions\n", + "\n", + "Variables alone have little meaning, we need expressions to do some proper math. Let's define a symbolic expression, representing the mathematical expression $x + 2y$. The most basic way to construct expressions is with the standard Python operators `+`, `-`, `*`, `/`, and `**`. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAADoAAAASCAYAAAAKRM1zAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACmElEQVRYCc2W3U1bQRBGDXIBiBKgAxI6MB0EUgGhg0R581tEOgBKgA6gAwIdhA6C3IFzzrKzGjuX6MryNYw03rmzs7vz7fyst+bz+ei90nQ63cO3b9W/j4zPfqN/rLrew9Z7BVpBXjAeBRrkc+Sv8BHyXej7jNt9jFa1wZkJ/GXF9YI6y2vZy+jO4Ous7yMPChQHdir38WXZZoLiN+DcI5OR3EFvWvemoYH2dqTDUEBPADKCXbR8AV02TTcOqd5cpNkh+lPYW/tcbe6xuany4ANnHb9yyIF65ktDYhSwfu/DD3xfMhaqc1eMxzmi5yh+yljdw1ewNWZduJk186aEL4L08qMT68/36vMt8rKPJ+g+aVQiiqE3ko1MFw2MqrQL5/mifIMfm9BNBTZiFLhBkezOPj+Z1JXuHKn7i0VPyeID8iM6Abvha2lUljB/gWDzWCYvyPUL3bMauf9/982b1TOs2bzG73hTjd6PvAZZn4ouIhrGYde1KOb+GTmsC8gIvVmxx2g5rEysN+N2GY1QI74jEAKyvHJ9Gm11JaK5RtGV249FrfGwoe3cRRsnzvWy9hlbJJG9PGs1yLmWgVUpjhl2JYhjBAGY+zYj0RsdDXIqW/C5AWAyPHGmUTnsOFvwLXrIgs7+8llqtkTTD1NX5LL/IQW9UNDonIuCR9wMca7OG4A7ZHtApgm6XA6CLP1AI+YCUyupMXpReztOanQG38Ju/gA/I7c01mZD5HMh2Hjb87HLPcVs8730ZfgD+6ZKLaKD/qnn4LU0oxef+/9WwEbd16PQdggDjTP2lQcjQcFmXiFky88sKM/Ki7b+YYiPdY8c2lJn3Xun/cyaXMP+o7vk7IVyGzR1kzODiQASqI3ISFqb110X/BfFu+8OLJ96AQAAAABJRU5ErkJggg==", + "text/latex": [ + "$\\displaystyle x + 2 y$" + ], + "text/plain": [ + "x + 2⋅y" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expr = x + 2*y\n", + "expr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that we wrote `x + 2*y` just as we would if `x` and `y` were ordinary Python variables. But in this case, instead of evaluating to something, the expression remains as just $x + 2y$. Now let us play around with it:" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAF0AAAASCAYAAAA5f9J6AAAACXBIWXMAAA7EAAAOxAGVKw4bAAADFklEQVRYCc2Y7VEbMRCGDeMCGNIBdBBCB04HIVSQUEIm//yPIR0AFTDQgemAQAfQQRh34DyPIt3Ih33AObq7nVnv3upjX61WK8HWYrEYDZWm0+ke2H5EfJ+Qz35jf4i2wQuwfgTkNXyAPhfw2J8hUgz4OfJzwod+hn6vDb5N9qFJsO2A6RI2SUwWk6ei7UoroOB8An9vObUBPsnHMpdZb7aYOUVpE+yMncNHsPiv6kCLBh1n7rjchiYMegR4fbwZvoN9KXvaOHhlzCbYG6cuHfRG5680Gtwngjtf06++GWu6Dc9c1fSYUakUHAL1G2w2HUfYd/S5iXpxga+jNU68mEa0h8sUafDFvQ9b7y+QgWLbJXLdXKlrpzLP9DPA/ZJBcAd7EViTraMuzBrbK4HFgJsI6UUjnp8R8wy9jvErti92GhKFTAe0mZID9kgL1myXduG8PRh7+PECvYlBHiHdBBNE8pXjayEnbYN75aTy8psFPGVoD9AfsBl8F9d4PGk/p5sXX53cLMcvvUJiJ+dvnDefLPqwxudj/E5vdrP6NB+DLqa6balLnLco9iWHfISgZ8BT+6oFpLYXkvGrgjrC7mnZQ1qyWhPjPYm7SDO3Ir5TUhg0S2Bezz0F2hoznTmKYsf/C8premgERFpAdWli84nmAjon/Lpx+8gqw9HdSGt7ItuqkxmNrsP3cjoJqW/vcgwog2mt9CI1K9x5weblxssqv7zoUp7wabYervDtRlRZje4G5Hj5DDW+Mcvt1AdZXswI2f9puAFLlxE229JlhdoN4ddAmgy36N4ZOU2w5SXLgIf7w060pTWtLB35RB3oH6IP8c3Vx7DZYNYIVMAn8Ax2offwM3pVauzTEfkENPDpb4fcbb1keAp9j/vC+gP7Zpd6y3SwmDBSiCvyGpvJMdsq+V9GnPyXi1Tk76EYfE+Dr7BWVBL7ditEbx/kcQpH6u1D3tfTAMOeyEDolkhPx+k/S+vfYtgtL8WIAHRxvD1Nec33L+kLfG9UEktiL1peiu1mNjHBMeheUma4tdza2cVm46od/QUsNB1MpQelkAAAAABJRU5ErkJggg==", + "text/latex": [ + "$\\displaystyle x + 2 y + 1$" + ], + "text/plain": [ + "x + 2⋅y + 1" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expr + 1" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABrklEQVQ4EZ2UMVICQRBFF+UAlEeA1MjSnEBvIBxBj0AZQWbhDYDMzILQTAISIwtuADfQ4gb43tTOOixYgl3V9Mzf7j+9v2epbDabrNfr1bMs6+DaJf6Fd8AXAsfYKcmSDShuN5vNV3w4m83OwZ6J7+xXxxCekNzH79MiyO12jY9T/JC1hNf4EpJaqWDKvgbuGxxsElq4otCO9ln5oH05BVZxKPuMA5bgdWLF50SJ7/AGPmc/JAbLn42ILTvcMR5cAPqqcfLmPIA/Ed9wdU+tzeZWYC8huMOY5ARZfsCHBdgN7rVKTUzpdgkpHoCracuE3NxP8rXdmJOag7XzbUKK1OiM6ImFsQ8DI1qolql+yiO23SHJatAgFp2xdihqGc1nC7BwQA56yBosfFVBQzaeckVMh2C+h6R6SV7+cgr9LKhCYpJDmLLe0QbMyUaT7CxueGZ3evGlVdkopqTqV7byn4Nv4H3z2nzi3kkt6BdWXuz/erfb7ePztD5oGJj/+LErfB7TWDtZ3+oxYsaDCcl1QC8W5TYiDiGO9zPAv37LsSpGCiV0IHamdmOwH+0AtG+pm8vq1UVIVQAAAABJRU5ErkJggg==", + "text/latex": [ + "$\\displaystyle 2 y$" + ], + "text/plain": [ + "2⋅y" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expr - x" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice something in the above example. When we typed `expr - x`, we did not get $x + 2y - x$, but rather just $2y$. The $x$ and the $-x$ automatically canceled one another. This is similar to how $\\sqrt{8}$ automatically turned into $2\\sqrt{2}$ above. This isn’t always the case in SymPy, however; consider this example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAFgAAAAVCAYAAADCUymGAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAD3klEQVRYCd2Y0VEbMRCGL4wL8FCC6YCECmJ3QEgFCR04kyf8xjgdABVkQgeQCojpwO4gHndA/k8naWRZd8Hn9RCyM3uSVtKvvdXuSnfV09NTZc0XFxcDa8zXgFd674PKmCaTyViQx8awrwVu4N8/6vsGz7AigZ8K60TlFyvMfeJIz4Hwg67vVF/Slvyx67qai4OtVF6DYWZgAfaF91PlW4D/dZKeGPdK5SjoqvpUdQw0Uv0+yLctNXemOe9VrixTBMpdbavMLuP1AkPx544Y6HuezhUW3rwS/0jlHerYAfzK0sBnUtCFRQeFuk4hauAuNNSkuXTO5+O5fcnx8E7k7YA9+iYGFhC5d9FJm5ebhCEX0h2PLVFu+NKYNhn2OOuFEVhb9RBuJ6p/ErOLH8XQg8bc1tWNJ3msMWftiL2xmIVAOn1owHE3IPW7gy7R/UjjZ2rHKPV9NypLWNhjlHrwVAO/wep4EN+IyXHkJYzvcorKEnECz0sdXrYLdgusbZfeFePiVOFmwQJfvU3uVM9tcCYZ0Vsi7DFwHiwAPDedTNgwES+GDsVpvxMmDzaAK84GGWBvYO5RwOF26w1aqcTgOBtElObv2Ba5jK0NrMovgaU5lKvWo2QYmoVKIUBXIDbAjQ2CpNwVm/U5lTmUcmJd+tduA34Q+v9N74jn1yAnp3Nou1ShgXjrZZxQV9Apl4Uh2LMfPDiAhM4SWOjbqkwUDPO2xhZGyYCV5EQZX0+ktc6k+UTwoUo8MpLawcEwJFGa5l+8G1nT2eOcLs3BGuu8IYDFA00LcW0BrIkIh7Z+N08YXbCb1jSRSyc26Uhl9FzV2TRycSD6YkR7Ie/CF1vunGEO9lj2NIAKuYeDiN3AW5iYpgwSfZr4NWSNGJsq5DqNsNcWsmxIP7yw9GmP0aO3qs67pfZQ0+XkJu+lHw9e9PRgJ2C+wZ3VVY8kGX0h0Ud5VmEXTzIZTQvsAuzuIr0XRsOx7lXPv0CHkqVpB+NiMEfeJrxbMXX5Ye4c66nBLrBbTKg0+Vx8J2ZRvqmXqsd0wZgCfZcMZXOywM4xrdpcuzByuPunuHnYE73cd7lJ/RZzJ4baPLjeAKv/rPoXOhcfW+E9B0frnYrHzxlrOUZrTsWzJkz1DcRz+g/qjTB5srttIWOySAayUhveG+G1YiLZkeqkUbz+spYUn3i8+24wM7AWJs3kp29xdSuh1iR/poeRFXSKw4FHCgzEF+611i2mTclJO9jB6UUOtiSuM+Titfuk5QIvgIU3ckceqyT38g+5LfdydsVINvvhLlBHfgdPVaancOj+r0u/CXxqxyvdHwOidMKb8DIVAAAAAElFTkSuQmCC", + "text/latex": [ + "$\\displaystyle x \\left(x + 2 y\\right)$" + ], + "text/plain": [ + "x⋅(x + 2⋅y)" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "x*expr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Aside from obvious simplifications like $x - x = 0$ and $\\sqrt{8} = 2\\sqrt{2}$, most simplifications are not performed automatically. A general formula to simplify formulas is `sym.simplify`, which attempts to apply all of these functions in an intelligent way to arrive at the simplest form of an expression:" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/latex": [ + "$\\displaystyle \\sin^{2}{\\left(x \\right)} + \\cos^{2}{\\left(x \\right)}$" + ], + "text/plain": [ + " 2 2 \n", + "sin (x) + cos (x)" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expr2 = sym.sin(x)**2+sym.cos(x)**2\n", + "expr2" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAOCAYAAAASVl2WAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAZElEQVQYGWP8//8/Aww0NDQYAdmrgdgYyP4AEmcBMgSA9GwgfgfEJkCsBMRwAFIAUhkKEgGyy4AUyBQ4YIKzcDBGFUACBj0chKHhJQQLN0ZQZAGDGBRBIOACxKC4OQfE94B4NwDm+hiAOyllRAAAAABJRU5ErkJggg==", + "text/latex": [ + "$\\displaystyle 1$" + ], + "text/plain": [ + "1" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sym.simplify(expr2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Only attempt simplification on expressions that are several lines of text. Larger expressions become increasingly computationally intensive to simplify and there is generally no need to do so." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In many cases, our expressions include a left- and right-hand-side. We cannot use `==` for that (`==` checks the similarity of the python-object), but we can use the `sym.Eq` function to create the symbolic equality $x + 2y = 3$:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAGAAAAASCAYAAACkctvyAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADhUlEQVRYCdWY21EbQRBFBUUAQAiQAYYMRAbGjsCQgV388UfhDIAQIAPIgEcGJgOryACfM0wP49ViS8i7rLtqNL09r9vP2dXS09PTaKh0dHS0AbZvGd82/cRn5PdZNvgu63CQga7Sq9MJ8mtlS0N1QAZ+Sr8rUAn+hO4rbRc+KaB8qARGDa6xwwEj+I/ILmh78JfLXYLngDFt/41naOwC3D3Yy2x4pKnA/0Dqvg9ujR4UgXOooFMHsL8RYHsLjVn0A/DN9SqwitxUHjpZKg0YWyJwF17ByrN4kL8aeqsJuELadEw1NAwW7OqwVqNBFtlwqrw4gAEVinKxA/+FZpR9pkk3zLl8Zrv/5ay9V07ZUs54uojpA/cm4juez2JdHjunf22vmNpLDw6zOpXWwFkc4ADCVHPpvejOaRrdtw695cLeHMBZUwQOjW9QxJuRcw4zRiNLzMUB8J9oEXGw7ZT10zjz0D3rZnJsxu3+BraBcxsHJQcwwcjXwEHWKYGbBdI6rR5Pwnf48fK9BO93z86K3WQcvi1NMh+dsrj0QjbVs89vl/3UhAUF7K/RI2O1q5ma3oIiA24RPFTnfHABMh0xcnI1NsUyboa0RZCOc32bgjNHUN7DMx4aWHxOijFmtB87tyIxNWXVcP8seA0g7XpBvxYZEEoEojZlYmyqZ6M2A4+Q6+0N+hSxUwtnFLDeDF2nN6IL8RwBoqFXaaX8MGa5UvbXDGBOJ5QxjOib9rUEiXmcHFCfzuRQptR7ZCoyok8K1/O75jlTJ27SlyyET6+g9JG1jpWMzZjU45E5TeXz8EvHnNcy+GXSNDdLBt+5jP3XaK22W2FA41pb4/PYaBZ4KMfj80Un0yeBwSjeoa8vXSHolBLt8DqkxsvjaKb670T2b81gxxYkjX7N/k3jb+d9r80AI8Xm247OmNAKIXMsLroi75rhXI1qYKiAEVrTGFld1jR+um+cxFjo1JVhayx/4puBIzaDRzsfwD+uwFgjjSZBO8GBK5pKm0IT+FKOnNMTXXGOTohvk/rYZllRUd/3fVP7SfObQHq3+u/h4DmjGSx1AKlT+S+r0z/jOFhvL3wJq8w8xLk6QsV9mxs0LXeMztrXrH//9EiNTUuXnRvDm95mzbHPQydLUGeEMfooAWZZneLpa5iz36Nszm3LTkvQ3GjesABD6wAvYCPf2u8HTh+O56jF6RcKaFOdt/5iVQAAAABJRU5ErkJggg==", + "text/latex": [ + "$\\displaystyle x + 2 y = 3$" + ], + "text/plain": [ + "x + 2⋅y = 3" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sym.Eq(expr,3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When setting up these expressions, watch out! Be careful with numbers, as SymPy may not intepret them as expected. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAACUAAAAPCAYAAABjqQZTAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACGElEQVRIDb2V7TEEQRCGlxKAIoOTgY8MyMBHBMiA8uvun1oZOBH4yAARHDIgA+oyOM8ztq92p9ZZCm/Ve9Pd09vT09MzV0wmk+I32O/3V/M42BZhL7d/pS8UNQwGg7JSXxlXYIntpeYyS7zHdxGHp8pJWax9DN1/58OVgI/II8ZjeIZ8DG+Re+HzxfjG/BiuQhO6gWt8r+17sJSU+AA+52XFVsLb3N6m43fdZv+JLSq1w1ai7PVdjVA22W0cRX3uz+RIapMVLH+O6Cfn/w0LHauw1CUjYh3gZ1WXob14iq1xAtV6+okNuA/13YNiZKViwVkN2eX49Lli0TPoJZGPyHmVvdH6eJlsjwtoi+hvjNKkusCdzwRBt+B0Y8ge/R08jw+xWaF4djTrvw2HKsAClb5Tbb2kg4gq+m79BCZmFXpVkg/VGLF8w56wpc0weuGK+TAgW7ocYYuGz+eTTgzfM9+5z5Di4NPoL5x34WX+kZUSlrmXpOZPVMr5WVhnsq3i6fuWZAps9prJ+sgmYEvJR09dYzVwjkZ588maPiSgf0s5XDhtyAWhFdUmDuEYvX4KJ+jjlBSCjfbGaNMlIJu15fXKJmiDE5gf1Tm2aUPrjH708VWR+gTZZKTrGLtRWWzOeRuLOf8GROXozRhDG9s3pO2decZ+h787nQLd4/daC4/NRf0fNV7BaCLG93t1nwWLsAXdpMmmo3wHBAKNiPr+/bAAAAAASUVORK5CYII=", + "text/latex": [ + "$\\displaystyle 0.5 x$" + ], + "text/plain": [ + "0.5⋅x" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "1/2*x" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Python does the division before it is multiplied by `x`, thus a floating point value is created. To fix this you can use the `sym.S()` function to “sympify” numbers:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAlCAYAAAB21ggZAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABtElEQVQ4Ee2VO1ICQRCGF+UASGgIN0DJCeAGPk6ghmZSRJDiDShPYMkNMCCn9AYQGlLcAL9v2FkWliqKWLvqp5/T89juprRerxNpMBhUYI9BSZIm/AHUwH1qmxEzPksV2RDDq0CegTfQRu/CTTYESdkfjGYOBnVoBW6Au0hVsPF7pH6/35BHoI/AV9TzPByJHb5Dnu3PHeL7Vt1K+TsEK4vbCJ55HMOwVYR6ORU+kL30J/wJrJAX8Eg9dC+fuIMZxTJdvETOCJs+Xy3QeavV+kHyFS7AFQG96XQ6B8/gEtsaW3a8ki9wChUufWzx/4JjL6S/RFWe9CH+5Icr55+SMq6hh0aBXwN7o4s9a+HsldLgEbxDUCBkJ8UL6CDbjaHj5JJO2zMjgtzNkWMLB8qXt604Jyg0e+qXmdkh4HF3dtCxwGHGQ7RJlB9Sh2RKZ275RF/+SIWs7NbAmH+5nSMVFmDwsmMWOqA3FLfa5xzD+TrZtx88Ehmd5lV49k3iBoUFBDnm6/DbGIRcE+o7CzB6ySY8lkdcY5IwQvdLY4IjlECMTLn/RHXlfPEZ7Lbxf05/pKz4fgFvfO5bFh09iAAAAABJRU5ErkJggg==", + "text/latex": [ + "$\\displaystyle \\frac{x}{2}$" + ], + "text/plain": [ + "x\n", + "─\n", + "2" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sym.S(1)/2*x" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or you can ensure the symbol comes first in the division operation:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAlCAYAAAB21ggZAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABtElEQVQ4Ee2VO1ICQRCGF+UASGgIN0DJCeAGPk6ghmZSRJDiDShPYMkNMCCn9AYQGlLcAL9v2FkWliqKWLvqp5/T89juprRerxNpMBhUYI9BSZIm/AHUwH1qmxEzPksV2RDDq0CegTfQRu/CTTYESdkfjGYOBnVoBW6Au0hVsPF7pH6/35BHoI/AV9TzPByJHb5Dnu3PHeL7Vt1K+TsEK4vbCJ55HMOwVYR6ORU+kL30J/wJrJAX8Eg9dC+fuIMZxTJdvETOCJs+Xy3QeavV+kHyFS7AFQG96XQ6B8/gEtsaW3a8ki9wChUufWzx/4JjL6S/RFWe9CH+5Icr55+SMq6hh0aBXwN7o4s9a+HsldLgEbxDUCBkJ8UL6CDbjaHj5JJO2zMjgtzNkWMLB8qXt604Jyg0e+qXmdkh4HF3dtCxwGHGQ7RJlB9Sh2RKZ275RF/+SIWs7NbAmH+5nSMVFmDwsmMWOqA3FLfa5xzD+TrZtx88Ehmd5lV49k3iBoUFBDnm6/DbGIRcE+o7CzB6ySY8lkdcY5IwQvdLY4IjlECMTLn/RHXlfPEZ7Lbxf05/pKz4fgFvfO5bFh09iAAAAABJRU5ErkJggg==", + "text/latex": [ + "$\\displaystyle \\frac{x}{2}$" + ], + "text/plain": [ + "x\n", + "─\n", + "2" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x/2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ":::{card} Test yourself!\n", + "Create an expression for the normal distribution function:\n", + "\n", + "$$\\frac{1}{\\sqrt{2\\pi\\sigma}}e^{\\frac{(x-\\mu)^2}{2\\sigma^2}}$$\n", + "\n", + "All variables have been defined with:\n", + "\n", + "```python\n", + "sym.var('x, sigma, mu')\n", + "```\n", + "\n", + "Click {fa}`rocket` --> {guilabel}`Live Code` to activate live coding!\n", + ":::" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "tags": [ + "thebe-remove-input-init" + ] + }, + "outputs": [], + "source": [ + "sym.var('x, sigma, mu')\n", + "expr_correct = sym.exp((x-mu)**2/2/sigma**2)/sym.sqrt(2*sym.pi*sigma)\n", + "expr = 0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "expr = " + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "tags": [ + "thebe-remove-input-init" + ] + }, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "4f6e6e54013747078a38a8b8828be565", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Button(description='Check answer', style=ButtonStyle())" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "82d1fa7e41ba4c188826a698baa8e76c", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "check_answer(\"expr\",expr_correct, check_equation)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Functions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You will also work with undefined mathematical functions in addition to variables.\n", + "These will play an important role in setting up differential equations, where\n", + "you typically don't know the function, but only its derivative(s). You can\n", + "create arbitrary functions of variables. In this case, you make a function of\n", + "$x$. First create the function name:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [], + "source": [ + "f = sym.Function('f')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now you can create functions of one or more variables like so:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAACUAAAAVCAYAAADB5CeuAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACf0lEQVRIDa2W7VHbQBCGFSYFmHQQlUBCB9ABIRUk7sCZ/LL/MdCBoQKGdEA6gNABLsFxB87zHCflJOuEBnlnVvf17qu93b2Tiu12W4zV+XxevpWjy/agGCmLxWIGxdEImjJy1BTv3GFOAC9Z28T1C8ZVP0wxPqNzTPsjYt7UYO/GNrTXEmQjBeCS9Q/oLfodPUFrYX3C4CftKIckhOOKZho5804B0hEd0rFH9Deaik4byX2JXHIWnenDY6Nyjx7Sb6RMI4X5v+jhy2g/Tzlh+phL3ymLK0A5h6yl1X5cabDIef4+ncIJU6ZDRmrN+C62U9pUxLTTWa9jZ73JpRyj39AS/YoqD2B+vXQbTzlPG5ECeI1+YUHSpX207ZAsn9FnOxm5xO5KZf0BvUFPGHso5A61Q9sWOctGpERg6I6UbCRYk3gtqC3YG6H0pRvGpttoKR6cdD1Mxoecu04xGS5CyJ9SdKsvsS/rkkds03r7BOiJuYCnNRM50W7SSF9EWgMpaY6gc75jM+cAbzvBu5Nhs11OGam+KEllmE1hr+CgB0ZcXdTMTdSMofPrnZpi0iK+yBhV00ayqr1qrogv88Ra6Nakh8TPRxr5vq+AkVo1IoWxL9Lb1yLlumlui5FRvU7CrlMAc655GnMS6q8dKVNXYNx38oRYI0akLdr5UfXl8vg9u0f9hPxBdbZOpZiWaDdt/Evxb7NE74b8G4F7Ro+GYIdg4CrlFHuA52dotWvraehJ8a7pulhbmx889GKVM/wl2KlPxCvh1SYIONPkD9pOwUfI4CZyyBX+p6yp4FRs+y62rpeIN8p+C8eINfc/6kPy3YeJtTDrw/StYT+TI8X8A8ObApWBYhW/AAAAAElFTkSuQmCC", + "text/latex": [ + "$\\displaystyle f{\\left(x \\right)}$" + ], + "text/plain": [ + "f(x)" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "f(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The same `UndefinedFunction` can be used to create multivariate functions:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "tags": [ + "disable-execution-cell" + ] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAADkAAAAVCAYAAAD8dkbIAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADW0lEQVRYCc2X7VEbMRCGHYYCDB3E6YCEDqADh1QAdOBMftn/GNOBQwUM6YB0wEcH0EGIOyDPI+suurNk7NiZ8c7sSVrt7r2rXel0ndfX1866PBwOe+v62JR9DstOZ00ajUYDXBys6WaT5r2Iqfb5zhUsEcoT5qZx/oJx1Q8ixn06h7Rfo85WNOBx4ae03wVUzCQKY+b34Wv4DD6Ca2K+y+Ab7VYFKEAwXdKcR4zlIFEyMAM00Hv4J5ySi2Cmt5XEJsZOtlxZAbN2C+/Rb5SoRhLy3/DebLSdTzGC7H2pXI+ZfEapFKB78Xk7Q2ugEuPJbioiKEvUAM3kC+Ob2J7TpqROu3zreezcr/qSDuFTuAd/gaU7dH7Muss9E58fsHhgHA4VrePcFe3nljcxHjcyqWFUFOTEPtwOUD+f4Cc7BRpjdykzfwdfwUeMPaT0HfYK7SrkIac/t1Hb/gSZ1dUmMfYamVQDR664VMwUcwJ9UalN2JvBFMSUsQDMpuRBls4H4aIHPv0Ou1iSVdR+d6my1JsPEqEODfbRtkACFXyO7rFN9+tHlB6RBX3adknlfLRlng8VHrN20VJwe7Vlqoij2yhXpZB7KAUZhMs+EjCViaCuq8G/tMkCGYxVlO5Hk6IsV3khGbkgNapWjW6WLAMdLyTAVaDqQwZZV15oWJ60CuqqiGq+w9tNDrPveckF6aFS1X/0M9eY6Wrv1pMxgFtaXyx5aAkgrQwPkGmYjQ/t0vGCvu9Mfala2o/OmcnnRpC8TCe+MLcqiGty3rJuk8HJfn7CKqYKyJxrLGDU82LxkOoW+o0Aoz99euLmKJwHjSDRslQ7GOfqO3XiHgu6qZC+du4XX3yGHzN5SuvnyFPXUq1Ll3GHsVkV/DJlHO7J2PiJ8hJeHWIlvLMFSP/j+BebwDeprNRH7wk+KM2vKsdXH+6uYof+GH7I2SDvwU/O7bAiffiGVZHcj8uehH7rzNSmyF82s5ol5sxeXdL03Q5WR+7ToQ+zLsbwF2KnLhWMG+WkUo7Qsyz9QXUfr0UR8K83nHihSBPgLcob2hzeiEls4VOzi2IIMrZVjTNcitS3Cjzh1iH3r1e2RWRm9tFzL3p/dZ+X9qK/WX+rLFfPq8hi7Q9WsfmfuuAZiCl9xx8E4gWsmkncfAAAAABJRU5ErkJggg==", + "text/latex": [ + "$\\displaystyle f{\\left(x,y \\right)}$" + ], + "text/plain": [ + "f(x, y)" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "f(x,y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ":::{card} Test yourself!\n", + "Create a function $H(x,y,z)$\n", + "\n", + "All variables have been defined with:\n", + "\n", + "```python\n", + "x, y, z = sym.symbols('x, y, z')\n", + "```\n", + "\n", + "Click {fa}`rocket` --> {guilabel}`Live Code` to activate live coding!\n", + ":::" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "tags": [ + "thebe-remove-input-init" + ] + }, + "outputs": [], + "source": [ + "x, y, z = sym.symbols('x, y, z')\n", + "H = sym.Function('H')\n", + "function_correct = H(x,y,z)\n", + "function_answer = 0\n", + "H = None" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "function = " + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "tags": [ + "thebe-remove-input-init" + ] + }, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "bf9cdc4356624837a034f353336aeb2a", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Button(description='Check answer', style=ButtonStyle())" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "8052642635a74e9b966db4bbc3ee54ac", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "check_answer(\"function\",function_correct, check_equation)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "mude", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/toolbox.md b/book/toolbox.md new file mode 100644 index 0000000..1154aeb --- /dev/null +++ b/book/toolbox.md @@ -0,0 +1,41 @@ +(toolbox)= +# Python Toolbox + +This page describes several ways to write and execute Python code, some of which don't require any installation on your computer and work entirely in a web browser! These approaches are described in the sections below, and are based on the tools IPython and Jupyter Notebooks. + +**IPython** is an interactive Python interpreter that adds features that are useful for engineering, such as command history or inline display of figures. As you will see below, you can enter multiple lines of text and evaluate them at once; this is often referred to as a *cell* of code. In a nutshell, if you string many of these cells together into a single digital document, you more or less end up with a **Jupyter Notebook**; this leverages the power of IPython by allowing you to type, run and save the cells in any order, as well as type formatted text in between. Together, these two tools make up our toolbox for this course, and, as you will see, both of them can run in your internet browser, so there is no need to install special software! + +## Interactive Pages + +This course is powered by a special software (the [Sphinx-Thebe](https://github.com/executablebooks/sphinx-thebe) that allows you to run Python code in your browser and gives you an experience that is more or less identical the the "standard" Jupyter Notebook experience you would have on your own computer if you installed the dedicated software. You can access this tool by clicking on the rocket icon ({fa}`rocket`) at the top right of a page where this is enabled. + +(calculator)= +## IPython: Your Primary Python Calculator + +Below is an example of an IPython interpreter embedded in this webpage, which we refer to as our **Python Calculator**. Note that the square brackets with numbers (e.g, `[1]: ...`) are a feature of IPython that keeps track of the cells you have run: the first (pre-loaded) command is a print statement that executes once the interpreter is ready for use. You can try entering code yourself (for example, type `x=2`) and executing it using `Shift+Enter`. You just defined a variable! Note that typing `Enter` in the interpreter adds extra lines, it does not execute the cell. Try entering multiple lines, for example, `3*x`, `Enter` and `print(x)`, then execute. Can you tell what happened? + + + +The simple exercise above should be all you need to get started with this course. Throughout this course we encourage you to the Python Calculator in a new browser tab, which will allow you to read the exercise and run code side by side. You can test it here in a new tab. When the console is critical for completing the exercises in a certain chapter, a drop-down note will be added that includes a special link inside, just like this: + +`````{admonition} Open the Python Calculator for this page +:class: tip, dropdown +Click this link and wait until the message "You may begin!" is printed to start evaluating code. More information about this tool can be found [here](calculator). + +Remember that most pages in this course can also be run interactively using the {fa}rocket icon above (read more about it [here](toolbox)). +````` + +All exercises in this course can be completed using only the Python Calculator. We hope you find it to be a simple but useful way to practice and learn the Python programming language. + +```{note} +A special instance of the Python Calculator is set up for each page which pre-loads a few packages needed to complete the exercise. Make sure you use link that is on the page of the exercises you are working on. +``` + +## Anaconda: Python on Your Computer + +If you want to explore Python programming and Jupyter ecosystems beyond the exercises covered in this course, it might be worthwhile to install a Python distribution on your own computer. The most common and easiest way to do this is with [Anaconda](https://www.anaconda.com/download). Installation instructions are not included in this course, but you can find plenty of website of videos that cover this, as well as using the Anaconda Navigator to open a Jupyter Lab or Jupyter Notebook environment. Most of the pages in this online textbook can be downloaded in the form of a Jupyter Notebook file (a file ending with `.ipynb`): open it via one of the Jupyter environments and you are ready to go! \ No newline at end of file diff --git a/docs/quizzes.md b/docs/quizzes.md index bfb3103..721a43e 100644 --- a/docs/quizzes.md +++ b/docs/quizzes.md @@ -5,4 +5,4 @@ Prior to 2024 the book used Jupyter Quiz, which is based on JSON files. These ar To make the change transparent, and possible support future conversion in case H5p is no longer supported, the following actions were taken: 1. A tag was added to the import statement in the Python cell, `# jupyterquiz-import`. If all exercises in a page are converted, the entire cell can be commented out (but should remain in the notebook with cell tag `remove-input`) 2. A cell containing a Jupyter Quiz exercises should have a tag of the form: `# jupyterquiz-exercise-x-y-z` where `x`, `y`, and `z` are the chapter, section, and exercise numbers (as they appeared in the original book and Jupyter Quiz question number), respectively. This tag should be added to the cell containing the exercise prompt, and the cell tag `remove-input` should remain in place. -3. H5p exercises are created and stored on the TU Delft H5P platform, accessible at https://tudelft.h5p.com/content. Each exercise is assigned a unique identifier on this platform, which is correlated with the original Jupyter Quiz exercise tags. \ No newline at end of file +3. H5p exercises are created and stored on the TU Delft H5P platform, accessible at https://tudelft.h5p.com/content. Each exercise is assigned a unique identifier on this platform (format `X.Y.Z`), which is correlated with the original Jupyter Quiz exercise tags. The id's were removed from the exercise header text as they are now automatically numbered in the toc, so the `X.Y.Z` id is presered in a comment under the header. \ No newline at end of file diff --git a/docs/restructure.md b/docs/restructure.md new file mode 100644 index 0000000..53f9aa4 --- /dev/null +++ b/docs/restructure.md @@ -0,0 +1,10 @@ +# Restructuring the book + +Notes from Shiya and Robert early 2025 when chapters were broken down into smaller chapters and sections. + +- names of subdirectories changed from numbers to single words (e.g., `01` becomes `basics`), where the "home" page of that chapter has the same name and is located in the root directory of the book. For example, see `./book/basics.md` and `./book/basics/.md` +- Each chapter contains subdirectories `Exercises/` and `nutshell/` at minimum. +- Each nutshell chapter should have an identical file structure with subpage names to the main chapter +- Jupyter Quiz questions were converted to h5p questions. This is preseved with commented code in the subpage where the h5p exercise has been moved to. +- Small "checks" are kept on subpages, but bigger "exercises" are preserved on a final subpage in the chapter. +- Exercises/checks will be numbered using the automatic numbering of jupyter book and naming it "exercise" in the heading (e.g., `### Exercise` renders as "1.2.3 Exercise"). \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 445b165..e3cd78e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,5 +6,4 @@ pandas jupyterbook-patches download_link_replacer ---extra-index-url https://gitlab.tudelft.nl/api/v4/projects/11239/packages/pypi/simple -sphinx-thebe ~= 0.9.9 \ No newline at end of file +git+https://github.com/TeachBooks/Sphinx-Thebe