diff --git a/.gitignore b/.gitignore index 28c4be04c12439804e974fb46909234c6dc182f0..59e33e872cbef74f63048ebfe91ed3d97bf07795 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ learning-vscode/VSCode_WSL.html learning-vscode/VSCode_Ubuntu.html learning-markdown/MarkDown.html learning-markdown/TODO_makdown.md +learning-python/Python.html +learning-python/sandbox.txt # ---> VisualStudioCode .settings diff --git a/learning-python/Python.md b/learning-python/Python.md new file mode 100644 index 0000000000000000000000000000000000000000..6cad8495a9eca2e0743e28f8db68167c8dab6c82 --- /dev/null +++ b/learning-python/Python.md @@ -0,0 +1,1307 @@ +--- +marp: true +title: Introduction to Python +author: P.Y. Barriat +description: Introduction to Python +backgroundImage: url('assets/back.png') +_backgroundImage: url('assets/garde.png') +footer: 16/10/2024 | Introduction to Python +_footer: "" +paginate: true +_paginate: false +--- + +Introduction to Python<!--fit--> +=== + +https://forge.uclouvain.be/barriat/learning-python + + + +##### October 16, 2024 + +###### ELIC Training Sessions + + +--- + +# Programming basics + +* **code or source code**: The sequence of instructions in a program. +* **syntax**: The set of legal structures and commands that can be +used in a particular programming language. +* **output**: The messages printed to the user by a program. +* **console**: The text box onto which output is printed. + +--- + +# Compiling and interpreting + +Many languages require you to compile (translate) your program into a form that the machine understands. + +```mermaid +graph LR; + A[source code: Hello.f90] -->|compile| B(byte code: Hello.exe) + B -->|execute| C(output) +``` + +Python is instead directly interpreted into machine instructions. + +```mermaid +graph LR; + A[code: Hello.py] -->|interpret| B(output) +``` + +--- + +# Python: Overview + +* Python is an interpreted language +* The interpreter provides an interactive environment to play with the language +* Simple syntax, relatively easy to learn +* Useful in many areas (science, web development, GUI programming) +* Big standard library, many additional packages + +* Python 3: new minor version (e.g. 3.9) released every October +* Python 2: support ended in 2019, [10% of developers](https://www.jetbrains.com/lp/python-developers-survey-2019/) were still using it + +--- + +# Code examples + +```py +>>> 3 + 7 +10 +>>> 3 < 15 +True +>>> 'print me' +'print me' +>>> print('print me') +print me +>>> # this is a comment +>>> a = 3 +>>> b = 4 +>>> a * b +12 +``` + +> Results of expressions are printed on the screen + +--- + +# Running Python code + +- write a program as a file (or collection of files), run that program + > GUI applications, web applications, data processing pipelines +- type code into an interactive console or notebook line by line + > for quick calculations, experimenting, data exploration / analysis) + +### Using Python + +- local installation +- remote Python server +- online Python consoles or online Notebooks (Jupyter) + > https://www.python.org/shell/ + > https://jupyterhub.cism.ucl.ac.be + +--- + +# Expressions + +* **expression**: a data value or set of operations to compute a value. + > `1 + 4 * 3` +* Arithmetic operators we will use: + - `+ - * /` addition, subtraction/negation, multiplication, division + - `%` modulus, a.k.a. remainder + - `**` exponentiation +* **precedence**: order in which operations are computed. + - `/ % **` have a higher precedence than `+ -` + > `1 + 3 * 4` is `13` + - Parentheses can be used to force a certain order of evaluation. + > `(1 + 3) * 4` is `16` + +--- + +# Variables + +- **Variable**: a named piece of memory that can store a value. + - Compute an expression's result, + - store that result into a variable, + - and use that variable later in the program. +- **Assignment statement**: stores a value into a variable + - Syntax: `name = value` + - Examples: `x = 5` , `gpa = 3.14` + - A variable that has been given a value can be used in expressions. + `x + 4` is `9` + +--- + +- Names of variables are usually written in lower case, separating words by underscores + +```py +birth_year = 1970 +current_year = 2020 +age = current_year - birth_year +``` + +- Variable names may only consist of letters, digits and underscores + +- Overwriting (reassigning) variables: + +```py +name = "John" +name = "Jane" +a = 3 +a = a + 1 +``` + +--- + +# Basic (primitive) data types + +- `int` (integer) +- `float` (floating point number) +- `str` (string): text +- `bool` (boolean): yes / no +- none: missing / unknown value + +--- + +Strings can be enclosed in single or double quotes + +```py +greeting = "Hello" +name = 'John' +``` + +Inserting a variable (f-strings): + +```py +message1 = f"Hello, {name}!" +``` + +Joining strings: + +```py +message2 = "Hello, " + name + "!" +``` + +--- + +Strings - escape sequences + +```py +text = "He said: \"hi!\"" +``` + +Line break: `\n` + +```py +a = 'line 1\nline 2' +``` + +single Backslash: `\\` + +```py +b = 'C:\\docs' +``` + +--- + +**boolean** value: yes/no + +In Python: `True` or `False` + +> note the capitalization + +**None** represents a value that is unknown or missing + +```py +first_name = "John" +middle_name = None +last_name = "Doe" +``` + +--- + +# Integer division + +* When we divide integers with `/` , the quotient is also an integer. + - `35 / 5` is `7` + - `218 / 5` is `43` + - `156 / 100` is `1` + +* The `%` operator computes the remainder from a division of integers. + - `218 % 5` is `3` + - `84 % 10` is `0` + +--- + +# Real numbers + +- Python can also manipulate real numbers. + > `6.022` , `-15.9997` , `42.0` , `2.143e17` +- The operators `+ - * / % ** ( )` all work for real numbers. + - The `/` produces an exact answer: `15.0/2.0` is `7.5` + - The same rules of precedence also apply to real numbers: Evaluate `( )` before `* / %` before `+ -` +- When integers and reals are mixed, the result is a real number. + - Example: `1/2.0` is `0.5` + - The conversion occurs on a per-operator basis. + +--- + +# Types and type conversions + +Determining the type of a variable via `type`: + +```py +a = 4 / 2 + +type(a) +``` +Objects may be converted to other types via `int()`, `float()`, `str()`, `bool()`, ... + +```py +pi = 3.1415 +pi_int = int(pi) +message = "Pi is approximately " + str(pi_int) +``` + +--- + +- `int(x)` converts `x` to an integer +- `float(x)` converts `x` to a floating point +- The interpreter shows a lot of digits + +``` +>>> 1.23232 +1.2323200000000001 +>>> print 1.23232 +1.23232 +>>> 1.3E7 +13000000.0 +>>> int(2.0) +2 +>>> float(2) +2.0 +``` +--- + +# Functions + +A function is a "sub-program" that can perform a specific task + +Examples of predefined functions: + +- `len()` can determine the length of a string (or of a list, ...) +- `id()` can determine the internal ID of an object +- `type()` can tell us the type of an object +- `print()` can write some output into the terminal +- ... + +--- + +- A **function** can receive so-called _parameters_ and produce a result +(a _return value_) + + - `len()` can take a string as a _parameter_ and produce an int as the _return value_ + - `print()` can take various objects as _parameters_; it does **not** have an explicit _return value_ + +- A **method** is a function that belongs to a specific object type (e.g. to _str_) + + Examples of **string methods**: + + - `first_name.upper()` + - `first_name.count("a")` + - `first_name.replace("a", "@")` + +--- + +# Builtins, standard library + +- **Builtins**: functions and objects that are used frequently and are available at all times +- **Standard library**: collections of additional modules and packages that can be imported + + > Documentation: https://docs.python.org/3/library/index.html + +## Builtins + +Amongst others: `print()`, `input()`, `len()`, `open()`, etc + +--- + +## Standard library + +The standard library contains additional modules that can be imported. + +Example: + +```py +import math + +print(math.floor(3.6)) +``` + +or + +```py +from math import floor + +print(floor(3.6)) +``` + +--- + +### Math functions + +Python has useful functions for performing calculations. + +| Function name | Description | +| ------------ | --------------- | +| `ceil(value)` | rounds up | +| `floor(value)` | rounds down | +| `log(value)` | logarithm, base e | +| `cos(value)` | cosine, in radians | +| `sqrt(value)` | square root | + +etc... + +--- + +### Math constants + +| Constant | Description | +| ------------ | --------------- | +| `e` | 2.7182818... | +| `pi` | 3.1415926... | + + To use many of these above, you can write the following at the top of your Python program: + +```python +from math import * +``` + +--- + +# Text input/output + +- `input` reads a number from user input. + You can assign (store) the result of input into a variable. + +- `print` produces text output on the console. + + Prints the given text message (or expression value) on the console, and moves the cursor down to the next line: + - `print "Message"` , `print Expression` + + Prints several messages and/or expressions on the same line: + - `print Item1, Item2, ..., ItemN` + +> A comma at the end will not print a newline character: `print 'hello',` + +--- + +# Examples + +``` +>>> x = 7 +>>> x +7 +>>> x+7 +14 +>>> x = 'hello' +>>> x +'hello' +>>> print "Hello, world!" +Hello, world! +>>> age = 45 +>>> print "You have", 65 - age, "years until retirement" +You have 20 years until retirement +``` + +--- + +# Hands-on exercise + +Write a program called **age.py** which will ask the user for their birth year and will respond with the user's age in the year 2024. + +Example: + +``` +What's your name? +> PY +What year were you born? +> 1982 +Hi PY! You are 42 +``` + +--- + +# Logic + +Many logical expressions use relational operators: + +| Operator | Meaning | Example | Result | +| ------------ | --------------- | ----- | ------ | +| `==` | equals | `1 + 1 == 2` | True | +| `!=` | does not equal | `3.2 != 2.5` | True | +| `<` | less than | `10 < 5` | False | +| `>` | greater than | `10 > 5` | True | +| `<=` | less than or equal to | `126 <= 100` | False | +| `>=` | greater than or equal to | `5.0 >= 5.0` | False | + +--- + +## Combining comparisons + +Logical expressions can be combined with logical operators: + +| Operator | Example | Result | +| ------------ | ----- | ------ | +| `and` | `9 != 6 and 2 < 3` | True | +| `or` | `2 == 3 or -1 < 5` | True | +| `not` | `not 7 > 0` | False | + +--- + +# Selection + +### `if` + +Executes a group of statements only if a certain condition is true. Otherwise, the statements are skipped. + +### `if/else` + +Executes one block of statements if a certain condition is True, and a second block of statements if it is False. + +### `if/elif/else` + +Multiple conditions can be chained with elif ("else if") + +--- + +### Examples + +```python +gpa = 3.4 +if gpa > 2.0: + print "Your application is accepted." +``` + +```python +import math +x = 30 +if x <= 15 : + y = x + 15 +elif x <= 30 : + y = x + 30 +else : + y=x +print 'y = ', +print math.sin(y) +``` + +--- + +# Hands-on exercise + +Write a script that asks the user to input a year and tells them wheter that year is a leap year. + +The rules for leap years are: + +- in general, a year is a leap year if it is divisible by 4 (e.g. 1904 was a leap year) +- exception from the above: if the year is also divisible by 100 it _is not_ a leap year (e.g. 1900 was _not_ a leap year) +- exception from the exception: if the year is also divisible by 400 it _is_ a leap year (e.g. 2000 _was_ a leap year) + +Hint: "x is divisible by y" in Python: `x % y == 0` + +--- + +# Repetition + +## The `for` loop + +Repeats a set of statements over a group of values. + +```python +for x in range(1, 6): + print x, "squared is", x * x +``` + +``` +1 squared is 1 +2 squared is 4 +3 squared is 9 +4 squared is 16 +5 squared is 25 +``` + +--- + +## The `range` function + +`range(start, stop [, step])` + +```python +for x in range(5, 0, -1): + print x +print "Blastoff!" +``` + +``` +5 +4 +3 +2 +1 +Blastoff! +``` + +--- + +## Cumulative loops + +Some loops incrementally compute a value that is initialized outside the loop. +This is sometimes called a *cumulative sum*. + +```python +sum = 0 +for i in range(1, 11): + sum = sum + (i * i) +print "sum of first 10 squares is", sum +``` + +``` +sum of first 10 squares is 385 +``` + +--- + +## `while` loops + +Executes a group of statements as long as a condition is True. +> good for indefinite loops (repeat an unknown number of times) + +```python +x=1 +while x < 10 : + print x + x=x+1 +``` + +--- + +## Loop Control Statements + +- **break**: Jumps out of the closest enclosing loop +- **continue**: Jumps to the top of the closest enclosing loop +- **pass**: Does nothing, empty statement placeholder + +```python +a = 1 +while True: + a = a * 2 + print(a) + if (a > 1000): + break +``` + +--- + +# Hands-on exercise + +Someone opens a new bank account and deposits 100€ at the start of each year. +At the end of a year, they get 4% interest. + +How much do they have after 10 years? + +--- + +# Composite types + +**dictionaries** are mappings that contain "named" entries with associated values. + +```py +person = { + "first_name": "John", + "last_name": "Doe", + "nationality": "Canada", + "birth_year": 1980 +} +``` + +Retrieving and setting elements: + +```py +person["first_name"] +``` + +```py +person["first_name"] = "Jane" +``` + +--- + +A **list** represents a sequence of objects + +```py +primes = [2, 3, 5, 7, 11] +users = ["Alice", "Bob", "Charlie"] + +products = [ + {"name": "IPhone 12", "price": 949}, + {"name": "Fairphone", "price": 419}, + {"name": "Pixel 5", "price": 799} +] +``` + +Determining the length + +```py +len(users) +``` + +Overwriting a list element + +```py +users[0] = "Andrew" +``` + +--- + +Retrieving list elements via their index (starting at 0): + +```py +users[0] +users[1] +users[-1] # last element +``` + +Appending an element + +```py +users.append("Dora") +``` + +Removing the last element: + +```py +users.pop() +``` + +Removing by index: + +```py +users.pop(0) +``` + +--- + +# Object references and mutations + +* What will be the value of `a` after this code has run? + + ```py + a = [1, 2, 3] + b = a + b.append(4) + ``` + +* An assignment (e.g. `b = a`) assigns a new (additional) **name** to an object. + The object in the background **is the same**. + +--- + +If the original should remain intact it may be copied or a derived version can be newly created based on it: + +```py +a = [1, 2, 3] +# creating a new copy +b = a.copy() +# modifying b +b.append(4) +``` + +```py +a = [1, 2, 3] +# creating a new object b based on a +b = a + [4] +``` + +--- + +- Some objects can be **mutated** (changed) directly + > e.g. via `.append()`, `.pop()`, ... + + Examples: `list`, `dict` + +- Many simple objects are **immutable** after they have been created. + However, they can be replaced by other objects. + + Examples: `int`, `float`, `str`, `bool`, `tuple` + +--- + +**tuple** + +- Area of application: similar to dicts + + ```py + point_dict = {"x": 2, "y": 4} + point_tuple = (2, 4) + date_dict = { "year": 1973, "month": 10, "day": 23} + date_tuple = (1973, 10, 23) + ``` + + Each entry in a tuple has a specific meaning + +- Behavior: similar to lists + + ```py + date_tuple[0] # 1973 + len(date_tuple) # 3 + ``` + +Unlike lists, tuples are immutable (no `.append` / `.pop` / ...) + +--- + +# Working with files + +A **file** is a sequence of bytes on a storage device + +Many file formats are a sequence of text characters +> e.g. the formats _.txt_, _.html_, _.csv_ or _.py_. + +The content of text files can be represented as strings (ASCII). + +Other file contents can be represented as byte sequences (binary). + +--- + +### Writing a text file + +```py +file = open("message.txt", "w", encoding="utf-8") +file.write("hello world\n") +file.close() +``` + +> The file is opened for writing (w). +> The character encoding will be UTF-8. + +### Reading a text file + +```py +file = open("message.txt", encoding="utf-8") +content = file.read() +file.close() +print(content) +``` + +> Standard mode: _reading_ (**r**) + +--- + +### File modes + +```py +# mode: text, append +open("file.txt", mode="ta") +``` + +- `t`: text mode (**default**) +- `b`: binary + +<!-- list-separator --> + +- `r`: reading (**default**) +- `w`: (over)writing +- `a`: appending + +--- + +### Open and the with statement + +```py +with open("todos.txt", encoding="utf-8") as file_obj: + content = file_obj.read() +``` + +The file will be closed automatically when the program leaves the indented block. + +### character encoding + +The default character encoding for text files depends on the operating system: + +```py +import locale +locale.getpreferredencoding() +``` + +> ASCII, latin1, UTF-8, etc + +Recommendation: Use UTF-8 (best support for special characters) + +--- + +# Parts of programs + +- programs + - code blocks + - statements + - expressions + +### Empty code blocks + +_empty_ code block via the `pass` statement: + +```py +# TODO: warn the user if path doesn't exist + +if not os.path.exists(my_path): + pass +``` + +--- + +### Statements across multiple lines + +a statement can span across multiple lines if we use parantheses: + +```py +a = (2 + 3 + 4 + 5 + 6 + + 7 + 8 + 9 + 10) +``` + +Alternative: _escaping_ newlines with `\` + +```py +a = 2 + 3 + 4 + 5 + 6 + \ + 7 + 8 + 9 + 10 +``` + +--- + +### Expressions + +_expression_ = something that produces a value (the value might be `None`) + +_expression_ = anything that can be on the right-hand side of an assignment (`=`) + +examples of expressions: + +- `(7 - 3) * 0.5` +- `(7 - 3)` +- `7` +- `round(3.5)` +- `x == 1` + +--- + +# Function parameters + +## Positional parameters and keyword parameters + +Calling `open`: + +- with positional parameters: + + ```py + f = open("myfile.txt", "w", -1, "utf-8") + ``` + +- with keyword parameters: + + ```py + f = open("myfile.txt", encoding="utf-8", mode="w") + ``` + +--- + +## Optional parameters and default parameters + +Some parameters of functions can be optional (they have a default value) + +> Example: For `open` only the first parameter is required, the others are optional + +The values of default parameters can be looked up in the documentation + +--- + +# Defining functions + +```py +def average(a, b): + m = (a + b) / 2 + return m +``` + +### Optional parameters and default parameters + +This is how we define default values for parameters: + +```py +def shout(phrase, end="!"): + print(phrase.upper() + end) + +shout("hello") # HELLO! +shout("hi", ".") # HI. +``` + +--- + +### Scope + +A function definition creates a new **scope**, an area where variables are valid + +In the following example there are two distinct variables named `m`: + +```py +m = "Hello, world" + +def average(a, b): + m = (a + b) / 2 + return m +x = average(1, 2) + +print(m) # prints "Hello, world" +``` + +--- + +### Scope + +Inside a function, outer variables may be read but not overwritten + +In other programming languages constructs like `if` or `for` usually also open a new scope - this is not the case in Python + +--- + +# Modules and packages + +**Module** : collection of Python objects that can be imported + +**Package** : collection of modules + +> packages are actually a special type of modules + +- `urllib` = package +- `urllib.request` = module +- `urllib.request.urlopen` = function + +<!-- list separator --> + +- `sys` = module +- `sys.path` = object + +--- + +Examples: + +```py +import module1 +from package2 import module2a, module2b +from module3 import object3a, object3b +from package4.module4 import object4a, object4b +``` + +```py +import os +from math import sqrt, pi +``` + +Short names: + +```py +import numpy as np +import matplotlib.pyplot as plt +``` + +> Importing everything from a module (usually not recommended): +> `from math import *` + +--- + +When importing _some_ packages, submodules will be imported automatically. + +Examples: + +```py +import os +import numpy as np + +os.path.join(...) +np.random.randint(10) +``` + +Counterexample - this will fail: + +```py +import urllib + +urllib.request.urlopen(...) +``` + +--- + +## Conventions for imports + +- all imports in a Python file _should_ be at the start of the file +- imports _should_ be split into three groups: + - imports from the standard library + - imports from other libraries + - imports within the project + +--- + +# Local modules + +we can import local Python files as modules + +example: local file _messages.py_ + +```py +import messages + +print(messages.message1) +``` + +we can create so-called _packages_ as folders + +example: folder _phrases/_, files _phrases/messages.py_ and _phrases/greetings.py_ + +```py +from phrases import greetings + +print(greetings.greeting1) +``` + +--- + +## Resolving imports + +Search order of imports: + +- directory of the Python script that was originally executed +- standard library +- external libraries + +Avoid name clashes with existing modules / packages! + +--- + +# NumPy + +Library for efficient data processing + +Data are stored in multidimensional arrays of numeric values which are implemented in an efficient way: + +- smaller memory use than e.g. lists of numbers in Python +- much faster execution of operations like element-wise addition of arrays + +Data can represent images, sound, measurements and much more + +Common import convention: + +```python +import numpy as np +``` + +--- + +# Pandas + +_Pandas_ is a data analysis library; it is based on _NumPy_ + +```py +import pandas as pd +``` + +### Series and DataFrame + +- **Series**: Collection of values for some keys (table column) +- **DataFrame**: Collection of associated series (table) + +--- + +# Plotting + +Basic (low-level) library for plotting: _matplotlib_ + +Higher-level interfaces: + +- _pyplot_ (contained in matplotlib, similar to matlab's plotting interface) +- _pandas_ plotting functions (based on pyplot) + +--- + +### Simple plot with pyplot + +```py +import numpy as np +import matplotlib.pyplot as plt + +x = np.array([0, 1, 2, 3]) + +y1 = x*2 +y2 = x**2 + +plt.plot(x, y1) +plt.plot(x, y2) +``` + +In Jupyter plots are shown automatically + +In a regular terminal / program: + +```py +plt.show() +``` + +--- + + + +--- + +### Pyplot: Configuration and Styling + +We'll create a plot that shows the sine and cosine functions in the interval from _0_ to _2$\pi$_ + +```py +x = np.linspace(0, 2*np.pi, 100) + +sin = np.sin(x) +cos = np.cos(x) +``` + +--- + + + +--- + +In the following examples we will show how to use **Cartopy** with **netCDF** ClimateData. + +--- + + + +--- + + + +--- + +# Working with various file formats + +Possibilities: + +- text files +- JSON +- CSV +- XML +- Python object files (via pickle and shelve) +- binary files + +--- + +## JSON + +JSON: popular and standardized data file format +can represent the fundamental Python datatypes (none, bool, int, float, list, dict) + +Saving JSON: + +```py +import json +data = ["one", "two", "three"] +jsonstring = json.dumps(data) +with open("numbers.json", mode="w", encoding="utf-8") as jsonfile: + jsonfile.write(jsonstring) +``` + +Reading JSON: + +```py +import json +with open("numbers.json", encoding="utf-8") as jsonfile: + jsonstring = jsonfile.read() +data = json.loads(jsonstring) +``` + +--- + +## CSV + +CSV is a file format which can hold tabular data; entries are separated by commas + +Example: + +```csv +ISO,Country,Capital,Languages +AD,Andorra,Andorra la Vella,"ES,FR" +AE,United Arab Emirates,Abu Dhabi,"AE,fa,en,hi,ur" +AF,Afghanistan,Kabul,"AF,tk" +``` + +Python libraries: + +- _csv_ (part of the standard libary) +- _pandas_ + +--- + +Writing CSV via pandas: + +```py +import pandas as pd +data = pd.DataFrame( + [ + ["CN", 9.6, 1386], + ["RU", 17.0, 144], + ["US", 9.8, 327], + ], + columns=["code", "area", "population"], +) + +data.to_csv("countries.csv") +``` + +Reading CSV via pandas: + +```py +import pandas as pd +data = pd.read_csv("countries.csv") +print(data) +print(data.values.tolist()) +``` + +--- + +Reading and writing CSV + +```py +import csv + +data = [ + ['code', 'area', 'population'], + ['CN', 9.6, 1386], + ['RU', 17, 144], + ['US', 9.8, 327] +] + +with open('countr.csv', 'w', encoding='utf-8', newline='') as f: + writer = csv.writer(f) + writer.writerows(data) + +with open('countr.csv', encoding='utf-8', newline='') as f: + reader = csv.reader(f) + for row in reader: + print(row) +``` + +--- + +Thank you for your attention<!--fit--> +=== \ No newline at end of file diff --git a/learning-python/Python.pdf b/learning-python/Python.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3456a506e9e9d4dbb46f8bbce8b4df8819d04923 Binary files /dev/null and b/learning-python/Python.pdf differ diff --git a/learning-python/README.md b/learning-python/README.md new file mode 100644 index 0000000000000000000000000000000000000000..af22d62d563341f353892321de6df9af297a585c --- /dev/null +++ b/learning-python/README.md @@ -0,0 +1,7 @@ +# learning-python + +This is the repository for the training Python + +You can find the slides [here](./Python.pdf). + +Presentation is [here](https://www.elic.ucl.ac.be/users/pbarriat/slides/Python.html) diff --git a/learning-python/assets/Figure_1.png b/learning-python/assets/Figure_1.png new file mode 100644 index 0000000000000000000000000000000000000000..2a5e598f6145805476e72027709613ca6b607764 Binary files /dev/null and b/learning-python/assets/Figure_1.png differ diff --git a/learning-python/assets/Figure_2.png b/learning-python/assets/Figure_2.png new file mode 100644 index 0000000000000000000000000000000000000000..0cf48fe5319b875d0cc929c4c9d5e8aabb4bfebf Binary files /dev/null and b/learning-python/assets/Figure_2.png differ diff --git a/learning-python/assets/Figure_2.py b/learning-python/assets/Figure_2.py new file mode 100644 index 0000000000000000000000000000000000000000..75dc24cfc0fda5636e980ecd22e9b9c9d42d15f5 --- /dev/null +++ b/learning-python/assets/Figure_2.py @@ -0,0 +1,24 @@ +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use("seaborn") + +x = np.linspace(0, 2*np.pi, 100) +sin = np.sin(x) +cos = np.cos(x) +plt.plot(x, sin, "C0--", label="sin(x)") +plt.plot(x, cos, "C1:", label="cos(x)") + +pi_multiples = np.array([0, 0.5, 1, 1.5, 2]) * np.pi +sin_points = np.sin(pi_multiples) +cos_points = np.cos(pi_multiples) +plt.plot(pi_multiples, sin_points, "C0o") +plt.plot(pi_multiples, cos_points, "C1o") + +plt.title("Trigonometric functions") +plt.xlabel("x (radians)") +plt.xticks(np.linspace(0, 2*np.pi, 5)) +plt.legend() +plt.axis("scaled") + +plt.show() diff --git a/learning-python/assets/Figure_3.png b/learning-python/assets/Figure_3.png new file mode 100644 index 0000000000000000000000000000000000000000..b4dd6cdb917ca0479fb463791994d78602e6a6ef Binary files /dev/null and b/learning-python/assets/Figure_3.png differ diff --git a/learning-python/assets/Figure_3.py b/learning-python/assets/Figure_3.py new file mode 100644 index 0000000000000000000000000000000000000000..fcfa6cb3b339b9c7444f7e6bd857603b3cf01528 --- /dev/null +++ b/learning-python/assets/Figure_3.py @@ -0,0 +1,60 @@ +# +# Input data +# +# We are going to use a netCDF file for testing the following code. +# The test file islocated in a dedicated online repository: +# https://nextcloud.cism.ucl.ac.be/s/H7XFSi8J4E8dnRK +# +# Download the netCDF prmsl.2000.nc : +# a classic (regular grid) pressure file +# + +from netCDF4 import Dataset +import numpy as np +import cartopy.crs as ccrs +import cartopy.feature as cfeature +from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER +from cartopy.util import add_cyclic_point +import matplotlib.pyplot as plt +import matplotlib.ticker as mticker + +my_example_nc_file = 'prmsl.2000.nc' +fh = Dataset(my_example_nc_file, mode='r') + +lons = fh.variables['lon'][:] +lats = fh.variables['lat'][:] +times = fh.variables['time'][:] +times_unit = fh.variables['time'].units +var = fh.variables['prmsl'] +var_units = fh.variables['prmsl'].units + +#fig = plt.subplots(figsize=(8, 6), dpi=102) +plt.axis('off') + +ax = plt.axes(projection=ccrs.Robinson(central_longitude=10.0)) +ax.coastlines() + +# Plot Data +data = np.squeeze(var[1,:,:]) +#cs = ax.pcolormesh(lons, lats, data, transform=ccrs.PlateCarree(), shading='auto') +lon = np.arange(0, 360, 2) +data, lon = add_cyclic_point(data, coord=lon) +cs = ax.contourf(lon, lats, data, transform=ccrs.PlateCarree(), transform_first=False) + +# Add Grid Lines +gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True, linewidth=0.5, color="grey") +gl.xlocator = mticker.FixedLocator(np.arange(-170,191,36)) +gl.ylocator = mticker.FixedLocator(np.arange(-90,90,15)) +gl.rotate_labels = False +gl.top_labels = False +gl.xformatter = LONGITUDE_FORMATTER +gl.yformatter = LATITUDE_FORMATTER + +# Add Colorbar +cbar = plt.colorbar(cs,orientation="horizontal") +cbar.set_label(var_units) + +# Add Title +plt.title('Daily Pressure at Mean Sea Level') + +plt.show() diff --git a/learning-python/assets/Figure_4.png b/learning-python/assets/Figure_4.png new file mode 100644 index 0000000000000000000000000000000000000000..0eea81ed7e00cb25675056117f9622d3e32d1b0c Binary files /dev/null and b/learning-python/assets/Figure_4.png differ diff --git a/learning-python/assets/Figure_4.py b/learning-python/assets/Figure_4.py new file mode 100644 index 0000000000000000000000000000000000000000..a4558a03fa69bd6f9e757f5a0e1a7ab23cfb1f07 --- /dev/null +++ b/learning-python/assets/Figure_4.py @@ -0,0 +1,75 @@ +# +# Input data +# +# We are going to use a netCDF file for testing the following code. +# The test file islocated in a dedicated online repository: +# https://nextcloud.cism.ucl.ac.be/s/H7XFSi8J4E8dnRK +# +# Download the netCDF prmsl.2000.nc : +# a classic (regular grid) pressure file +# + +from netCDF4 import Dataset +import numpy as np +import cartopy.crs as ccrs +import cartopy.feature as cfeature +from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER +from cartopy.util import add_cyclic_point +import matplotlib.pyplot as plt +import matplotlib.ticker as mticker +import matplotlib.path as mpath + +my_example_nc_file = 'prmsl.2000.nc' +fh = Dataset(my_example_nc_file, mode='r') + +lons = fh.variables['lon'][:] +lats = fh.variables['lat'][:] +times = fh.variables['time'][:] +times_unit = fh.variables['time'].units +var = fh.variables['prmsl'] +var_units = fh.variables['prmsl'].units + +#------------------------------------------------------------ +# Compute a circle in axes coordinates, +# which we can use as a boundary for the map. +# https://scitools.org.uk/cartopy/docs/latest/gallery/lines_and_polygons/always_circular_stereo.html + +theta = np.linspace(0, 2*np.pi, 100) +center, radius = [0.5, 0.5], 0.5 +verts = np.vstack([np.sin(theta), np.cos(theta)]).T +circle = mpath.Path(verts * radius + center) + +fig = plt.subplots(figsize=(6, 6), dpi=102) +plt.axis('off') + +ax = plt.axes(projection=ccrs.Orthographic(central_longitude=0.0, central_latitude=90.0)) +xlims = [-180,180] +ylims = [50,90] +ax.set_extent(xlims+ylims, crs=ccrs.PlateCarree()) +ax.set_boundary(circle, transform=ax.transAxes) + +ax.stock_img() +ax.coastlines("110m", linewidth=0.5, color="black") + +# Plot Data +data = np.squeeze(var[1,:,:]) +#cs = ax.pcolormesh(lons, lats, data, transform=ccrs.PlateCarree(), shading='auto') +lon = np.arange(0, 360, 2) +data, lon = add_cyclic_point(data, coord=lon) +cs = ax.contourf(lon, lats, data, transform=ccrs.PlateCarree(), transform_first=False) + +# Doing the gridlines we want +gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True, linewidth=0.5, color="grey") +gl.xformatter = LONGITUDE_FORMATTER +gl.yformatter = LATITUDE_FORMATTER +gl.xlocator = mticker.FixedLocator(np.arange(-180,181,18)) +gl.ylocator = mticker.FixedLocator(np.arange(-90,91,10)) + +# Add Colorbar +cbar = plt.colorbar(cs,orientation="horizontal") +cbar.set_label(var_units) + +# Add Title +plt.title('Daily Pressure at Mean Sea Level') + +plt.show() diff --git a/learning-python/assets/back.png b/learning-python/assets/back.png new file mode 100644 index 0000000000000000000000000000000000000000..0674657248db1242420acd99ec7d510b8f3236cd Binary files /dev/null and b/learning-python/assets/back.png differ diff --git a/learning-python/assets/garde.png b/learning-python/assets/garde.png new file mode 100644 index 0000000000000000000000000000000000000000..7c82359c3ac6126ffeed79a081ab2c75c00e19dc Binary files /dev/null and b/learning-python/assets/garde.png differ diff --git a/learning-python/assets/kroki-plugin.js b/learning-python/assets/kroki-plugin.js new file mode 100644 index 0000000000000000000000000000000000000000..f0baa0a5eb82d2e4f80f1398721ac8a69836a85a --- /dev/null +++ b/learning-python/assets/kroki-plugin.js @@ -0,0 +1,52 @@ +const { deflateSync } = require('zlib') + +const krokiLangs = [ + 'actdiag', + 'blockdiag', + 'bpmn', + 'bytefield', + 'c4plantuml', + 'ditaa', + 'dot', + 'erd', + 'excalidraw', + 'graphviz', + 'mermaid', + 'nomnoml', + 'nwdiag', + 'packetdiag', + 'pikchr', + 'plantuml', + 'rackdiag', + 'seqdiag', + 'svgbob', + 'umlet', + 'vega', + 'vegalite', + 'wavedrom', +] + +const entrypoint = 'https://kroki.io/' + +const marpKrokiPlugin = (md) => { + const { fence } = md.renderer.rules + + md.renderer.rules.fence = (tokens, idx, options, env, self) => { + const info = md.utils.unescapeAll(tokens[idx].info).trim() + + if (info) { + const [lang] = info.split(/(\s+)/g) + + if (krokiLangs.includes(lang)) { + const data = deflateSync(tokens[idx].content).toString('base64url') + + // <marp-auto-scaling> is working only with Marp Core v3 + return `<p><marp-auto-scaling data-downscale-only><img src="${entrypoint}${lang}/svg/${data}"/></marp-auto-scaling></p>` + } + } + + return fence.call(self, tokens, idx, options, env, self) + } +} + +module.exports = marpKrokiPlugin diff --git a/learning-python/assets/marp.config.js b/learning-python/assets/marp.config.js new file mode 100644 index 0000000000000000000000000000000000000000..c5a35bca5b0623dc640ce779365a6d00bf5dab64 --- /dev/null +++ b/learning-python/assets/marp.config.js @@ -0,0 +1,5 @@ +const marpKrokiPlugin = require('./kroki-plugin') + +module.exports = { + engine: ({ marp }) => marp.use(marpKrokiPlugin) +} diff --git a/learning-python/assets/prmsl.2000.nc b/learning-python/assets/prmsl.2000.nc new file mode 100644 index 0000000000000000000000000000000000000000..eb3f88879fc1167dd80a2700c00221c74a61ddbc Binary files /dev/null and b/learning-python/assets/prmsl.2000.nc differ diff --git a/learning-python/assets/python.svg b/learning-python/assets/python.svg new file mode 100644 index 0000000000000000000000000000000000000000..e771ee25415b2151239834d1abca3926a8f9aea5 --- /dev/null +++ b/learning-python/assets/python.svg @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg width="800px" height="800px" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M31.885 16c-8.124 0-7.617 3.523-7.617 3.523l.01 3.65h7.752v1.095H21.197S16 23.678 16 31.876c0 8.196 4.537 7.906 4.537 7.906h2.708v-3.804s-.146-4.537 4.465-4.537h7.688s4.32.07 4.32-4.175v-7.019S40.374 16 31.885 16zm-4.275 2.454c.771 0 1.395.624 1.395 1.395s-.624 1.395-1.395 1.395a1.393 1.393 0 0 1-1.395-1.395c0-.771.624-1.395 1.395-1.395z" fill="url(#a)"/><path d="M32.115 47.833c8.124 0 7.617-3.523 7.617-3.523l-.01-3.65H31.97v-1.095h10.832S48 40.155 48 31.958c0-8.197-4.537-7.906-4.537-7.906h-2.708v3.803s.146 4.537-4.465 4.537h-7.688s-4.32-.07-4.32 4.175v7.019s-.656 4.247 7.833 4.247zm4.275-2.454a1.393 1.393 0 0 1-1.395-1.395c0-.77.624-1.394 1.395-1.394s1.395.623 1.395 1.394c0 .772-.624 1.395-1.395 1.395z" fill="url(#b)"/><defs><linearGradient id="a" x1="19.075" y1="18.782" x2="34.898" y2="34.658" gradientUnits="userSpaceOnUse"><stop stop-color="#387EB8"/><stop offset="1" stop-color="#366994"/></linearGradient><linearGradient id="b" x1="28.809" y1="28.882" x2="45.803" y2="45.163" gradientUnits="userSpaceOnUse"><stop stop-color="#FFE052"/><stop offset="1" stop-color="#FFC331"/></linearGradient></defs></svg> \ No newline at end of file diff --git a/learning-python/assets/python_logo.png b/learning-python/assets/python_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1cbf71a855276f690fc1aff722993843f79b7bb2 Binary files /dev/null and b/learning-python/assets/python_logo.png differ diff --git a/learning-python/assets/tum.css b/learning-python/assets/tum.css new file mode 100644 index 0000000000000000000000000000000000000000..08d289362d7399b163db43fbc0e37f9b4a6c9397 --- /dev/null +++ b/learning-python/assets/tum.css @@ -0,0 +1,55 @@ +/* @theme tum */ + +@import 'default'; + +section { + /*background-color: #fff; + color: #000; + background-image: url('images/TUM_Logo_blau_rgb_s.svg'); + background-repeat: no-repeat; + background-position: right 40px top 40px; + background-size: 8%;*/ +} + +section.lead { + /*background-image: url('images/TUM_Uhrenturm.png'); + background-position: right; + background-size: 45%;*/ +} + +section h1, +section h2 { + color: #1f315c; +} +section a { + color: #5fb2e6; +} +section footer, +section::after { + color: #9cb7d4; +} + +section.invert { + background-color: #003359; + color: #fff; + /*background-image: url('images/TUM_Logo_weiss_rgb_s.svg');*/ +} + +section.lead.invert { + /*background-image: url('images/TUM_Uhrenturm_w.png');*/ +} + +section.invert h1, +section.invert footer, +section.invert::after { + color: #fff; +} + +section.invert a { + color: #e37222; +} + +/* Add "Page" prefix and total page number */ +section::after { + content: attr(data-marpit-pagination) ' / ' attr(data-marpit-pagination-total); +} diff --git a/learning-python/compile.sh b/learning-python/compile.sh new file mode 100755 index 0000000000000000000000000000000000000000..605c32557ecc6b6896717aa3afe9a92ebe8e0e92 --- /dev/null +++ b/learning-python/compile.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# +# PY Barriat, September 2024 +# +# Download and install marp (MarkDown slides extension) from here: +# https://github.com/marp-team/marp-cli/releases +# +# Install npm (needed for mermaid: nice extension to make diagramm) +# npm i +# sudo apt install npm +# + +rm -f ./Python.pdf ./Python.html + +npx marp --allow-local-files --theme ./assets/tum.css -c ./assets/marp.config.js ./Python.md -o Python.pdf +npx marp --template bespoke --bespoke.progress --allow-local-files --theme ./assets/tum.css -c ./assets/marp.config.js Python.md -o Python.html