From e6d7738e256a48780a6a1a4156152326c8816f9a Mon Sep 17 00:00:00 2001 From: "Alan M. Lewis" Date: Tue, 27 May 2025 17:04:59 +0100 Subject: [PATCH 1/7] Organise notebooks into website content --- _config.yml | 8 +- _toc.yml | 26 + lessons/advanced_libraries.md | 3 + lessons/advanced_libs/Asprin.mol | 47 + lessons/advanced_libs/Intro_to_ASE.ipynb | 402 ++++++++ lessons/advanced_libs/PiC_scipy.ipynb | 330 +++++++ lessons/advanced_libs/RDKit_drawing.ipynb | 254 +++++ lessons/advanced_libs/ethane.xyz | 11 + lessons/advanced_libs/ethane_new.xyz | 10 + lessons/basics.md | 4 +- lessons/common_libraries.md | 3 + .../common_libs/Introduction to NumPy.ipynb | 579 ++++++++++++ .../Matplotlib_Documentation.ipynb | 162 ++++ .../common_libs/NumPy_axes_operations.ipynb | 738 +++++++++++++++ lessons/common_libs/Venus data.csv | 79 ++ lessons/common_libs/Vit C in Orange Juice.csv | 121 +++ lessons/common_libs/intro_to_pandas.ipynb | 327 +++++++ lessons/common_libs/periodic_table.csv | 119 +++ lessons/common_libs/periodic_table_out.csv | 119 +++ .../python-in-chem_pyplot_basics_SM.ipynb | 466 ++++++++++ lessons/files.md | 3 + lessons/files/elements.csv | 4 + lessons/files/gas_const.txt | 1 + lessons/files/molecule.txt | 1 + lessons/files/reading_files.ipynb | 291 ++++++ lessons/files/spectrum.dat | 9 + lessons/files/writing_files.ipynb | 257 ++++++ lessons/loops_functions/For_Loop_Lesson.ipynb | 381 ++++++++ .../PyinC_while_loops_WIP.ipynb | 182 ++++ .../loops_functions/functions_and_scope.ipynb | 471 ++++++++++ lessons/manipulating_variables.md | 3 + lessons/organising_code.md | 3 + lessons/variables/Conditions.ipynb | 869 ++++++++++++++++++ lessons/variables/Variable_data_types.ipynb | 425 +++++++++ .../variables/mathematical-operators.ipynb | 221 +++++ 35 files changed, 6926 insertions(+), 3 deletions(-) create mode 100644 lessons/advanced_libraries.md create mode 100644 lessons/advanced_libs/Asprin.mol create mode 100644 lessons/advanced_libs/Intro_to_ASE.ipynb create mode 100644 lessons/advanced_libs/PiC_scipy.ipynb create mode 100644 lessons/advanced_libs/RDKit_drawing.ipynb create mode 100644 lessons/advanced_libs/ethane.xyz create mode 100644 lessons/advanced_libs/ethane_new.xyz create mode 100644 lessons/common_libraries.md create mode 100644 lessons/common_libs/Introduction to NumPy.ipynb create mode 100644 lessons/common_libs/Matplotlib_Documentation.ipynb create mode 100644 lessons/common_libs/NumPy_axes_operations.ipynb create mode 100644 lessons/common_libs/Venus data.csv create mode 100644 lessons/common_libs/Vit C in Orange Juice.csv create mode 100644 lessons/common_libs/intro_to_pandas.ipynb create mode 100644 lessons/common_libs/periodic_table.csv create mode 100644 lessons/common_libs/periodic_table_out.csv create mode 100644 lessons/common_libs/python-in-chem_pyplot_basics_SM.ipynb create mode 100644 lessons/files.md create mode 100644 lessons/files/elements.csv create mode 100644 lessons/files/gas_const.txt create mode 100644 lessons/files/molecule.txt create mode 100644 lessons/files/reading_files.ipynb create mode 100644 lessons/files/spectrum.dat create mode 100644 lessons/files/writing_files.ipynb create mode 100644 lessons/loops_functions/For_Loop_Lesson.ipynb create mode 100644 lessons/loops_functions/PyinC_while_loops_WIP.ipynb create mode 100644 lessons/loops_functions/functions_and_scope.ipynb create mode 100644 lessons/manipulating_variables.md create mode 100644 lessons/organising_code.md create mode 100644 lessons/variables/Conditions.ipynb create mode 100644 lessons/variables/Variable_data_types.ipynb create mode 100644 lessons/variables/mathematical-operators.ipynb diff --git a/_config.yml b/_config.yml index a40ece5..f4c73a3 100644 --- a/_config.yml +++ b/_config.yml @@ -7,9 +7,15 @@ author: The Python in Chemistry Community # Force re-execution of notebooks on each build. # See https://jupyterbook.org/content/execute.html +only_build_toc_files: true execute: execute_notebooks: force +launch_buttons: + notebook_interface: classic + binderhub_url: "https://mybinder.org" + colab_url: "https://colab.research.google.com" + # Define the name of the latex output file for PDF builds latex: latex_documents: @@ -42,4 +48,4 @@ sphinx: html_theme_options: logo: image_light: ./logo/logo-light.png - image_dark: ./logo/logo-dark.png \ No newline at end of file + image_dark: ./logo/logo-dark.png diff --git a/_toc.yml b/_toc.yml index 3a14203..15d8b8c 100644 --- a/_toc.yml +++ b/_toc.yml @@ -10,6 +10,32 @@ parts: sections: - file: lessons/basics/write_run_python.md - file: lessons/basics/notebook.md + - file: lessons/manipulating_variables.md + sections: + - file: lessons/variables/Variable_data_types.ipynb + - file: lessons/variables/mathematical-operators.ipynb + - file: lessons/variables/Conditions.ipynb + - file: lessons/organising_code.md + sections: + - file: lessons/loops_functions/For_Loop_Lesson.ipynb + - file: lessons/loops_functions/PyinC_while_loops_WIP.ipynb + - file: lessons/loops_functions/functions_and_scope.ipynb + - file: lessons/files.md + sections: + - file: lessons/files/reading_files.ipynb + - file: lessons/files/writing_files.ipynb + - file: lessons/common_libraries.md + sections: + - file: lessons/common_libs/python-in-chem_pyplot_basics_SM.ipynb + - file: lessons/common_libs/Matplotlib_Documentation.ipynb + - file: lessons/common_libs/Introduction to NumPy.ipynb + - file: lessons/common_libs/NumPy_axes_operations.ipynb + - file: lessons/common_libs/intro_to_pandas.ipynb + - file: lessons/advanced_libraries.md + sections: + - file: lessons/advanced_libs/Intro_to_ASE.ipynb + - file: lessons/advanced_libs/PiC_scipy.ipynb + - file: lessons/advanced_libs/RDKit_drawing.ipynb - caption: Teaching Python in Chemistry Meeting Blogs chapters: - file: 2025-meeting diff --git a/lessons/advanced_libraries.md b/lessons/advanced_libraries.md new file mode 100644 index 0000000..704474d --- /dev/null +++ b/lessons/advanced_libraries.md @@ -0,0 +1,3 @@ +# Advanced Libraries + +This section gives a quick introduction to a few chemistry-specific libraries. diff --git a/lessons/advanced_libs/Asprin.mol b/lessons/advanced_libs/Asprin.mol new file mode 100644 index 0000000..856dab1 --- /dev/null +++ b/lessons/advanced_libs/Asprin.mol @@ -0,0 +1,47 @@ +2244 + -OEChem-04102511032D + + 21 21 0 0 0 0 0 0 0999 V2000 + 3.7320 -0.0600 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3301 1.4400 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5981 1.4400 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 2.8660 -1.5600 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5981 -0.5600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4641 -0.0600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5981 -1.5600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3301 -0.5600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4641 -2.0600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3301 -1.5600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4641 0.9400 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.8660 -0.5600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.0000 -0.0600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.0611 -1.8700 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8671 -0.2500 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4641 -2.6800 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8671 -1.8700 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.3100 0.4769 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1.4631 0.2500 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1.6900 -0.5969 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3301 2.0600 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1 5 1 0 0 0 0 + 1 12 1 0 0 0 0 + 2 11 1 0 0 0 0 + 2 21 1 0 0 0 0 + 3 11 2 0 0 0 0 + 4 12 2 0 0 0 0 + 5 6 1 0 0 0 0 + 5 7 2 0 0 0 0 + 6 8 2 0 0 0 0 + 6 11 1 0 0 0 0 + 7 9 1 0 0 0 0 + 7 14 1 0 0 0 0 + 8 10 1 0 0 0 0 + 8 15 1 0 0 0 0 + 9 10 2 0 0 0 0 + 9 16 1 0 0 0 0 + 10 17 1 0 0 0 0 + 12 13 1 0 0 0 0 + 13 18 1 0 0 0 0 + 13 19 1 0 0 0 0 + 13 20 1 0 0 0 0 +M END diff --git a/lessons/advanced_libs/Intro_to_ASE.ipynb b/lessons/advanced_libs/Intro_to_ASE.ipynb new file mode 100644 index 0000000..3256896 --- /dev/null +++ b/lessons/advanced_libs/Intro_to_ASE.ipynb @@ -0,0 +1,402 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "1639ee9d-703b-4c01-9a65-45d2a84cf4b0", + "metadata": {}, + "source": [ + "## The Atomic Simulation Environment, ASE" + ] + }, + { + "cell_type": "markdown", + "id": "24eee375-0afd-4f6c-9fca-1c5268956e59", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- For loops\n", + "- Matplotlib" + ] + }, + { + "cell_type": "markdown", + "id": "4f7ccf4f-156f-4963-97e5-81191e2d07a6", + "metadata": {}, + "source": [ + "## Learning Outcomes" + ] + }, + { + "cell_type": "markdown", + "id": "4424d3e8-1280-45e1-97c8-86fb203059ce", + "metadata": {}, + "source": [ + "The Atomic Simulation Environment __[(ASE)](https://wiki.fysik.dtu.dk/ase/)__, is a python library containing tools to undertake, manipulate and analyse molecular simulations.\n", + "\n", + "The ASE supports several external **calculators**, including LAMMPS, QuantumEspresso and Orca (amongst many others) and also contains a number of inbuilt calculators. A list of external and inbuilt calculators is __[here](https://wiki.fysik.dtu.dk/ase/ase/calculators/calculators.html)__." + ] + }, + { + "cell_type": "markdown", + "id": "5c80ae51-0086-46bb-abe9-c4f2a9b8aefc", + "metadata": {}, + "source": [ + "### Atoms objects" + ] + }, + { + "attachments": { + "e1de4673-c8c2-46ca-ae6e-5f5ee70d7054.png": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAZ8AAAE/CAYAAACZ/s56AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAAB3RJTUUH5AgFFyIxqaq7KAAAAAFvck5UAc+id5oAAEhVSURBVHja7b1pkGTXeab33so9a+1qdANoACJAEiL2hQ2KhChBECfkgaUwJY9ED2kqFEOOBjIkkhJJECDZWBoWwRFnxJkYSiM6FLY8YQfHHjv8Y8AICxRMGqI0UyDUMEkBjQYaANFAd1fvXVmV+3aPf2SfWydPnnOXzJtLZb5PxI2sXKo6q/qefO73ne98xzl48BAIIYSQUTI37jdACCFk9qB8CCGEjBzKhxBCyMihfAghhIyc5LjfACHj5ksH7xIJ5b576WhfOloAmsrRAFAHUAVQAvA3Bw854/4dCNlpUD5kJnn84F3C9pwUkcC2fFLYlk/q0pEGkAXwXx68S0gRHaKICAkF5UNmBj/hmHDQGSBzlw7H55hDR1o/e/AuUQZQAPAWRUSIFcqHTD1RpaMzB/NAEdqtRMooc/AuUQBwlhIipAfKh0wtg0pHRUY/CWzPCSW1WzlPJL+W/3ji4F3iPIAmJUSIB6vdyFQSp3gkqoAS2tfySF465JxQBkAewG4AuSG8J0J2Kox8yFQxDOlIZDpNnefRhaSLSEqoBWAegHvwLnEKwCqjIDLjMPIhU8MwxSOxFRvohQc2CeUAXAagwCiIzDiUD5kKRiEewL/izSQlVUayRDsLYBHAeQqIzDCUD9nxjEo8Oo72tSkakrfqHJGMguYBnKSAyIxC+ZAdzSjFE3WSxiQiKSGZissDeIMCIjMI5UN2LOOIeITl6yDUqEifC8oDeJECIjMG5UN2JAOJx3F6jwgI9EoozJsxzQepAvoRBURmCJZakx1H3+KRkgmSjbD/eFU0JgnB537XW0F3QUIK2z3lCJkFGPmQ6cdxgLm5zpFIdI5kcvtIJDrPBchJKIer3TcdgFlAeqGCKiBGP2RWoHzIjiJy1CPTalI4mQyQy20fmQyQTgOpVLeEDAJS2+aoAnK1r00CMgnJ1JgUoIDIbMC0G5leZMSTSHTkksl0btPpzmNCAK0W0GwCjUbnaLWAdnv7Z1xKwdminqAIyPS88a1iuyqO5iGzACMfsmOIFPVI8SSTHdksLADLy8DevcAVVwBXXtk59uwBVlaA+fmOnJLJ7hTcJUwRjukQhvth0nPAdhQEMPoh0w8jH7IjiCwemWpLpTriWVkBVlc7x9JS57lGAyiXgYsXO9IBOpGOEJ1oSApICKtw9CjH9niQeLy3Pu4/NCEjgvIh04mMevL57Yjn6quByy8Hdu3qyKdWA86f70RGrrudems2O9/vugDsUU7YI2heSI9+JD86eJe4gw1IyZRC+ZDpQo160mkgm+1EPVdeCfzUTwHXXtuRUSoFbG11Um2tVicCKpeBSqXzva0W4DgQl6IedZ8e9et+JBSUmiNkFuCcD5l4+q5wS6U6cznLy8BllwH79nWOa6/tzPvs3dtJwy0sbBcjJBI98z1+smkrRz8yslXISTj3Q6YVRj5k+pApNznnk893BLO42BFRPt+paKtWt9f96KXVl+7rEU8b/tFPG71SChKTKiBCZgXKh0w0j/YT9cgOBVJCQOcx1+0IJ5vtzOuUSp371ep2mbXreq+1SccmmDBiCpIRBURmBabdyEQT6QTVOxS47vYaHlnVduECcPIksL4OnD4NnD0LFAqd5+v1zutdtxONCGGVi0kkYcQUdJhg6o1MI4x8yPQgIx5ZLu26HaEUix3xpNOdCrdcrvN4odCRz/nzneKDarUjn3YbwnWtMgkbDdmiHj8x0TJkVqB8yPQhRGdOp9HoCGVrqxPlNJvAxkYnFddud6S0udmJhhT5uO02WkKgdSnyaaFbFPr9MIcpHWeqoCNkVqB8yMTyB4Okm2TKTcpHFhjk8520XKvViYLK5c7cT6UC1OtwWy24rou2FI8h9TaoiPwiH0JmBcqHTCypfr9Rptza7U56DdiOglKpjnyknOr1joQaDYhmE26rhabroilEaLG0gMAIyfYa9fCDC07JtEH5kOlCzvu4bie6kV9L0ci+bbKpaLvduW210G630XTdTsoN2L7FtjiiiEb/nqCD8z1klqB8yMTS94exLiAZBcl+bVI+rtspqb6UZmsp4mlr6TZbFGOTkEk4fhJjyo3MGpQPmVjkh3bfO3xKwchbvVO1EBCXCgvUSKetRDymwxbd6M+F+T55y6iHzBqUD5lY5CS83OcmEupW2EL0iMcrf1Yr2pR5Hlu6rBXiMH2/X/qOUQ+ZRSgfMrHID2h1l8/ISPFcahAqW9l0SUVJsQVFL2EE4yca08Goh8wilA+ZWOSHcwLdW05HRohQ/deiyCeugwtLyaxC+ZCJpXnpkC12pITCIJRbm3hMAgo7b6Me8n32Kx9CZhHKh0ws8kNdptwEtud//KIgfWdRNdXm14ctaI5Gika99Tualq/Vn03IrEL5kImlDiCDbvkk0C0gFdM21VG2PbCVREc9dOnYJMR0G5llKB8ysdQAZLGddtOr36R8HHSn2fRN2uJMu+nRTxPhIyP1OUY9ZNahfMjEUgaQx3bkk0SvfKSATPKJK/KRX9simCa6RdQ0PD6oeNhah0wb3M+HTCzfPXjIqQNoXDqaPkcr4HmbIGyFA02fx4P+vaDXMd1GCCMfMuHU0Il8ZCQj53zUhae2tJtf0UFQ2s1vzseWdvOTnCoeyocQyodMOFVsn6RSPn7rfkzyUSUUJJ8wBQc2sQRFQ2weSsg2lA+ZaLawvbWCi84JG6XizbZddVzyUb/WU4MN5Rikuo3zPWQa4ZwPmWj+v4OHnCo66be6djQsRxPh5okaPo8Ffa9JMrafy67VhPTCyIdMPCVsz+u4MM/7qEQpt5Zfm7ZGCLPINExxA8uqCemF8iETz0V0TlSBzgd5Et3y8Uu9meQzrDkfU/QzaMTDlBuZVph2IxPP2wcPOSV0ig9q6E7BNQKOZsTHg9JuDcOt6WeywIAQfxj5kB1BAZ0Ix0WnAEFPvfktNvUrOrD1d4vS4cB0MNVGiD+MfMiO4PSl6KeC7QioDnMRghoRBUVH/URGQUdc4mHKjUwzjHzIjuE8gN3YnvdR536A7rmfsPM+cUY+cTYLpXjItMPIh+wYqgcPOZvo9HyrwjwH5BcN2SKiMOXb+vfpr+XGcIREg/IhO4riwUNOEdvpN11CNhnpovFLyYURlno/7k3hGPWQWYBpN7LjOA9gBZ29ftTiA79eb2HW+4Qpt9a7UzPaIaQ/GPmQHUf24CFnA53Fp2V0oiC1EKGKTlTiFwn1e6hFBcMQD6MeMitQPmRHkjt4yClgW0B6Ck6fD6ohODUXVj7DWsND8ZBZgvIhO5ZFTUD6PJBNROrh95j+nEy1DSPNRvGQWYPyITua3ZcEVIRdQmq0YypOMEVE8lau+RlmtwKKh8wilA/Z8ey7NAfkJyBTJOQnIhnpxF3JpkPxkFmF8iFTwbsuCWgLHQHpxQi2lJwqIT29NuxKNoqHzDKUD5kabjl4yCmjEwHJKCiMhOSanVEuFKV4yKzDdT5kqrjj4CHnRwfvEnKNjtx620Xv+h/1PkDpEDJKKB8ydcgP+B8dvEsA240+dbmMenEoxUPINpQPmVp0CY37fRBCtqF8yNQzLglROoTYoXzIzDAqCVE6hARD+ZCZQ5XD7/7uT4n79+4d6OeJX/1V3HnnoxQOIRGgfMjM86cnTuDUqVN4/fXX8eMf/xg//OEPkfvOd4yv/R9On4brujh37hzefPNNvPjiizh06NC4fwVCdhyUDyEGfFJnwnEcOE7naXlLCIkGF5kSQggZOZQPIX3C6IeQ/qF8CEFHIJQIIaOD8iFEoV8Bra0d4G7ahESA8iFkABgtEdIflA8hA0IBERIdyocQQsjIoXwIUQgbxbBAgZDBoHwIuUQYmQghIn8PIaQXyoeQAaGACIkO5UMIIWTkUD6EgNELIaOG8iEzDedwCBkPlA8hfSIr3igsQqJD+RByCUqEkNFB+ZCZh9IhZPRQPoQoRFlkSgjpH8qHkIio4uGcDyH9QfkQQggZOZQPIegvgmHEQ0j/UD6EEEJGDuVDiEI/0Q8jIEKiQ/kQokGZEDJ8KB9CCCEjh/IhpA8YHREyGJQPIZeIOn8jX0sRERIdyocQjX4ERAiJBuVDCCgRQkYN5UMIIWTkUD6EREDffA5g1ERIP1A+hCj0W3RACIkG5UPIJdjbjZDRQfkQ0gcUDyGDQfkQEgHO+RASD8lxvwFCxo0qj6uvvhpXXXUVhHhBCCHgui7a7bZ3+61vtdBut9FsNtFoNLC8vDzut0/IjsQ5ePDQuN8DIWPhne98WczNzXnyEUJ4h+u6XYcqoFar5d02m020Wi00Gg3U63UsL3+cYRAhIWDkQ2aK669/VSSTSczNzQHIeY/7icd1XTiO493qx9zcHObm5pBIJFAu/wdRr9dRrVZx1VW/QxERYoHyITPBTTf9RCSTSThOvmeORpWOEMIoGB3T3I98TArpzJn/SVSrVVx77acoIUI0KB8y1dx885silUphbi57KdrZRo12pHRc1zX+HPka+XUikfAek1GPlJd6AMBbb/1bUalUcOONX6CECLkE5UOmkp/+6aNifn4eiUQO6ryORJeEjHxMgpKRjCop9TF5K4Xkui4SiQSSyWSXhF555Y/FDTc8SAERAsqHTCG33fa2SKeXkEgkelJnavSii0fdIsGUdjM9LiWkzgfJOSAZEUkRZTIZHDnyL0WpVML73vcEJURmGq7zIVPFnXeeFNlsFqlUyvvgTyQSXvQjb21ikV9LbMLxE5F+qO8jlUohl8vh+ecfE339goRMCZQPmRr27z8lMpkMkslkj3Rs4vETkC4h9WvT834RkiqhVCqFTCaDtbUDFBCZWSgfMhXcdddpkU6njdKxiUHF1qUg6HU2Aen/lh4NJZNJpNNp/M3fPEwBkZmE8iE7nrvuOi1kms0vuhlWGxzTzw2TlpNR0Pe+9zkKiMwclA/Z0ejisUU8JsLISC1QUG9Nr7H9XNN9XUDf+c6nKSAyU1A+ZMfy3veue90KdOlEwfZ6XSq2SjnT87Z/R31/uoC+/e3foYDIzED5kB3JHXecMKbaAP8N4cJ2LzCJRt43YXvchikNl0ql8NRT91NAZCbgOh+y47jppp+IVGq+RzpBqHLSF4wC/pGOfhsm+jE9b3tfUkCEDMJv/uaKkJ061Oa39Xod9XodtVoNW1tbOHz4urGvM6N8yI4jm80aIx6JbQ5GT82pWyao9+XX6s/yE4/t0LHtBaRHQU89db/48If/fOwfDmTyeeCBay61j5rraoqrd11Pp9PIZDLe8YEPnBeVSgXFYhFvvnnzWM41yofsKG699S2RSGSNJdQ2HMfxugwkk0mog7XdbnvbIQDwHpNfh5GLLTVnen3Y+SAKiPjx4IM3iFQq1bMdSLvd9sSjpnRtywDm5uZw/fWvimKxiDNnzkCIXxnZOUf5kB2FFIcp2jEJSF1Tk81mkc/nkclkkE6n4boums0myuUyyuUyAHhXjVJA8mfbesFFiYRMAlK/HmY5OJkOvvjFW0Q6nTae/7I3oV/Xdtshz8Otre+JSuVDIzkJKR+yY7j11rfE3FzGKh49qpCVZOl0GgsLC1heXsbi4iJyuVxX5FMqlXDx4kUIIbxUhW2DuX4EpL5PPSrSUX83Rj9E8tnPXi+Wlpasz6sdPEzNcvU2T8lkEq1Wy8sEyIuzzoXXM+LixYuYn//HQz33OMNJdgyyUaiKrSpNDsZkMon5+Xns2rULq6uryOfz3sS+4zhIJpNYWVnBysqKFxXJfydqVOMXIYWNkgjROXDgdl/xSPS5Q72a0rT5od78NpVKIZvNYnFxEVtb/36oJyTlQ3YEN974hvBbj2NKZc3NzSGbzWJhYQErKytQc+Q6S0tLyOVy2N7ldPtnqeLwE4n6XBTZ+EmHpdezzeOP7xfJZLQEla2VlK3jhtp7UI2E8vk8zp37n4d2/lE+ZEdgi3psH+iyyCCVSnnRjt98iuu6kE1JbSk3k4T0vPmgc0KMfojk8cf3Rz4ZbAU4fs1z9aa7MmOQTCaRzWZx/Pg3h3JSUj5k4nnXu450RT1hCwDm5uYgm40GXT3KtREmuURJoZkk5fc+bbufqjD6mT0ee+y9ff2fm6Jq21yjeqEmb/Uu7HIfqldf/Xrs5yDlQyaeRCLhfR0lepDzNqlUyro9tvpzZYlqu932rQryqxwKEyUFRUVktjlw4HbRb9WjKWr3S/Xq55xNQOl0Gi+88ESsJyflQyYev11I/SIT+XW1Wg0sYa7VaiiXy6jX62g2m0YB+UVEtn/bL/IJE/WQ2eL3f/9dked4VGxRT5R0sIqahkun07HuQUX5kInm6qt/JILmYGySkG1FZPm0jWq1io2NDZRKJVSrVW9VeFAEFBT1BL3OJikyuywvLw/0/Wr3jqB0cVQJyWKcuARE+ZCJRq7HCYp09A/2druNZrOJWq2Gzc1NFItF1Gq1rvSb67poNBq4cOECCoUCtra2UK/X0Wg0esQTJLwwzwWl3tTFfjqc95l+Hn745r7TbSryZ0S5WLKJSP2ZcS+C5iJTMtHYoh7bYNBz2rVazSsmqNfrXjm1EALVahWlUgmbm5vY3NxEpVIJHflEEUyU+2R2SafTsfwcuVRAvRCLei6bLvaA7fG4tnZA3H33kwOZiPIhE486EIDuwWW7ElM/zGUUVK1WIVuTqI9Vq1VPPI1GwxPPoPLpJzIis8nnPvfTIq6u5vKizHR+yfM67Pk9zPlIyodMNOqHtd55GoA18lFf22q10Gg0UK1WPXGpj6tHq9Xqinr022EejHxml7iiHqD7Yk2XjX4eh5WRSUKDRj+UD5lo9FQb0LtQTn+9jr6ITh2YUjaqdIIGYlgR2QY6ox6i8s/+2ZWxzPWoqBdNQYdNRsM+RykfMrEsLv61cN2lrjkewC4fU7sak4zUaMo0EINu/QQUJUJSX8uoZ3bJZDKxTuTLlLJ+MaVut2C6DSOnOM9TVruRiSZsNOH3uIxqms1mT5pNDlJ9nieMRPwGatR0HeUzu8zNzcUaWch0snpe6+e4LhxT5G869PN0kLJrRj5kYlE/nNXdSGWhgelqMWiBnW2dUFAkE1VKfuk2k+TIbKOem4NEQa1WC+Vy2XhhpaeYTelm09fqY3FeJFE+ZGJRP6xNuzDKryW2/lW2nmp+1Wd+UYwtJ26LfoKeZ9Qzu3z0owtCnguyGMav6s1PTM1m01sorcvHlmIzRUam18vbOKF8yMQiT3h9kyy/BW9hW4uEKXsOM+9jS7mFERULDYhMucnzXDbENV1Uyderz8tzuF6vo1KpoFareS2ibFGOfM7vNaaDBQdkZqjX6z3bIZgGp44p8tGjHr8Fn6aIxRT5+EU2piIG02OMemYbWfIvtwzR5QLAWOYsH3fdThspdT5T3lcPXTZhvtaPuM9VyodMLHNzH3ba7WeFOhjVOR/Av9otTNTjF/3YUm+26CeMrPTXk9lGprRk53a5u6ipma7pvNXncmxRTZjH9dfoc0ZxQ/mQiabVanUNRtd1u+6H2VZ7GGm3sOsn/NJyhMgPdykfUzGN3zYepnkbk1R0uQRFRPpr2eGAzBzNZrNrzscv8gHil08/4vFLs7HIgKjID3d5Xutr2gC7fPwKB2wS6ecYRsoNoHzIhKPmwxOJRE85apzysZVdh5nzCRMJMd1GdOr1urfIVAjRVWAjGVQ+gx7DOl8pHzLR1Ot1Tz4y8lFb5cQln0EKDqKIh0UGREVu4SHPbznnA2z3JwRgPUdtaTdVQuqhFyTI+2qxgt7rcFhQPmSiyWZ/w2k2/6NQB6ffIlPAX0BxRz6jEs+HP/zn8Tb/IhNBuVxGNpvtkc+gkY8p+jHJJUhOw7xQonzIxNNsNrvW+fhFPkBwtduw53xsbUqYbiM6L7xwpXPPPVtCboGgykffy0qes7bzsN/IR5eR/HrY5yvlQyaeer3etYePST5qikK+zlSmGrbDga3cOkr0o/eLI8REtVr19t+RW1Wb0sl+kU9U+ejSMUlo2FA+ZOIpl8tdxQZycKq5cZUo8z79tNjxE5CpLcmg1W1MuU035XLZ63SQTCa9OU7bLr7DlI/sjhAW7udDppp9++53Ll78XwSwHfnIA4A19Raly0G/BQdBkQ/LqkkQm5ubSCQScF0XqVTK2uXANC856JyPFI48hlndpkP5kB1BtVoFgJ5J2X56vEVZ6xN1kameaqN4SBAnT97pZDIvCyGEt7RA3/wQMFe8DRr5yGo7eYxy8TPlQ3YEf/Znf4ZPfepTEEJ4eXF9YlYnaEuFYVe7xSGeBx98EKdPf19sbd3D1NsUs7W1BaCznbZ6fktMqTe/lK++yFQtNNCjnn7FM0jKDaB8yITzB3/wbrG8vAwA+OY3v4kHHnjAWBUUJvVmS7vFNeejRj1xsbS0hHw+j2LxiHjrrbfQat1HCU0h589/wHGcH4hcLodUKtUz7wMEFx3Y5GOKfnT5jKPdE+VDJpbHH9/vhQ6lUgmFQgG1Wq3n6jCsfPopt45a7RZnvvzgwYNwHAfpdBorKyvI5/PY2npRvPXWrRTQFFIoFNBut5HJZEKl3sIsNPUTzyAl1YNGPQDlQyaQxx57r5AyqdfrKBQKOHfuHE6dOoVf+IVfwLPPPmtdE+FXcm0qt+63uahJOnHO8TzwwAMolUrIZDJIp9OYm5uDvCqen/+JuHjxIk6fvosSmiKazX/obG09bY1+9HPXr+ggTNptlMUFJiZGPp/4xB6hNtdT/4jyj1Wr1VCtVlEqlXD48HUceFPG5z//HrGwsACgI4pCoYCLFy/i1KlTOHnyJI4fP44TJ06gXC4jl8v1RD+A/86mYeZ9+pVP3IUFp06dwsrKChYWFpDP55FOp72Ib35+HplMBktLR8Xp06fB+aDp4cCBA3jiiSe86EcKCLDP+9iiH79qt0GahcYR9QCAc/DgobH9oT/zmXeKZDLpXa3qbcL1P5wsB5QSqlQq2NrawokTd3Dw7XDUFFuxWEShUMDp06exvr6OEydO4Pjx4zh58iTOnTsHAFhYWEA6nfain6hrfvqteBtFh+q9e/didXUV+/btw+rqKpaXl7GwsIBsNotMJuNJ13U7G5EVi0VwPmjno46BL3/5y975bet2YJv38Uu7SUGNWzzAmCKfhx++WcgBpKZE1D9i0G6Vkg9+8IOYm5sTpohJl1alUkGpVMKRI+/iIJ0Q1AFXq9VQKBRw9uzZnmjn5MmTXorg7rufdP7zf/6ymJ+f9xblhZ37idrpwK/UehgpC3VB6fPPPyYuv/xyXHHFFVhdXcXi4iLm5+c9CSUSCc4HTQEPPXSTyOVy3v033ngD99xzD/7qr/6qa92PJOxiU9NGcYNcKMUpHmDE8vnyl28TqVTK+Jytn5H6IZFIJJBMJvHud78basQk+x2pf/xkMul9MKlHKpXCHXecEOVyGZubmzh79mc4WMfAF75wo8jn8wA6uzkWCgVcuHABp06dwvr6Oo4fP+5FO5VKBUD3yf+zP/tV5z/9py+JbDbbsyo8TPSjFx5ELbcexfqdn/mZ/94BgBdeeEJcddVV2LNnD1ZXV7GwsOCl3jgftLNRL77a7TaOHj2K119/Ha+//jo2NjYgz299d1ObgPy2wJ60NWcjSbs9+OANYn5+PvB1UiK2kPHKK6/0/iPk621/fL3CQ5YU1mq1rrRdqVTC5uYmyuVf5GAdEeqA29raQqFQwKlTp3Dq1Kku6Vy4cMH7HttV1/e//5BQU1EmAQ2SetMlNMwJ2qA2Oi+++M/F1Vdfjd27d3vzQblcrktCcqFiuVzGmTNnsLn58zyvJxQ96pfiee211/DSSy9hY2MD+Xy+S0ASvzU/8jMwriKYuCMeydDl88gjdwi5RWwQ8o+ph43Ly8uwRUwAutJtNvmoRQv6vFG5XEaxWMT58+eRy32Eg3VIqIOtWq12pdjkvI5MsUnCnPjf+97nhFp+PWj0YzqGfeUYtn/bc889IvT5oPn5eU9Cpvmgt99+G83mP+R5PUHoF2BSPEePHsXhw4dRKpXQbrdx991POs8//5h3gaVnh2xLAuI6V4clHmDI8lFLZsOiy0cuMPTDNt9jin7Uo1qteocUUKFQoIBi5uGHbxbZbBZAZ2dSNcWmz+vINjpRT/rvfOfTQi1ACCOgIPmoohom/TQOlfNBl19+OXbv3m2cD3IcB+12G81mE5ubm+B80GSgiufChQueeF599VUcPnwY9Xodrut2jYG1tQPC1sldjcbjPFeHKR5giPLpRzzAtnyATquJKN9nqnE39TLSq+ZMAlpe/jgHagyoA21zcxOFQgHr6+s9KbaNjQ0Ag53w3/7274QSUJj026jy44N2rNbng+bn57GwsNCVinMcB61WC7VaDRsbGzh1aj/P7TGhjodTp07h6NGjeOONN/DKK6/g6NGjqNVqAOzjYG3twEhOzGGLBxiSfB599E6h5iejINs8hE3VSWSu25Z2azab3ryPKh95VCoVLwUnV9Pv3ftJDtI+UQdZpVJBoVDAmTNnulJsJ0+exPr6uvc9cZzwTz11v1C7Xvs1HdWjm1FOyMa9TcLf//1XxTXXXIPV1VXs2rUL8/PzyOfznoTk36HVaqFSqeD06dOcDxox6ph466238Nprr+GNN97Ayy+/jGPHjqFer4ceA8OS0CikI4ldPl/84i0ik8n0/f2yUi0q/chHFZAa/agR0Dve8XscoBH40pduFTJibTabKBQKOH/+vDHFVq/XAQznhH/qqfsFgJ4UhdoBQb8/Koa1P89zzz0idu3ahauuugqrq6tYWlrqKkrgfNB4OHDgdqF+psmigtdffx0vv/wyTp48iUaj0dc4iEtCo5SOJHb5qHaPSr1eR7/iUuUTppmeKfpRCxDK5TK2trawsbGBm256iIMzBOr/faFQuJTi2S6dltIpFAoAhn/CSwFNEqPYGO755x8Te/fu7VofpC5S1eeDtra2cOzYLTv2HL/ssue8TIteLq8WIjUaDSQSvzrS31MdE61Wq6uU+qWXXsLZs2fRarViGQtRRDQO2ejEKp9B0m2DohcqhOnkqla+qdGPWgG3tbWFixcvemsuSC/qACuXy10pNnVe5/Tp0973jPLknwQJjWM3UnU+aNeuXVhYWPA6Q2QyGS812Ww2d9R80Dve8WJXBa3fTp+m1jPqZ0I+/98M7ffVU8+vvfaadxw+fBgbGxteRdu4/6bjIDb5fPaz14ulpaW+v1+mQPpFyscmHlvRQVD0UywWsbm5iWq1Gvkk2bv3eWFak6Rflcn3OeqrskFR0wmNRqMrxaaXTsutecc50MYhoUnYAludD1L7xdnmg86cOYNC4efG/r5V3v3uV4Sp1NjWpy9o2wu9KKlWq+Gyy/5JbL+zXmhjKqXWK9pmjdg6HMjV6v1Qq9UgS3H7xfYhb9s0LOhQyxrDRnPXXvuS6J7kXgwcGK1WC6lU6lLU9rSQ6YF6vY7FxY9N5Imp7rEjhPBSbOvr6z0pNrlJ1iQMMimCUUhoEqQjue22LztyPmjfvn3YvXu3cT4olUphcXERuVwOxeIRcfz4cTQa/8VYf48bb3zjknTyPQuHVfHIuSy9FFnemi5s9ec3Nv5XUa/XUSwWcf31n+3791bFc+7cOW9+Ry2lFkJMxJgYJ7FEPp/61LVi165doT+kdQaNeiStVgvVarWrZbhtHws98pHrfmzRT6lUMp4w73rXESH7L+m/k98aEtsWzHrqUL6/yy//pxNxopr22Dl9+nRPtHP27FnveyZ5kMUpokkSjo2dMh90yy3HhN5WRhK2M3lQ9GPqgaYuRu+n2EgdH+vr614p9ZEjR/Daa68NtchmpxFL5JPNZvuWR6VSGShqUlEnHYNapJgiI73RpKn8dm3tgLj77ied7Suy+Z4Nn/SBoUZRfn8nW9XV3Nwczp//d6JWq+Hqq/+7sZy06nyevseOXsUm12nthAFmEkYYIe0E0ZhQ+8Xt27evq1+cPh8kt62Yn39TdCLb9w79d7755jcvrdXKhlqnJR/TEUJ47YZk9kKNkuTzc3NzSCQS3nPJZNL72W+99W9FpVLBjTd+IfD3fuCBa8TevXu9+8eOHfMiniNHjuDYsWN9V7RNK7HIZ5AigygLScNg6ncUtAGYTU42Ad1++3GRSOR8OyjLFICpF5guKfm1HATy1jTA1tf/XFQqFbz73X8wkpP4c5/7abG4uAigd48dvQFoqVQCsDOk48dOFUsU9u9/3AE680F6vzh1PiiRSGB+fh7pdBqLi6+JYc4H3XHHCZFK5Y0LhG3tkfR0m+nQJSRfr64HkxKSYz+ZTMJ1XWSzWRw58i/F1tYW3v/+PzT+3nqFrywqeP3113H48GGsr6+j2Wzu+HERNwPL5/779/XVyQDotJZYWVmJ9Rfy2+JYF4/t66CeXnKSVp34lLd6+35TOk698pKv1x/Tr8rUK7JcLoc33vg3olwu47bbvjySah11jx29ik3usQPsfPHMGrfd9mVnbe2AMO0fZJsPKpVeEW+//XZs80E33viGyOfzSCYzgZ0pVNS1W6bWM7b7QaJSx5783RcWFvD8848JvepVHSPNZrOrOejhw4dx7ty52Eqpp42B5aOGrFG7Evg1C+2XMOIJKyZdQpJvfOMb+NznPufdtw0M01WZLhnTyS+lZboykwMinU7DdV38/d9/VcQtINMeO+fOncP6+rrvHjux/2eSkSD/7/zmg2Tj1nQ6jeXlZdxwww3Y2npJDDofdNttb4tMZqFn2wD9wk5HHTumsedXbBAkJZOA2u02stmsl3YHepcY6KXUhUJhpkupgxhYPjK1pH/Ihv3euFaXu66LWq3mTR7KSUV1gtE06Rg2MtJRq+vUfYXka20nt99zQVdkjuN4qQG5N5HruvjRj74i7rjjkYFPcHXrC9seO1I65XIZAKUzTcir+kOHDlr3D4pzPuj224+LTCbr243chN6ZIuznjv6aoHEo35MqoUwmg7/92y+KZ555xvs5hUKhq5T6pZdeQqVSmflS6iAGlo/6IQ2gZ9c9oLuaTd4eO3YMu3fv7iptHgTHcbrko1az6LLRH9NFZBKTjroLq+33NIk1SECmx0yDQR0Q6XQaL7zwhCgWi7j33j/u6w8Z5x47ZGdz110HHQD48Y+fFNdcc03o+aCzZ89iY+ODoc6JO+44ITKZbNc26LbPAL8L1H4uYE0Ckl/rY9A05lKpFO699148++yzOHv2bFdz0CNHjrCUOiSxyUdWOOktvuVjElOFiTo30o+EhBAoFouo1WpoNBo90vGTUdCtLfIxTYYGpQDCYEsRBKUGUqkUcrkcvvvdz4p/8A/+deh/MMweOydPnsSJEye87+Ggmg1uv/2AAwBHjvyxkP3ibPNBS0tLyOVy2L37FXH8+HHU67/k2H/ucZFOZ7w0st8GgEGorwv6Hr/qOBVThKSOOfk7f/CDH8RXvvIVr5T69ddfZyl1BAaSz4c/PCfkB7SUh34F49c1WH6v/NA2RROA/wd4s9n01uToabd+DtNWtKb39LWvfQ0PP/xw1+8p36ufjMKgR0emv4U+IGQUlM1m8fTTnxL33fenvif/KPbYIdPBDTc86Dz//GNiz549uOKKK7z9g2zzQfl83jofdMstx0Qmkw/c+txv7OjPmT5bbKIJum/6t2zjLZVK4aGHHsL73/9+dAowWEodhYHko/ZTk/f13K3fYjA1YrKl6yTyZ8qIqd1ud/Vnk/3a9NY6+kKyfiTU77xUnK36bVdj6qEK6Kmn7he2kmHTHjum0uk49tgh04E6H7Rv3z7s3bs31HxQoVDAyZN3eudPNpvt2W8pbKoaCBfd6OLxK1qIiiohKaC1tTXs2bOH4yQiA8lHfqjLKjcZvfi1wdDFo0ZMfl0C9J/jt2upTSj6a2z3VVmZUm4mwkY5poERdBWn/zumx/Q0nElA49pjh0wP6nyQXB8km5ba5oMWFjrzQddddx2SybRVPCZM5dS2nTtNX5uWQZjGnOk1+vswzQfJ6I3jJDoDyUdGGlI+auQjMclHjSr0dJ2paaCtKaepRYZNSLqUgu7LI6x8AH8BBV2R+aUO9K/1f9M0KGQFETA5e+yQ6UHOB73ySvj5oKCqNtMHPtCbypefAzIrocso6mH6t8O8N/Wizy/TQMwMJJ9KpYLFxUVvrsa0fbGedpMT+PLDXZ3vCepYa+pWYItwTPfDRj7q4Ye+zkAfBKa1CmGuyGyDwi8qUgWkRkBPPXW/ePzxFwBMxh47ZLrQ54PUTexkKk4WFkQVj0wly3Sy/D75+dFoNLzxZ4qGbIu/9cfCyMn0HuX7nJubQ7vdpoAiMpB8nnvuMue+++pCysfWCNA039NsNr0dS8PIJyjyCZJNP0fQ1ZDpPcuBIe/7RXN+c0K6gMLmp/XJUQDYv38/nnrqqZ4U24kTJ8a2xw6ZHsLMB+VyuVBpNvmcjN4zmYzX9FQuSpcNdyuVipeGk4VLkrDRTtA4CzP2Bl0mMqsMXGpdr9e9yKfdbns5UBVT9KLKRy6aDCMf2wZRprkdeXXkt8eP7TCt7dHRr+qkEOXgkL9Hu922pt3CREB+OWm/SEjKUQiBV155pSfF1mg0AFA6JB5s80HXXXedMR3vtzRBLh1YWFjw0nbpdNobT+VyGZubm5581MInU9bE9Fni97ogSdlg9BOegeVTrVahRz6mwgF9e9t6ve4rH9P3RW2PbpONurmcbcuFMHM98/PzyOfzSKVSXucBeUWmzoPJQSF/pyh56CivMyEH+EMPPYR77rln4vbYIdOHOh/0kY98xHfxqKnEWopncXERe/bsQTab9T4rJLlcDolEwqt6ldWu8ucO45A/W4eRT38MLJ9yudxV/hw2gqnVal4Y7SefQSMf006mpsdUEYWJegBgz549mJ+fRy6X896n3ANlY2MDQgjvPagteEzFFGEeC4qC5OMS/e955MgR72uKhwybX/7lXzampiV65KOm27LZLFZXVz3JmFhcXES1WkWpVPI+P8KOL78jyuvl76T+Lox+wjGwfAqFAlKpFIQQkJuq2SreVImUSiVPPlJaYb6vnzkfm2hM94OKDCTf+ta3sLS01NMcVZaZuq7btQ7J9Dv5zWv1c0UWlJs+d+7cTGwXQCaDTCbTVZRjK8IBuivbZBdpmdYO+jf0zRzV8aSPL78UnP76sBeBpD8Gls/x47c7+fxrQl7lm4oO9P/wdruNdDqNWq0GAF7aSr1KUv9z/XYnDLOmxyQb086mYYoMJEtLSz2pAEk2m8Xi4iJKpRLK5XLX3MsgV2T9XpkRMg5su5D6vV7KR17E+SEr4PSCH5Ngws75mAQUdtypMPoJJpbN5IrFIgB4tf1hKtfkJDywnXYL0x1B7bfml3YLinxkjlgVT9h0G2AeWCpyAKndr00nsV+kY7sqCysj+e+qcFCQUXDddYeF43Q6pNs+oPU5H/m8ulTAD7kOT/1MsGURTNLx283YNsb8xhqJRizyWV9/r3P11T8S7Xbbi2L8igfkiVKv1+E4nf3i9V5P8nts8z79Fhyo4lHb8kQRz5VXXhk4MGzdGmzbdfvtpBpGQEwJkElCXUbh9yGtCkfelxemas9IE3Nzc6hWq15PR31DyKDox08ufmnwoM0mSThikQ/QacMv02l+qTddIuVyGa7r+krLTz6DRD7yUKOwMJw6dQr33Xcf9u3bh7/4i7/oed62XbdJPFEjH5ukeEVGJglb2l3e11+jj2u5hMOPixcvYmtrq6ubvS0Cso0dvzHml74LM86YZfAnRvnc47jusyKbzRpFYrvCr9frcF23R1p65wA9ZReHfGTE0++H9Pr6Ou677z48/fTTXY8nEgnUajVUKpWuCjq/K7CwkU/YlIDfVRkHBRkme/b8QAC7jOepX+Ub0Eml1Wo1lMtlbGxsYHFx0du2XiKEwObmJjY2NlAsFlGpVDz5+IklyhFFXrzI64/Y5AOg62TRox+/FBrQOenUajkV03+8Le0WRj5SPOr6mzgpFosoFAqoVquoVqtdfeIGHRh+OW1btETIKMlkMr6pYFtzXFm0VKvVvLVorutiYWHBW8xdr9dRKpWwsbGBQqGAzc1NVKvVrk0kTRkHvwu7fqIjZhgGJ1b5pFL/tbO5+X+JXC5nFYmpeKDZbGJhYQGpVMqastPni2zzPn5zPmpZdZQ5nrAIIVCr1bCxsYHNzU0Ui0Xv31Mr9fq96gq6+qJ4yCQhz0OJntHQ0S9UZfqtUCh4c0iNRsPbv6tcLntzPjKLEWaM9RMJ+R2kP2KVDwBkMr/ubG7+b8JU+WarepMnjFzJLCvfJFHnfUztdVTxxH3CyNShbPkh98ipVCpdG9zpAvKrwglzFRamascGU29kmJjOUVNvN11E6viWUZC6gFSO6Xq97klHbSQcRRphLwYpn+EQu3yAzlzI6upqV/pNYhNJtVrFyspKV780AEZpmdb66BVvpshnkI3hPv3pT+NP/uRPeh7/xje+gbfffhutVstrrVMul1GpVFCtVrsmQuM62cNGRoSMA104QHfDW3nfVnotq9yazWZXFkSVkt65Xv1MCJKMbSz2Mz6D4EWenaHI5z3v+bzz4ov/XCwvL3ctIJXoIlFPBrkBVVDBQpiiA/UYNA3Vbrfxe7/3e117uCeTSZw9e9Z7XjYUVdcQmUpA477y4kQomSTUcWqTj+l71K9Ni1PVtLtpfsd2yzE2mQxFPgBw661fcp5//jGxuLjYVf0mMYmkWCxi165dyOe793g3fY9p3seWehuU+++/39t7CIAX+qtrE+SA0K/K/AaHTUZBUZLpSo7pADIpqOdgGPnoJdimW1vRkX7+B42tQcaU/u9RPIMxNPkA2/t8/N3fPS50AenRj7yqqVQqXkNBW8WcfkKYKt7kCTIov/3bv2080Wy/h+mIMijCRkhBVT0cGGRc6BdAQoiucWxruWOqjAs7D2obR7qYglJwptfbvo9jbDCGKh/J+973hLO2dkCoJ52ax9XzvxcuXEA2m/UKEGwCsn3Qx3XV/8lPfrLrg9y0UM42IPxO6H5TAlGu3ggZF6boW6bS/NJuJumE6T4QNO5swgkjLNvPp3gGZyTyATot/NfWDnj/Y3qOV6dWq3nbLgTNGcVdb/+JT3yiq1os7BWZXhARVh5+c0L9pOwoHzJO5HmrXjBGjXz8BBTlQi1MKts2zvyyGJTP4IxMPsD2HjKqhIKQczdAd6rLb73AIPzWb/1W1xqgoIGhDwq/3HSUKzK/PLY+EPTnCRknunzkZpNRIx85nsKOszCRj1+2JErkQwZnpPKRqBuZRRFRULQ0KB//+Me7oh313wojn35TAmEjojD5aQ4MMm5arVbP/K5acGDqZO13kRdljAVFPqYLt6jPkXgYi3xU+hVRnHz0ox8FgJ4Ty29g+F2VRRkYfie7LUftN2AIGTemtJvcpRSInnaLUz5BF2426fQrH67xsTN2+ahE3dp5EFn92q/9mtf+Rx0oOmGuyAZNB4QVji1Sko8xD00mgWazaYx85PkZx5xP1HEW5sLNbzwypR0/EyWfqOiy8pPR3Xc/6QjxbSF7yMnUgCkXrc8nxZV2C3tFFnRVZhsghEwCzWbT22VUCOGJyHVd47zPKOQTJqoJSr/x4i5edrR8dIIiJ8f5r5xW6xmhVs65rtvTyHTU8omSf7a9lgODTAqyStVU7WaqeItTPv2MsbDPk3iZKvmEQfaLArYHhd7OwyYf+bWabvMTj9oOpJ85n7AHxUMmifn5f+w0m/9RqNVu8vDben6c8tHb9eiPkfiZOfnIdBsAL+1mSwdI9HU+YeSjtw8apnz6gROhZJio7afCjLNRz61GkVC/cIz5M3PyUbfnlZFPHAvgbFdmw458CJlE6vW6Jx097WbbViFqh4OgNXVhx5lJOPL1zCoMj5mTT7Va7ZoMVeXTTz560DLQIPnoA0O9z4FBJpWVld90SqX/XQDoKjqwNRi19Xfrd0mDX2GPbTypPSI5zzN8Zk4+q6u/5VQq/4ewySdKSqCfgdFPPtokoUHEw3QAGQX1eh0AkEqlvMIev3mfuBaa9rOGRxfPoBd2HGPBzJx8gM6gUMtA/VJv+oCQX9vEE2Yi1G+NT5gJUKYDyE6gUql4BT36rsZ+nQ7iamUVNe2miofja/jMpHxKpZI3KAad9zFNhpoGxiATofq+QBwYZCdwzTUPOKdP/4/CNM6izPvElWEIGmNxrZdj1BOOmZTPNdc84Jw9+xdePjps6i2o3DpKSiDMVZmej45DPBwYZJRUKhUAnbkbU5YB6F7aEDbFbbrQC6oqDZrz4RzPaJlJ+QCdQaGn3gaZ9wlKCfQb+TDVRnYy73znZ5xjx/5UpNNpL/WmRz8qYed9oqbdgop64hpbvLgLz8zK59prP+UcP/5NIeUjq3H6aX7Yz2Ro1DmfOODAIOOgVCphfn6+K/qJUvU26Nxqu93G008/jfX1dfz4xz/GV7/6VaaxJ4CZlQ8AlMtlAN3VOMMcFFErcWSqjZCdzC23fNF5+eV/IVzXHSj66Vc+3/nOdwAAmUwGCwsL+NCHPoS//Mu/jH2dHC/uojHT8rnhhged11771yMbFFGrcOK8IuPAIOPkppsecg4f/pqQOxOr636A4MKDfrscfPvb3/beQzabxcLCAlZXV7G6uopz586N+88y08y0fADg+us/6xw9+q/EICmBQeQzCvEQMglsbW1hfn4eqVSqq98bEH5hd5R5n3a7jUKhgMsvvxzAduSze/duzM/PxyofXtxFZ+blA3TSb9lsFslkskdAOmHX+wwy7xO3eDgwyCRw991POmtrB4Qca7YlDqa1df2Os3PnzmHv3r1wHAfJZBK5XA7Ly8u47LLLcOzYsVh+L46v/pgb/EfsfO6881GnWq2iXq+j0Wh0Hc1ms+dotVpdX8v76q3t0J9X7w8j4uHAIJPE3Xc/6ZTLZdRqNdTrdW/MNZtN45jTx0iYcaZ+7yc/+cmuuZ1sNovFxUVcdtllsfw+HF/9w8jnEu9972PO3/3d415O2q8VSNQmo2HKQIeRZuPAIJPIz/3cHznPPvugSKfTXWMNCE6/RSk6UL9HIlNvq6ur2LNnz0CpN46vwaB8FN73viectbUDXQKKOiEatdyacztkFrn33j92nnnm97sEZJtn9Utzmxac6uOqVCphdXUVQLd80ul03++f4hkcpt007r77SadarfakBfzScEEpOVM6IM6FbSY4OMik80u/9G+cUqkEv/FmS8mZ0nO2Yp3z5897j6XTaeTzeezatavv1BvHVjxQPgZ+/ue/1iUgfTDoAyKMlNQBMuy1OxwcZKfwK7/yTadarfYIyDbuTOMtqFjn+9//fteYG2Teh2MrPpyDBw+N+z1MLE8//SlhqsqRhM1J63uUDBMODrJTeeqp+wUA6/yP4zieRKKOpeeeew6pVAoA8Pbbb3uttWT6W42oGo0GarUaKpUKNjc38fWvfx0Ax1bcUD4BPPXU/cLUDh4IXo+gvmbYcGCQaUAKKG6++93vIpFIANger2onETWSajQaXvQlJVQul1EoFHD27M9wnMUE5RMC9YpMXoEB9m68o4biIdNGHBJ65plnMD8/73VTANAV7Ujx6HOyMvpRBVStVlGpVFAqlVAoFFAq3csxNyCUTwSGdVU2CBQPmTYeeeQOkUgksH///r5/xvPPP+9FOjp+8lHnc9X5J1VAlUoFW1tbuHDhAtLpf8Tx1yeUT0QmRUCUDplGHn98v3F8hRXR2tpaqBJqKSB94apeSGQTULlc9qIgCqg/uM4nIvJDf1wSonTItGITDwC88MILAPwlJF8TBnX+Vp/PVfvO6UcikUAymUQqlUImk0E+n8fm5n8Qb7/9Nm688QscmxGgfPpk1BKidMg04yceFV0wUkZRxCPRu2rb7pukJCWUTqeRzWZx+eWX4+WX/4W46aaHOE5DQvkMiCqFuEVE4ZBZ4JFH7uh73Bw6dMjYAiuIKN8TRkKZTAbLy8t44YUnxP79j3PchoDyiRFdFlFl9Ed/9Ec4duwYXnrpJRw9enTcvw4hQ+fBB28QtsKAMPQjHgA9a+9s9/3+XXnI/YnS6TSWlpawtnZA3H33kxRQAJTPEAkTudx112lx/fXXo9Fo4Pz5814eeZC+U4TsFObn5/v+Xrn78CD4NQk2Pa+jRkNSQNlsdrx/1B0C2+uMmUOHrnCEEEgkEkilUshms5QPmQm+9KVb+063VSqVWMQjb/02rvOTk0RNx6XTaaytHZiIqthJhvKZAFqtFubm5pBKpbwrJ8qHTDuy3U0/5PP5gf5tGbH4daCPKiFVQI7jUEABUD4TQLPZBICu6CeXy/HkJVPLF75wo+h3vqZer8fyHmTk5LdFg5+UTCk6+XMHjcpmAf6FJgA5mKR8MpkMcrncuN8WIUMjmex/ujmurIDecse075a6AWSY6Ej/2byAtEP5TAAbGxte1Yy6eI2pNzKN/O7v/pToNzIol8t9V7jpyNSbbZfhoF2Iw0iI2KF8JoAf/GCPA8CrlqF8yDQzyFzPIBGTCTXqkZGO6dAjIf1Wl5AKox8zlM+E0Gw2e9JulA+ZRuREf9QI4fTp07FFPRI/4YSRkS09x+gnGMpnQmi1WgC6532y2SyvmshU8dGPLoh+01ODREwmZAdr2dVaNhodREZ+O6qSbiifCcFU8TZoOSkhk0Y6ne7ayM2206/pw1vupxXXNvStVgv1er1rWwV9mwX1viqbIEkx9RYMOxxMCBcvXsTS0lLPvE/cV3uEjBv5AS3Tb+q22WrZsrpuRj4m01pqE9B+aDQaKJfLPdGPHgGZhGSSki4jRj7BUD4TwtrabufaayE470OmGTU9ZZOPaT7o+PHj2L17N9rttvd6uZjThO1xIQQajQaKxSJqtZpRPqbDJCA/YZFgKJ8JotVqsdyaTDXyw1mm0OQW16osTJ0F1JJoKR8ZAalIaendBlzX9dJs1Wo1knjCHvJ3Y9QTDspngpDyUQWUyWTYJZdMDfLDXhWIGsGYeqvJVJscHzJCsknLNH8kxSCFox/6dtrqzqam1+iH+hrKJxyUzwTRbDaRyWR65n0ImRbkh7SacguSjzrJL7dfMElL3urSUlN9qlxsotFfowsmSEYkHJTPBFEoFLC4uNhT8Rb3wjpCxkWj0UCj0eiRD9A756PKR36w2+QD2Hu0yao609yNLhtdQDbhmJ5rNpuMeiLAT7UJ4m//dsX52Me6iw4470OmiXq9jnQ67c3DBM35yEOmy+RckR4x2b5P71ygC8gU6djEYoqO9MdIeCifCaPdbrPogEwt1Wo1tHykSNrtNur1uhcxye+LWz5RDtPcEaOeaFA+E4ac90kmk968D4sOyLRQKpWQzWbhOI53oWWTiCqSWq3mfZ9MxYX5PtMCUL+CAT+5yMflc+ptu90e9592x0H5TBitVssrOuD2CmTaePHFdzgf+MB5AXTa5SSTyVASKRaLyOVyxshHX5waJfIxzfOoUlEPk5wajQYr3PqE8pkwtra2MD8/31N0ICdaCdnpVCqVrrU3MvWmoktkeXkZtVrNE40pYjJ9nyn6MUU9evRjko0uIvk1o57+oHwmjL/+60XnYx9zWHRAppZSqYS5uTm4rutFPn7l1uo6Hykt9fsktu8bRD66dOQh56BYZNA/lM8EwqIDMs385Cc3Oddf/6pwXRepVCp0xVu1WvWq3eScj74pnWnOR1/n41dubZrbkaLRjyji4XxtL5TPBNJqtZBOp72ig2w2i3Q6zaIDMjWUSiUIIZBOp70UmimKUeVz9uxZJJNJRJWWaZ2PvuDUr7hAjXbk0Ww2Y+uuPatQPhOIlI8e/RAyLZw7dw5CCGSzWSSTyR6RmFJoS0tLnrRarZZvsYJt3meQyIfiiRfKZwIplUpekYEqn373vSdk0mi17nO2tr4n2u22V/Um5WPqdKCm3gB4yxFsqbegirewpdbq/I4UT9QCA2YrzFA+E8j3vpdn0QGZeiqVDzmu+/+ITCaDVCrVVToN2KOYYrGIVqvVIy2J37xP1MhHPxjxxAflM6HItQyy3Frd2+fee0vi2WcXeDVFdjwXL17EwsKCN8cZVPXWbrdRLBaxvLxsjX6CKt6CuhyYKt36TbUx6rHjHDx4aNzvgRj49V/PiFQqheXlZQDoKjdVF8PJdEC1WkWlUkGhUMCxY7fwhCc7hq2tfy9kA11ZfCCxRTHpdNrLBoSZL/Irtw6KfPpdRErx+MPIZ8L4zGfeKWTvKwBd/a3UCh05UNUjmUwilUphfv5NUSwWcebMGdTrv8QBQCaapaX/1jl//t/1pN8Ac58313VRKpXQarW8ggVTt4Mo8z62OR9uiT08KJ8J4QtfuFHIqziJXM+g5qv13La8NW2kNTc3h2JxTZw5cwbJ5K9RQmRiueyyf+IcP/5NIVNpfnM/UiD1eh3Ly8td5dp+0rJFP6a0mxx3/YqHUU8wlM+YefDBG8T8/LzxOTkAZa5ZF4wcjHLtQ7vd9tYGyQHmui727NmDzc3/W7juL3NAkInlmmsecF599etCzv/YKt/UC7Jms4mFhYWedT9RUm+6fAaRDkDxhIXyGSOPPnqnCCqfVvei149EItG10ls+pqbgZMFCq9XC1ta3xdmzZ3H55f+Ug4NMJO95z+edF154QqjRjMQkkq2tLaysrCCfz/dUzPkVHpgWmsaRYqN4wkP5jInHH98f6SxX+1/ph3zcJKhkMtnVKWFlZQXr638u9u27n4OETCT79z/uPPfcIwLoXHwlEokuKaiRiRACFy5cQLlc7hGQfN4kLVU+amZhECieaFA+YyCqeNR5Hr2Lr7xvEpIeDck1QwsLC3jzzT8R1133aQ4WMpF84ANfcdbWDggpjiBqtRrq9bpxmwZTyk4ecUHxRIfyGTFRxQP0f0VmkpGUUD6fx+HDXxM33/wwBw2ZSOQH+tragVADQAjhlUfLc14VjBxHakVcnO+TRIPyGSH9iAeAsYJHvS+xDShdQnJOKJfL4Qc/eFS8//1/yMFDJpaoEgK2K0Vtz8X5vkh/UD4jol/xADAKR+a9/YSk3+oCkhEQu2WTnYB6jkYR0TDfB+kfymcEfPGLtww0UEyRj63xom3Nj+lnyoIEQnYaUQUQh6wonXjhJ88IyGQyA/8MmafWV23r0pFf67cmEalREKMfMs3o53YYGXE8DBfKZ8h86Uu3xpIekAvobJ1+/aRkiookUkDch57MEhTL+OEGMUMmlUrF9rOkfPRyUXX9QlghqRKSab1x5tEJIbMF5TNEPv/59wh9Xc6g2NqFmLYNNq1r8JMQIYSMCspniMQ9mS+jHv0wiUj/2k9EqnwY/RBCRgHlMyTuv3+fiHsxm2wJYmqQ6HdfF5AuIUY+hJBRQ/kMiTjnegB4rd7VnlR+wgkjo0HbxhNCSL9QPkNCrUyLA3U7X30jLL1FvL5Zli4g+bWUkP4emXojhAwblloPEfnhDqBrc6woCCFQr9dRLpdRr9e72r/rEvKTkl+0xMiHEDJqKJ8h8Bu/kRVSPHI/ErXLrkQI4a2zMSGEQKVSQblcRrVa9dJuYQ6/SEh/nBBCRg3lMwTkos12u+2l32zykQJS9+VxXRfNZhP1er3r0PeZ95OP+rzfaxn1EELGAeUzBGTUI6MKk3xsfdpkObUqjiDh+D0eJCnKhxAyDiifISD3lk8kEgC25QN07yVi6sNm2mPette8KpcgSdmeI4SQcUD5DAFVCFIqtsjH1iYnSEB+UtFFZDsY9RBCxgXlMwRkWfTc3NxA8jEVC9ginagHox5CyDihfIZAvV7vkY9eam3aj0dfAKrLRxVPq9Xy1v3IQ10LxKiHEDLJUD5DoFwuI5/Pe/JJJBK+kY/aqToo7RY26lFFpAuJ2ycQQsYN5TMEDh26wvnFXywLWTadSCS8/Xgk/UQ+egWbKhYpGz360Z9n1EMImQQonyFRq9UwNzcH13WRTCa9yMe0JXZU+ejRj0k4tsN13XH/aQghhPIZFpVKxZOP7HSgdzIwlVkPKh+TcOQcFNNthJBJgfIZEltbW0gkEl7kI+d9gO6mo3rFmxSQqWGoST426UjhyNso1W3cYpgQMmwonyHx5ps3O+n0a8J1XaRSKSSTSS/tZltoaio6CFtwECQezvMQQiYJymeIFItFCCGQTqe9eR819Wab9/Fb6xO24EDtB8d5HkLIpEH5DJFTp05h3759aLfbPak3SVC5td9anyD59CMeptwIIaOA8hkiQvyKs7X116LdbiOdTgeu9wnqcqAvMrXJR6bbCCFkUqF8hkyx+AuO6/6/IpvNetGPqeQ6an83fb5H3tbr9b6r2hj1EEJGBeUzAjY2NrCwsNA19xO03ieKfNTIp9+ebRQPIWSUUD4jIJ3+R87m5v8pcrkcUqmUtfDAL/UWFPnI9BwhhOwEKJ8Rkct9xNnc/JbIZDI90Q+A0Kk3U8FBu90eqJSaUQ8hZNRQPiPk5MmT2L17t7H4IGzqTS86GLSMmuIhhIwDymeE3HTTQ84Pf/iHYmVlxROQuuhUFZBadq2n3eRzgy4cpXgIIeOC8hkxd975qPPcc4+IhYUFpFIpo4Bs0Y98PI5uBRQPIWScUD5j4AMf+IoDAD/4waNC73ygC0guPo0TiocQMm7mBv8RpF/e//4/dBqNBmq1GqrVKiqVCmq1WldPNoqHEDKNMPIZM1IGa2sHBIChNQCldAghkwTlMyHoEor75xJCyCRB+UwYcUiIwiGETDqUz4RiEohNSJQNIWSnQfnsICgZQsi0wGo3QgghI+f/Bwbf9i6ytC5sAAAAHXRFWHRjb21tZW50AEdhdXNzVmlldyBUSUZGIG91dHB1dMNrnLMAAAAldEVYdGRhdGU6Y3JlYXRlADIwMjAtMDgtMDVUMjI6MzQ6NDkrMDE6MDDHMT2wAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDIwLTA4LTA1VDIyOjM0OjQ5KzAxOjAwtmyFDAAAABZ0RVh0dGlmZjphbHBoYQB1bnNwZWNpZmllZLN+fk4AAAAPdEVYdHRpZmY6ZW5kaWFuAGxzYlW3F0MAAAAUdEVYdHRpZmY6cGhvdG9tZXRyaWMAUkdCsyBJ3wAAAABJRU5ErkJggg==" + } + }, + "cell_type": "markdown", + "id": "e522f21f-4b1a-4c0c-af05-feab7016aea9", + "metadata": {}, + "source": [ + "At the core of the ASE, is the **Atoms object**. Every _calculator_ operates on an _Atoms object_.\n", + "\n", + "An Atoms object is what we'd normally call a molecule. Makes sense right? A molecule is simply a list of atoms.\n", + "\n", + "Before we start, take a look at the below acetone molecule:\n", + "\n", + "![acetone.png](attachment:e1de4673-c8c2-46ca-ae6e-5f5ee70d7054.png)\n", + "\n", + "What information do I need to provide in order to distinguish each atom in the molecule? If you already have a background in molecular simulation, you may have already have some ideas from input files you have written.\n" + ] + }, + { + "cell_type": "markdown", + "id": "161f0dd0-c37c-44f8-bedc-5919fe9a8b48", + "metadata": {}, + "source": [ + "Some further questions to help you think about your answer:\n", + "- It is fairly straightforward to distiguish the single oxygen atom:\n", + " - Using **Atomic symbol / number**\n", + "- The central carbon is different from the two methyl carbons:\n", + " - Being bound to the electronegative oxygen atom, will cause the **partial charge** to be different\n", + "- While not shown, some atoms might be isotope labelled:\n", + " - The **atomic mass** is therefore useful\n", + "- It is otherwise difficult to distinguish the two methyl carbon atoms or the six hydrogens (assuming the methyl groups rotate freely)\n", + " - Therefore the **atom positions** are required to distinguish these atoms." + ] + }, + { + "cell_type": "markdown", + "id": "e34436a2-d7f4-4324-ac12-a30b74b76deb", + "metadata": {}, + "source": [ + "The ASE **Atom object** (for a single atom) provides the following information:\n", + "\n", + "- Atomic Symbol / Number\n", + "- Position\n", + "- Mass\n", + "- Momentum\n", + "- Magnetic moment\n", + "- Charge\n", + "- Tag (that can be used for special purposes)\n" + ] + }, + { + "cell_type": "markdown", + "id": "09b63bdf-36ea-4f96-a00d-6e687eedad0d", + "metadata": {}, + "source": [ + "Let's dive in.\n", + "\n", + "First import the Atoms class of the ASE:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c383410a-714a-458d-9c57-9858e5cf54bd", + "metadata": {}, + "outputs": [], + "source": [ + "from ase import Atoms" + ] + }, + { + "cell_type": "markdown", + "id": "e0c52455-f273-48c2-9d4b-d42d42839478", + "metadata": {}, + "source": [ + "Now let's make our first molecule (_ahem_ Atoms object), a simple CO molecule:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "648ce119-acd7-4b15-a684-2f6ffe458993", + "metadata": {}, + "outputs": [], + "source": [ + "d = 1.1\n", + "co = Atoms('CO', positions=[(0, 0, 0), (0, 0, d)])" + ] + }, + { + "cell_type": "markdown", + "id": "b3160912-4b27-448d-a703-aedd26f3a363", + "metadata": {}, + "source": [ + "The ASE also provides a variety of __[molecular viewers](https://wiki.fysik.dtu.dk/ase/ase/visualize/visualize.html)__, with different functionalities. For now, we'll use a simple but reliable viewer, that works directly in jupyter notebooks, called **x3d**:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a176851c-6c5f-4160-a94c-8f3d1614335f", + "metadata": {}, + "outputs": [], + "source": [ + "from ase.visualize import view\n", + "view(co, viewer='x3d')" + ] + }, + { + "cell_type": "markdown", + "id": "ddb72a6c-651d-4d97-9fd9-499d6a8e9117", + "metadata": {}, + "source": [ + "In this simple viewer, we can use the mouse to rotate, zoom and translate the molecule within the viewer window." + ] + }, + { + "cell_type": "markdown", + "id": "21e1f876-bf93-4b94-9936-c11ad719122a", + "metadata": {}, + "source": [ + "Next we'll calculate the energy of our CO molecule. We will use the EMT calculator as it is quite fast and is implemented directly in ASE. To use a calculator, we need the following three steps:\n", + "1. Import the calculator\n", + "2. Setup the calculator\n", + "3. Attach the calculator to our Atoms object" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "76308f29-0f9a-44c3-ab9f-31b283e81bb4", + "metadata": {}, + "outputs": [], + "source": [ + "#1. Import\n", + "from ase.calculators.emt import EMT\n", + "#2. Setup calculator, EMT doesn't need any options, so we just need to define it\n", + "calc = EMT()\n", + "#3. Attach the calculator to our Atoms object\n", + "co.calc = calc" + ] + }, + { + "cell_type": "markdown", + "id": "748bdbf1-9e50-424d-9d9d-07939a47c2f5", + "metadata": {}, + "source": [ + "And now to calculate the energy of the molecule, we use the **get_potential_energy()** function:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2b21fcbc-8d48-4ed4-962d-30984488a953", + "metadata": {}, + "outputs": [], + "source": [ + "co.get_potential_energy()" + ] + }, + { + "cell_type": "markdown", + "id": "6d220b8b-63b3-4fe1-8d0b-f81184a7a79c", + "metadata": {}, + "source": [ + "Now let's manipulate our molecule, above we defined our bond length using the variable `d` to indicate our bond length. So we can easily change our bond length in a **for loop**.\n", + "\n", + "To set the CO bond length directly, we can use the __[**set_distance()** function](https://wiki.fysik.dtu.dk/ase/ase/atoms.html#ase.Atoms.set_distance)__. The set_distance function requires, at a minimum, three arguments; the index of _atom0_, index of _atom2_ (because our Atoms object is mostly going to be bigger than diatomic), and the _distance_ we want to set." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "642f800f-7478-4de4-a2ff-b2c50d04864a", + "metadata": {}, + "outputs": [], + "source": [ + "# Set up empty lists for distances and energies\n", + "distances = []\n", + "energies = []\n", + "\n", + "for distance in range(90,200): #loop variable must be an integer\n", + " co.calc = calc\n", + " co.set_distance(0, 1, distance * 0.01)\n", + " distances.append(distance * 0.01)\n", + " energies.append(co.get_total_energy())\n" + ] + }, + { + "cell_type": "markdown", + "id": "bf439b10-419d-4af0-9d34-70adbec59e7e", + "metadata": {}, + "source": [ + "We can use **matplotlib** to plot our results:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "71b9cb8d-aac8-4e81-a60f-2e8e1f82ca8d", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "ax = plt.gca()\n", + "ax.plot(distances, energies)\n", + "ax.set_xlabel('Distance [Å]')\n", + "ax.set_ylabel('Total energy [eV]')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "2c620673-38f4-4ba0-8d6b-498daf7e9393", + "metadata": {}, + "source": [ + "From our plot above, we can largely tell the equilibrium CO distance. We can also extract the minimum distance from the lists we created:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "95f260c1-ab5b-4eb8-9bc3-338696ee3974", + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Minimum energy =\", min(energies))\n", + "\n", + "print(\"Equilibrium bond length =\", distances[energies.index(min(energies))])\n" + ] + }, + { + "cell_type": "markdown", + "id": "f017ae4a-f850-4365-b7d2-bb75bb6f84f9", + "metadata": {}, + "source": [ + "## Getting and Setting\n", + "\n", + "We've just discovered two functions, `set_distance()` and `get_potential_energy()`. **get**ting and **set**ting are general concepts, with a fairly straighforward meaning:\n", + " - **get** will interrogate the Atoms object and return a value\n", + " - **set** will change the value in the Atoms object\n", + "Most things can be both **get**ted and **set**ted\n", + "\n", + "Common get functions include:\n", + " - get_distance(), get_angle(), get_dihedral()\n", + " - get_chemical_formula()\n", + " - get_dipole_moment()\n", + "\n", + "Common set functions include:\n", + " - set_distance(), set_angle(), set_dihedral()\n", + " - set_chemical_formula()\n", + " - set_cell() (for periodic systems)\n", + "\n", + "A complete list is in the __[Atoms object documentation](https://wiki.fysik.dtu.dk/ase/ase/atoms.html)__" + ] + }, + { + "cell_type": "markdown", + "id": "b1052def-b8fe-48f4-a2bf-ed97cdd144b1", + "metadata": {}, + "source": [ + "## Reading and writing molecule files\n", + "\n", + "We've just made our own CO Atoms object here, but for something more complicated, ASE has its own methods to both read and write many __[common molecule formats](https://wiki.fysik.dtu.dk/ase/ase/io/io.html)__.\n", + "\n", + "As always, we import:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "99bb88b8-0bfc-4844-b7fd-71fe3195eca3", + "metadata": {}, + "outputs": [], + "source": [ + "from ase.io import read, write" + ] + }, + { + "cell_type": "markdown", + "id": "aef470cb-e15a-4f19-82c7-1e9fcdd203d8", + "metadata": {}, + "source": [ + "Then to read a molecule, we simply specify the filename, ASE uses the file extension to automatically determine the format of the file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ca3aa17a-52a4-4cc8-b3cd-67c469b57493", + "metadata": {}, + "outputs": [], + "source": [ + "ethane = read(\"ethane.xyz\")" + ] + }, + { + "cell_type": "markdown", + "id": "12a9c9ff-868b-49e4-a84c-e9ffced62f1e", + "metadata": {}, + "source": [ + "And to write, we similarly provide a filename, and ASE will use the extension we provide in order to determine the correct file format.\n", + "The write function takes two arguments:\n", + "`write(filename, Atoms_object)`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "086a2c5e-2cfd-4a68-aec1-841121b847c4", + "metadata": {}, + "outputs": [], + "source": [ + "ethane_new = 'ethane_new.xyz'\n", + "write(ethane_new, ethane)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ed95dbd-d7f2-4611-adb9-21cdd3015686", + "metadata": {}, + "outputs": [], + "source": [ + "# TODO\n", + "# more examples" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/lessons/advanced_libs/PiC_scipy.ipynb b/lessons/advanced_libs/PiC_scipy.ipynb new file mode 100644 index 0000000..f3c0de9 --- /dev/null +++ b/lessons/advanced_libs/PiC_scipy.ipynb @@ -0,0 +1,330 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ad0fb146-f9ef-4d6c-9a04-ce3a7ad3ddd2", + "metadata": {}, + "source": [ + "# Scipy\n", + "A scientific Python library that among other functions provides:\n", + "- scientific constants\n", + "- advanced linear regression\n", + "- non-linear least squares curve fitting" + ] + }, + { + "cell_type": "markdown", + "id": "9242e111", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "- `matplotlib`\n", + "- `numpy`\n", + "- functions\n", + "- f-strings" + ] + }, + { + "cell_type": "markdown", + "id": "0dac4919", + "metadata": {}, + "source": [ + "## Learning outcomes\n", + "- Use physical and chemical constants from a library.\n", + "- Convert between common units of temperature, pressure and energy.\n", + "- Perform a linear regression and plot the result.\n", + "- Perform a non-linear least-squares fit and plot the result." + ] + }, + { + "cell_type": "markdown", + "id": "b33bf40b", + "metadata": {}, + "source": [ + "## Use of scientific constants\n", + "In any calculations or script you should define scientific constants with a clearly named variable rather than typing the number directly in your calculation. It is best practice to use the SI units for the constant." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1731cb41", + "metadata": {}, + "outputs": [], + "source": [ + "# Ideal gas constant\n", + "R = 8.314 # in J K^-1 mol^-1\n", + "# The volume of 1 mol of ideal gas at a pressure of 1 bar and a temperature of 298 K.\n", + "p = 100_000 # in Pa\n", + "n = 1 # in mol\n", + "T = 298 # in K\n", + "print(f\"The volume of 1 mol of ideal gas at standard pressure and 298 K is {1000*n*R*T/p:.2f} L.\")" + ] + }, + { + "cell_type": "markdown", + "id": "3e6b77c3", + "metadata": {}, + "source": [ + "## Scientific constants with `scipy.constants`\n", + "Import the `constants` package from the `scipy` library as a whole or import the specific constant(s) that you need." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ec42bf6b", + "metadata": {}, + "outputs": [], + "source": [ + "from scipy.constants import R,c\n", + "print(f\"The ideal gas constant is R = {R} J K^-1 mol^-1)\")\n", + "print(f\"The speed of light is c = {c} m s^-1\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62208e55", + "metadata": {}, + "outputs": [], + "source": [ + "import scipy.constants as c\n", + "print(f\"The Boltzmann constant is k_B = {c.k} J K^-1\")\n", + "print(f\"Planck's constant is h = {c.h} J s\")" + ] + }, + { + "cell_type": "markdown", + "id": "59a13bef", + "metadata": {}, + "source": [ + "## Exercise\n", + "Use the constants from the `scipy.constants` package to convert the energy of 1 kJ mol-1 into\n", + "- eV\n", + "- cm-1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b030b98", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "451e15a4", + "metadata": {}, + "source": [ + "You can find a whole list of physical constants included in the `scipy.constants` package at https://docs.scipy.org/doc/scipy/reference/constants.html" + ] + }, + { + "cell_type": "markdown", + "id": "c51b2c98", + "metadata": {}, + "source": [ + "## Advanced linear regression with `scipy.stats.linregress`\n", + "The linear regression method provided by the `scipy` package provides some advanced statistical parameters, those that users may be familiar with from Microsoft Excel's LINEST:\n", + "- Slope\n", + "- Intercept\n", + "- R value\n", + "- P value\n", + "- standard error in the slope\n", + "- standard error in the intercept" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36ba6ccf", + "metadata": {}, + "outputs": [], + "source": [ + "# Define an x,y dataset that follows a linear trend\n", + "import numpy as np\n", + "x = np.arange(0,10)\n", + "y = (3.0 + np.random.rand()) * (x + np.random.rand(10))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d715e20", + "metadata": {}, + "outputs": [], + "source": [ + "# Perform linear regression\n", + "from scipy.stats import linregress\n", + "result = linregress(x,y)\n", + "print(f\"The linear regression parameters are: {result}\")" + ] + }, + { + "cell_type": "markdown", + "id": "c0d7c80a", + "metadata": {}, + "source": [ + "### You can use `matplotlib` to visualise the data and the linear regression\n", + "Each of the elements of the fitting results can be accessed by appending the name, separated by a dot from the regression result e.g. `result.slope` for the slope or `result.intercept` for the intercept." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ad05330", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "plt.scatter(x,y,label=\"Data\")\n", + "plt.plot(x,x*result.slope + result.intercept,label=\"Regression\")\n", + "plt.title(\"Linear regression\")\n", + "plt.xlabel(\"x\")\n", + "plt.ylabel(\"y\")\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "4b1acf38", + "metadata": {}, + "source": [ + "## Exercise" + ] + }, + { + "cell_type": "markdown", + "id": "4df88078", + "metadata": {}, + "source": [ + "## Non-linear least-squares curve fitting with `scipy.optimize.curve_fit`\n", + "While as Chemists we like to linearise data to then apply a linear regression, sometimes data is in a format that cannot be easily linearised and requires to fit the non-linear data with the appropriate function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9a5c00a", + "metadata": {}, + "outputs": [], + "source": [ + "# Import required packages\n", + "from scipy.optimize import curve_fit\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from scipy.constants import pi,k,u # Pi, Boltzmann constant, atomic mass unit" + ] + }, + { + "cell_type": "markdown", + "id": "4cbc0b5c", + "metadata": {}, + "source": [ + "### Maxwell-Boltzmann distribution\n", + "We will determine the mean speed and temperature of argon." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3ecac55", + "metadata": {}, + "outputs": [], + "source": [ + "# Generate some data with noise\n", + "T = 300 # in K\n", + "steps = 50\n", + "v = np.linspace(1,1000,steps)\n", + "m = 39.948*u # mass of argon in atomic mass units\n", + "F = ((m/(2*pi*k*T)**1.5 * 4*pi*v**2 * np.exp(-m*v**2/(2*k*T)))/1e9+np.random.rand(steps))*1e9\n", + "plt.scatter(v,F)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5cb2ddc1", + "metadata": {}, + "outputs": [], + "source": [ + "def func(v,T,m):\n", + " \"\"\"Fitting function for a Maxwell-Boltzmann distribution.\"\"\"\n", + " return m/(2*pi*k*T)**1.5 * 4*pi*v**2 * np.exp(-m*v**2/(2*k*T))\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4030e65a", + "metadata": {}, + "outputs": [], + "source": [ + "# Performing the nonlinear fit which returns the fitting parameters \n", + "# as a tuple (which is like an immutable list) and the covariance matrix.\n", + "#\n", + "# In the fit we assume the element also as an unknown i.e. as a fitting parameter together with the temperature.\n", + "popt, pcov = curve_fit(func, v, F, p0=[250,1e-25])\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33b4692d", + "metadata": {}, + "outputs": [], + "source": [ + "plt.scatter(v,F,label=\"data\")\n", + "plt.plot(v,func(v,*popt),label=f\"fit with T = {popt[0]:.1f} K, m = {popt[1]/u:.1f} amu\")\n", + "plt.title(\"Fitted Maxwell-Boltzmann distribution\")\n", + "plt.xlabel(r\"speed / m s$^{-1}$\")\n", + "plt.ylabel(\"Intensitiy / arb. units\")\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "d39c119f", + "metadata": {}, + "source": [ + "# TODO\n", + "- Add example for unit conversion with `scipy.constants`\n", + "- Add exercises to all sections (unit conversion, linear regression possibly based on first linearising data, non-linear fit)\n", + "- add some questions / quizzes\n", + "- add a few debugging examples where suitable" + ] + }, + { + "cell_type": "markdown", + "id": "a73b7e31", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/lessons/advanced_libs/RDKit_drawing.ipynb b/lessons/advanced_libs/RDKit_drawing.ipynb new file mode 100644 index 0000000..4c0062e --- /dev/null +++ b/lessons/advanced_libs/RDKit_drawing.ipynb @@ -0,0 +1,254 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "Lck-NAtqxj-h" + }, + "source": [ + "# RDKit\n", + "\n", + "## Prerequisites:\n", + "- Importing libraries\n", + "- Molecule objects in RDKit\n", + "- SMILES molecular line notation\n", + "- Molecular file formats (MDF Mol)\n", + "\n", + "## Learning outcomes\n", + "- Become familiar with the use of RDKit to draw 2D molecular structures\n", + "- Use both SMILES strings and molecule files as input to create RDKit molecule objects" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1p_TIbTe1msT" + }, + "source": [ + "## Drawing molecules with RDKit\n", + "\n", + "RDKit is a free, massively powerful library of cheminformatics tools. An overview of the RDKit package (and its full documentation) can be accessed here https://www.rdkit.org/docs/Overview.html\n", + "\n", + "\n", + "The RDKit Python library makes drawing molecules simple. It requires two steps:\n", + "\n", + "\n", + "1. Create a molecule object that RDKit can operate on\n", + "2. Use the Draw function in RDKit's chemistry module to create the 2D image corresponding to the molecule object\n", + "\n", + "In order to do this, we must first tell Python to import the requires functionality from the RDKit package. Then, we are free to build our molecule and plot it.\n", + "\n", + "\n", + "## SMILES\n", + "Here we specify the molecular structure using the Simplified Molecular Input Line Entry System (SMILES) notation.\n", + "\n", + "Inspect, then run the following code to draw the benzene molecule." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "mge9eDGA0A4M" + }, + "outputs": [], + "source": [ + "from rdkit import Chem\n", + "from rdkit.Chem import Draw\n", + "m1 = Chem.MolFromSmiles('c1ccccc1')\n", + "Draw.MolToImage(m1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1x0gHFxK64ui" + }, + "source": [ + "Here, we create a molecule object using the `MolFromSmiles()` function. RDKit reads the SMILES string and creates a 2D representation of the corresponding molecule. This is stored in the variable `m`.\n", + "\n", + "Once we have the `m` object, we can perform many different operations on it with RDKit, but here we focus on drawing the molecular structure. To do this we use the second import statement to give us access to RDKit's drawing functions.\n", + "\n", + "The function that we use in this example, `Draw.MolToImage()`, draws the molecular structure to the screen. However, you could also save your image to a file using the `Draw.MolToFile()` function for later insertion into e.g. Word documents." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "31Z-vyOx3Sf5" + }, + "source": [ + "By editing the SMILES string, we can alter the structure contained in the RDKit molecule object, and therefore the output image.\n", + "\n", + "Let's create toluene - you can do this by simply adding another carbon to the SMILES string.\n", + "\n", + "Note, however, that we are adding a capital C. In SMILES notation, capital \"C\" denotes an aliphatic sp$^3$ carbon and lowercase \"c\" gives an aromatic sp$^2$ carbon." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "S1Bo_RJb1VTP" + }, + "outputs": [], + "source": [ + "from rdkit import Chem\n", + "from rdkit.Chem import Draw\n", + "m = Chem.MolFromSmiles('c1ccccc1C')\n", + "Draw.MolToImage(m)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Kz6LvoP95fsF" + }, + "source": [ + "Similarly, we can change our benzene example to give us pyridine by replacing a ring carbon with nitrogen. We use a lowercase \"n\" because the pyridine nitrogen is also sp$^2$/aromatic." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "UKNsFba00tcK" + }, + "outputs": [], + "source": [ + "from rdkit import Chem\n", + "from rdkit.Chem import Draw\n", + "m = Chem.MolFromSmiles('n1ccccc1')\n", + "Draw.MolToImage(m)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sFyadGUL9czn" + }, + "source": [ + "For simple molecules, editing the SMILES string by hand is fairly straightforward. This is not really the case for \"interesting\" molecules. In such cases, one alternative is to use an online source to obtain the SMILES for your molecule.\n", + "\n", + "The PubChem service (https://pubchem.ncbi.nlm.nih.gov/) is particularly useful for this. In the following example, PubChem was searched for \"asprin\". The entry for this compound contains the corresponding SMILES string, which was used here.\n", + "\n", + "NOTE: An alternative SMILES format is used here that explicitly shows the position of double bonds (denoted \"=\"), so no distinction is made between aromatic and aliphatic atoms. You can read more about SMILES grammar at http://opensmiles.org/opensmiles.html" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ZlMpP_h-yG1f" + }, + "outputs": [], + "source": [ + "from rdkit import Chem\n", + "from rdkit.Chem import Draw\n", + "m = Chem.MolFromSmiles('CC(=O)OC1=CC=CC=C1C(=O)O')\n", + "Draw.MolToImage(m)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "wO8MNehOGFQS" + }, + "source": [ + "## Molecular structure files\n", + "\n", + "An alternative input method to the SMILES strings, above, uses external files containing information on the elemental makup of the molecule in question and its geometry/bonding.\n", + "\n", + "RDKit can read several molecule file formats, but the next example uses a file in the \"MOL\" format." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true, + "id": "yFv3z0gfxehq", + "jupyter": { + "outputs_hidden": true + } + }, + "outputs": [], + "source": [ + "from rdkit import Chem\n", + "from rdkit.Chem import Draw\n", + "m = Chem.MolFromMolFile('Asprin.mol')\n", + "Draw.MolToImage(m)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "EydaQBa6TbGX" + }, + "source": [ + "NOTE: The orientation of the the asprin molecule is different because the order of the atoms in the .mol file is different from that given in the SMILES string. This means the \"starting\" atom for the drawing changes." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_0ed7gxW_sTz" + }, + "source": [ + "## Practice\n", + "Search PubChem for the data on paracetamol. Copy the SMILES string and edit/run the following Python code to draw the paracetamol molecule.\n", + "\n", + "Remember to put the SMILES string in quotes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "DwMYZFi4ACs-" + }, + "outputs": [], + "source": [ + "from rdkit import Chem\n", + "from rdkit.Chem import Draw\n", + "m = Chem.MolFromSmiles()\n", + "Draw.MolToImage(m)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "U93Gwk3V_Q9I" + }, + "source": [ + "# TODO:\n", + "- Clarify different SMILES formats (or simply tidy them up to use a single format - probably better for introductory students)\n", + "- Add examples using structure files as input instead of SMILES for more complex molecules to show limitations of 2D depiction (then add 3D images?)" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/lessons/advanced_libs/ethane.xyz b/lessons/advanced_libs/ethane.xyz new file mode 100644 index 0000000..0942a40 --- /dev/null +++ b/lessons/advanced_libs/ethane.xyz @@ -0,0 +1,11 @@ +8 +GV ethane + C -2.12799175 0.80645143 0.00000001 + H -1.77133744 -0.20235861 -0.00000018 + H -1.77131892 1.31085006 -0.87365124 + H -3.19799175 0.80646453 0.00000003 + C -1.61464951 1.53240788 1.25740487 + H -0.54464951 1.53239477 1.25740486 + H -1.97130382 2.54121792 1.25740506 + H -1.97132234 1.02800925 2.13105613 + diff --git a/lessons/advanced_libs/ethane_new.xyz b/lessons/advanced_libs/ethane_new.xyz new file mode 100644 index 0000000..99a89e4 --- /dev/null +++ b/lessons/advanced_libs/ethane_new.xyz @@ -0,0 +1,10 @@ +8 +Properties=species:S:1:pos:R:3 GV=T ethane=T pbc="F F F" +C -2.12799175 0.80645143 0.00000001 +H -1.77133744 -0.20235861 -0.00000018 +H -1.77131892 1.31085006 -0.87365124 +H -3.19799175 0.80646453 0.00000003 +C -1.61464951 1.53240788 1.25740487 +H -0.54464951 1.53239477 1.25740486 +H -1.97130382 2.54121792 1.25740506 +H -1.97132234 1.02800925 2.13105613 diff --git a/lessons/basics.md b/lessons/basics.md index 80aa04f..ed1d235 100644 --- a/lessons/basics.md +++ b/lessons/basics.md @@ -1,3 +1,3 @@ -# Python Basics +# Getting Started with Python -Here, you will find some basic lessons in Python programming. +Here, you will find how to start running Python. diff --git a/lessons/common_libraries.md b/lessons/common_libraries.md new file mode 100644 index 0000000..79506dc --- /dev/null +++ b/lessons/common_libraries.md @@ -0,0 +1,3 @@ +# Common Libraries + +This section will introduce you to three commonly used libraries - NumPy, Matplotlib, and Pandas. It also covers how to read the documnetation of libraries like these. diff --git a/lessons/common_libs/Introduction to NumPy.ipynb b/lessons/common_libs/Introduction to NumPy.ipynb new file mode 100644 index 0000000..7976fe5 --- /dev/null +++ b/lessons/common_libs/Introduction to NumPy.ipynb @@ -0,0 +1,579 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "805c8bc8-6f38-481c-be9a-ce2ba998d686", + "metadata": {}, + "source": [ + "# An introduction to NumPy\n", + "\n", + "## Learning objectives\n", + "\n", + "- Create `numpy` arrays of one and two dimensions.\n", + "\n", + "- Perform mathematical operations on arrays.\n", + "\n", + "- Extract a single value from an array at a particular location.\n", + "\n", + "## Prerequisites\n", + "\n", + "- Variables\n", + "\n", + "- Lists" + ] + }, + { + "cell_type": "markdown", + "id": "5fc4dc12-62a2-42a0-af8d-451177ae071e", + "metadata": {}, + "source": [ + "## Introduction\n", + "\n", + "`numpy` is a Python library that enables us to create and use arrays of variables. `numpy` is very useful for working with data, as we will explore in the lesson.\n", + "\n", + "The basic object of `numpy` is an array, this is a collection of variables that looks much like a `list` but can be multi-dimensional. `numpy` typically uses numeric variables, with arrays of either integers of floats." + ] + }, + { + "cell_type": "markdown", + "id": "bec760b3-cc91-4655-a988-c50cbca27385", + "metadata": {}, + "source": [ + "### Import the NumPy library\n", + "\n", + "For `numpy`, the standard-practice alias is `np.`:" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "928691dd-00ed-46db-83b9-85e480d48b52", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "id": "2718fca7-d13e-4add-979e-2425b70078ac", + "metadata": {}, + "source": [ + "### Creating a NumPy array" + ] + }, + { + "cell_type": "markdown", + "id": "2b7964d7-a083-49c6-a701-99ecfc60bf60", + "metadata": {}, + "source": [ + "Imagine running an experiment in the lab in which the concentration of one product over time is measured. Mole fractions of our product of 0.0, 0.05, 0.08, 0.1, 0.11 are measured as a time series.\n", + "\n", + "In order to create a `numpy` array of our data, it's easiest to first create a list of the data. (Is this the best way to introduce this?)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "d20e8fd6-69c8-404d-91d6-27df5a5ce96a", + "metadata": {}, + "outputs": [], + "source": [ + "product_fraction_list = [0.0, 0.05, 0.08, 0.1, 0.11]" + ] + }, + { + "cell_type": "markdown", + "id": "a607f43f-b622-442b-8596-a00ce7c4147c", + "metadata": {}, + "source": [ + "The `numpy` `array()` function is used to create an array from a list." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "62d77504-91ae-43c9-8384-af3a3c950f1e", + "metadata": {}, + "outputs": [], + "source": [ + "product_fraction_array = np.array(product_fraction_list)" + ] + }, + { + "cell_type": "markdown", + "id": "8b0c94b4-5091-424a-90db-337957c94fa5", + "metadata": {}, + "source": [ + "Printing `product_fraction_array` allows inspection of the array." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "8319e6b9-a709-4c6c-8c24-47b21aba0b31", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0. 0.05 0.08 0.1 0.11]\n" + ] + } + ], + "source": [ + "print(product_fraction_array)" + ] + }, + { + "cell_type": "markdown", + "id": "1ed4c5cd-bcc1-4b9f-b1b1-bcd9b8009041", + "metadata": {}, + "source": [ + "`product_fraction_array` is a one dimensional array containing the experimental values of mole fraction." + ] + }, + { + "cell_type": "markdown", + "id": "f9a1237b-9e50-49de-b8b7-80c7c7874c0e", + "metadata": {}, + "source": [ + "`numpy` also has function for creating arrays filled with zeros or ones. These functions are fandily named `zeros` and `ones`! For one-dimensional arrays, you have to pass the length of array that you want to create to the function." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "4fbde00e-fca3-4e99-9ccf-1e825b2aaabc", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0. 0. 0. 0. 0.]\n" + ] + } + ], + "source": [ + "array_of_zeros = np.zeros(5)\n", + "print(array_of_zeros)" + ] + }, + { + "cell_type": "markdown", + "id": "e831afad-609b-419f-ad71-17774439fa76", + "metadata": {}, + "source": [ + "### Excercise" + ] + }, + { + "cell_type": "markdown", + "id": "bdfcca73-0230-4110-869e-9351d54624da", + "metadata": {}, + "source": [ + "Create an array containing the following mole fractions of a reactant in a reaction: 0.5, 0.4, 0.37, 0.35, 0.34." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a68e2315-0776-4978-b7fa-0bc1780d0891", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "a3a1d2c8-84dd-4462-933c-7f57cf318d45", + "metadata": {}, + "source": [ + "Answer:\n", + "\n", + "```python\n", + "reactant_fraction_list = [0.5, 0.4, 0.37, 0.35, 0.34]\n", + "reactant_fraction_array = np.array(reactant_fraction_list)\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "d41fd57d-c124-495b-8c37-9943b48c518f", + "metadata": {}, + "source": [ + "### Mathematical Operations" + ] + }, + { + "cell_type": "markdown", + "id": "004e8fd3-7b0d-4523-9d49-4a0d7de5e635", + "metadata": {}, + "source": [ + "`numpy` arrays allow mathematical operations. The most basic mathematical operations involve a single array and an integer. For instance, we might want to turn our mole fraction into a percentage by multiplying every value by 100. This is simple through `numpy` as mathematical operations are applied to each element." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "84535acd-cb25-4ba6-90ff-fdb5a4cfa694", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[ 0. 5. 8. 10. 11.]\n" + ] + } + ], + "source": [ + "product_percentage_array = product_fraction_array * 100\n", + "print(product_percentage_array)" + ] + }, + { + "cell_type": "markdown", + "id": "df8154d0-4b41-4a70-a3c2-e4a7b388066a", + "metadata": {}, + "source": [ + "All mathematical operators work in the same element by element way, including `+`, `-`, `/` and `**`." + ] + }, + { + "cell_type": "markdown", + "id": "bedf8b8c-224c-40ee-b6f4-bac5d7883f7f", + "metadata": {}, + "source": [ + "Mathematical operators also work between two arrays. For example, it would be possible to calculate the mole fraction of our known reactant and product at every time point by adding the two arrays together." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "56a09393-fe8a-4d67-b89d-10a626bbb655", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0.5 0.45 0.45 0.45 0.45]\n" + ] + } + ], + "source": [ + "reactant_fraction_list = [0.5, 0.4, 0.37, 0.35, 0.34]\n", + "reactant_fraction_array = np.array(reactant_fraction_list)\n", + "\n", + "summed_fraction_array = product_fraction_array + reactant_fraction_array\n", + "print(summed_fraction_array)" + ] + }, + { + "cell_type": "markdown", + "id": "dd335fb5-c4eb-4256-9343-88863254adbd", + "metadata": {}, + "source": [ + "Mathematical operations between two arrays works in an element by element way too. The first element in one array is added to the first element in the other array, and so on.\n", + "\n", + "If an attempt is made to add two arrays of different size together, this gives an error!" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "39a68643-a5b7-4d83-838f-3cc8db6be500", + "metadata": {}, + "outputs": [], + "source": [ + "#array_four = np.array([1,2,3,4])\n", + "#array_five = np.array([1,2,3,4,5])\n", + "#array_four + array_five" + ] + }, + { + "cell_type": "markdown", + "id": "8107eb92-6022-42b9-9852-17f181f548db", + "metadata": {}, + "source": [ + "## Excercises" + ] + }, + { + "cell_type": "markdown", + "id": "f67fd141-122a-4573-b0b0-47ecdf151e85", + "metadata": {}, + "source": [ + "Using the mole fraction of products and reactants given above, create an array containing the mole fraction of other reactants and products in the reaction." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bccc39cb-1d02-4664-ab69-b0e6f2a8d7a9", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "7bdb72ca-d330-4f57-946f-d549882d821c", + "metadata": {}, + "source": [ + "Answer:\n", + "\n", + "```python\n", + "remaining_fraction_array = np.ones(5) - summed_fraction_array\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "14b0d8ba-f7e2-4c4e-b67d-48467a6c107d", + "metadata": {}, + "source": [ + "The reaction time was also collected during the experiment. This data in minutes is: [0, 2, 4, 6, 8]. Create an array for this time data and convert the values to seconds." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fc444172-a526-4c9c-b554-519996ea8ee1", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "af6876e7-dee8-4938-bf9e-36fdccb17d9c", + "metadata": {}, + "source": [ + "Answer:\n", + "\n", + "```python\n", + "minutes = np.array((0, 2, 4, 6, 8))\n", + "seconds = minutes*60\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "1a780dbc-b9f2-4029-9faf-bbdb1ff66732", + "metadata": {}, + "source": [ + "## Indexing elements" + ] + }, + { + "cell_type": "markdown", + "id": "c92bd0ee-30bc-41f4-85bd-f506e5c0f164", + "metadata": {}, + "source": [ + "Individual elements in `numpy` arrays can be accessed very simply using indexing. Indexing of one-dimensional arrays works very similarly to lists, i.e. the number of the element is given in square brackets.\n", + "\n", + "For example, to take the first value of product mole fraction from `product_fraction_array`:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "bc94118d-66f3-426e-8c92-adeaa4bb40d7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.0\n" + ] + } + ], + "source": [ + "first_element = product_fraction_array[0]\n", + "print(first_element)" + ] + }, + { + "cell_type": "markdown", + "id": "1230059e-37f8-42cb-a123-bb31f07898f5", + "metadata": {}, + "source": [ + "As ever in Python, indexing starts at 0, i.e. the first element is at position `0` and so on." + ] + }, + { + "cell_type": "markdown", + "id": "26e8db32-f232-4ab1-a776-da17aea0becb", + "metadata": {}, + "source": [ + "### Excercise" + ] + }, + { + "cell_type": "markdown", + "id": "7e96792f-cc39-487b-9d65-44ae4ea1e3e7", + "metadata": {}, + "source": [ + "Calculate the difference in time (in seconds) between the second and fifth time points in the time series used in the previous excercises." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70c74f43-b1f7-4c38-9a77-402c9a20c7f5", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "02bf27af-222f-4263-8331-7401abbaa538", + "metadata": {}, + "source": [ + "Answer:\n", + "\n", + "```python\n", + "time_difference = seconds[4] - seconds[1]\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "bd83ef73-062e-44b1-95e8-58c5c6f47fd4", + "metadata": {}, + "source": [ + "## Multi-dimensional Arrays" + ] + }, + { + "cell_type": "markdown", + "id": "0582dbb6-43ae-4f10-b5b7-b83aeb0e96dd", + "metadata": {}, + "source": [ + "`numpy` arrays are not just restricted to one dimension. There are no restrictions on the number of dimensions for numpy arrays.\n", + "\n", + "For example, it's possible to combine both the concentration and time data in a 2D `numpy` array. One possible way to do this is to combine two lists into a list of lists." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "4988bc0c-24ab-4003-b7ec-2f18cefaa81c", + "metadata": {}, + "outputs": [], + "source": [ + "combined_list = (product_fraction_list, (0, 120, 240, 360, 480))" + ] + }, + { + "cell_type": "markdown", + "id": "2610da37-4524-46a5-80de-f785ea1c25f4", + "metadata": {}, + "source": [ + "Using the `array` function on a list of lists creates a multi-dimensional array." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "393c10d1-ba47-4571-8bdf-0db5f7884259", + "metadata": {}, + "outputs": [], + "source": [ + "combined_array = np.array(combined_list)" + ] + }, + { + "cell_type": "markdown", + "id": "7a412030-2e7a-4713-8f6a-69547dcc6ca2", + "metadata": {}, + "source": [ + "Creating a 2D array also works from a list of 1D arrays. Note, the lists (or arrays) must be the same length for this to work." + ] + }, + { + "cell_type": "markdown", + "id": "c94bc156-6041-4007-a7f9-f1c3b92bfd92", + "metadata": {}, + "source": [ + "## Excercise" + ] + }, + { + "cell_type": "markdown", + "id": "9a8ea97d-81a7-47c2-adb5-b89e375a1cb6", + "metadata": {}, + "source": [ + "Create a two-dimensional array containing the `reactant_fraction_array` and `seconds`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e68cb100-2b43-4d7f-a839-fe095fb78f27", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "bd61c85b-1f73-4e6d-92b4-94ebe6a1fcfa", + "metadata": {}, + "source": [ + "Answer:\n", + "\n", + "```python\n", + "reaction_array = np.array((reactant_fraction_array,seconds))\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "48169543-098f-4cc8-84c1-7718b10b16f9", + "metadata": {}, + "source": [ + "## Learning Objectives\n", + "- Create numpy arrays of one and two dimensions.\n", + "\n", + "- Perform mathematical operations on arrays.\n", + "\n", + "- Understand how to index `numpy` arrays." + ] + }, + { + "cell_type": "markdown", + "id": "83d2a72b-a435-4178-aa90-c70bdcce28ab", + "metadata": {}, + "source": [ + "## TODO\n", + "\n", + "Check content vs other NumPy lesson.\n", + "\n", + "Add more complex excercises." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/lessons/common_libs/Matplotlib_Documentation.ipynb b/lessons/common_libs/Matplotlib_Documentation.ipynb new file mode 100644 index 0000000..4a5b7d6 --- /dev/null +++ b/lessons/common_libs/Matplotlib_Documentation.ipynb @@ -0,0 +1,162 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "4c983a83-8172-4b50-b428-b65eb006acc2", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "id": "9b6f0144-2402-43ec-927a-33517502a59d", + "metadata": {}, + "source": [ + "## Searching the Docs - Matplotlib!\n", + "#### Introduction:" + ] + }, + { + "cell_type": "markdown", + "id": "75ab876e-424b-4cd3-929e-f6d40c13cc67", + "metadata": {}, + "source": [ + "### Task 1: Finding argument options from the documentation page\n", + "\n", + "Here is some code to create a linear plot. The datapoints have been defined as a circle.\n", + "1. Can you change the markers to crosses?\n", + " > **Hint:** Where has the datapoint style been defined in the code?\n", + "2. Now can you change them to be squares?\n", + " > **Hint:** Take a look at the `matplotlib.markers` documentation page [here](matplotlib.org/stable/api/markers_api.html#module-matplotlib.markers).\n", + "3. Can you change the linestyle to be a dotted line?\n", + " > **Hint:** Find the linestyle menu on `matplotlib.pyplot.plot` documentation page [here](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html).\n", + "4. Now can you increase the data point size?\n", + " > **Hint:** What did you do in task 3?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab5c3579-d62e-4751-b182-682fc4c2531f", + "metadata": {}, + "outputs": [], + "source": [ + "T = np.array([700, 750, 800, 850, 900])\n", + "k = np.array([1.5e-5, 4.9e-4, 5.9e-3, 4.7e-2, 5.5e-1])\n", + "\n", + "plt.plot(1000/T, np.log(k), marker='o', linestyle='-')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "95dfea33-1642-4653-8a80-ba4dc8ff3d9e", + "metadata": {}, + "source": [ + "### Task 2: Exploring Pyplot Functions" + ] + }, + { + "cell_type": "markdown", + "id": "321ad4e0-b412-49af-b941-fdadf740617c", + "metadata": {}, + "source": [ + "1. Explore the [matplotlib.pyplot](https://matplotlib.org/stable/api/pyplot_summary.html#module-matplotlib.pyplot) documentation page to find the function to change the y axis scale to a log scale. Once found, ammend the code below accordingly.\n", + "2. Explore the [matplotlib.pyplot](https://matplotlib.org/stable/api/pyplot_summary.html#module-matplotlib.pyplot) documentation page to format the x and y axis major and minor ticks. Update the code accordingly. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "951f91a1-0e80-43ec-aaa0-97ac7976432d", + "metadata": {}, + "outputs": [], + "source": [ + "data = np.genfromtxt(\"Venus data.csv\", skip_header=1, delimiter=',', dtype=float, usecols=(1, 2, 3))\n", + "\n", + "plt.plot(data[:, 0], data[:, 1], color='b', label=\"SO\")\n", + "plt.plot(data[:, 0], data[:, 2], color='r', label=r\"SO$_2$\")\n", + "plt.xlabel('Altitude (km)', fontsize=14)\n", + "plt.ylabel('Mixing Ratio (ppm)', fontsize=14)\n", + "plt.xlim(0, 180)\n", + "plt.ylim(0, 1e-5)\n", + "plt.minorticks_on()\n", + "plt.legend(frameon=False, fontsize=14)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "3ffabcd1-fc1e-4394-9524-3eb4271e6a34", + "metadata": {}, + "source": [ + "### Task 3: Different Plot Types\n", + "\n", + "1. Create a boxplot from data and format it appropriately\n", + "2. Create a violinplot (displaying mean values) and format it appropriately" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "510c0e66-df4f-42ea-91dd-c35a8710e6bc", + "metadata": {}, + "outputs": [], + "source": [ + "data = np.genfromtxt(\"Vit C in Orange Juice.csv\", skip_header=1, delimiter=',', dtype=float)\n", + "\n", + "plt.boxplot(data)\n", + "plt.show()\n", + "\n", + "plt.violinplot(data, showmeans=True)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "b1bbdbd4-78ce-4010-a41d-0ac3dabe7d39", + "metadata": {}, + "source": [ + "# TODO:\n", + "\n", + "- Searching\n", + "- Understanding scary examples\n", + "- A non-coding activity (MCQ/Drag and drop style)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b204a3c2-ed09-4725-b712-acb6ffcd3645", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.12.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/lessons/common_libs/NumPy_axes_operations.ipynb b/lessons/common_libs/NumPy_axes_operations.ipynb new file mode 100644 index 0000000..fee8997 --- /dev/null +++ b/lessons/common_libs/NumPy_axes_operations.ipynb @@ -0,0 +1,738 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "28ce25bd-a7cc-45ba-b502-0b00f089facb", + "metadata": {}, + "source": [ + "# NumPy Operations" + ] + }, + { + "cell_type": "markdown", + "id": "5f375c7b-ea30-469e-a8c4-84f036ce200c", + "metadata": {}, + "source": [ + "In the _previous lesson_, you've seen how we can use NumPy to easily and efficiently apply operations to whole _arrays_ of numbers, rather than having to painstakinly apply them to each number individually.\n", + "\n", + "Now, we'll look in more detail on ways to control _how_ these operations are applied, especially in the (common) case of arrays having more than one dimension." + ] + }, + { + "cell_type": "markdown", + "id": "2280072b-353f-455b-a589-fc3685a505bb", + "metadata": {}, + "source": [ + "## Learning outcomes" + ] + }, + { + "cell_type": "markdown", + "id": "887b7149-cdc4-425b-8d09-8a6ee27d1df8", + "metadata": {}, + "source": [ + "- Build familiarity with multi-dimensional arrays of numbers in NumPy\n", + "- Be able to access \"slices\" of data from multi-dimensional arrays\n", + "- Perform basic statistical functions selectively along dimensions (\"axes\") of an array\n", + "- Find the indices of the maximum and minimum elements of an array" + ] + }, + { + "cell_type": "markdown", + "id": "0fcbb3e5-f4ed-4f3d-8531-170168118656", + "metadata": {}, + "source": [ + "Up until now, we've mostly been looking at _one-dimensional_ arrays -- basically, lists of numbers. You can access _elements_ of this array by _index_ -- an integer specifying the location of the data in the array.\n", + "\n", + "However, there are many reasons we might want to use _multiple indices_ to organize our data, especially when these indices represent something more than just position in a list. For instance, take the example from the previous lesson, where we have a list of temperatures of the same substance measured at several different times. Let's say that each of these measurements was taken at a different time of day. Therefore, your index also tells you what time of day the corresponding measurement was made.\n", + "\n", + "Now, let's say you repeat this experiment (repeated temperature measurements of the same substance) on several different days, but taking care to take the measurements at the same _times of day_ as your first series of measurements. You could just put all the measurements into one list, but then it wouldn't be very easy to figure out which index (position in the overall list) corresponds to which day of measurement and which time of day. It would be much nicer to have _two_ indices, one referring to the day of measurement and one referring to the time of day.\n", + "\n", + "In fact, NumPy arrays let you do exactly this -- you can create a _two-dimensional_ array with two indices specifying the location of a data point in the array.\n", + "\n", + "There are many ways we can create such an array, but let's just say for now that you've recorded your data by making lists of your observations from each day, and collected those lists into one overall list, like so:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1e77cb01-1f98-40da-a3d3-b89d70b9f086", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24bf5d06-fb73-41a7-94a2-51e0799c9451", + "metadata": {}, + "outputs": [], + "source": [ + "from matplotlib import pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "id": "f6e506d8-13de-45c8-9e4f-c1b86beb6bed", + "metadata": {}, + "source": [ + "(data generation code at the end of the notebook)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72a50b4d-2bba-4de4-ba0a-a424c6ca083c", + "metadata": {}, + "outputs": [], + "source": [ + "my_measurements = [[19.43, 20.84, 20.59, 21.51, 21.75, 22.08, 21.22], # Day 1\n", + " [19.63, 20.59, 20.96, 21.42, 21.69, 21.72, 21.33], # Day 2\n", + " [19.58, 20.63, 20.98, 21.23, 21.74, 21.59, 21.64], # Day 3\n", + " [19.19, 19.90, 20.66, 21.26, 21.28, 21.32, 20.71], # Day 4\n", + " [19.64, 20.20, 20.97, 21.32, 21.86, 21.80, 21.43]] # Day 5\n", + "times_of_day = [9.0, 11.0, 12.5, 13.5, 15.0, 17.0, 19.0]" + ] + }, + { + "cell_type": "markdown", + "id": "ac757314-83e1-4e2d-a320-8736222fc606", + "metadata": {}, + "source": [ + "**Note:** What is missing from the above cell? What additional information do we need to make this data meaningful and useful to other people?" + ] + }, + { + "cell_type": "markdown", + "id": "c2a83153-715a-4acd-b4e1-6fe1115518ae", + "metadata": {}, + "source": [ + "And now we'll convert these rather unwieldy data structures into NumPy arrays, the usual way:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ed53150-93af-49ed-811a-b071d4a6661d", + "metadata": {}, + "outputs": [], + "source": [ + "measurements = np.array(my_measurements)\n", + "times = np.array(times_of_day)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "590d8c7f-bee8-41b4-9056-f52353b7c08b", + "metadata": {}, + "outputs": [], + "source": [ + "measurements" + ] + }, + { + "cell_type": "markdown", + "id": "a30d5bf0-48c9-4e79-a618-3899f5cd4b2b", + "metadata": {}, + "source": [ + "Looks pretty similar. What happens when we try accessing an index of this array?" + ] + }, + { + "cell_type": "markdown", + "id": "347c4cc7-0562-42b0-972e-414fc2c5b66f", + "metadata": {}, + "source": [ + "## Accessing elements of an array" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7730e210-526d-401f-b119-006ac61c2638", + "metadata": {}, + "outputs": [], + "source": [ + "measurements[2]" + ] + }, + { + "cell_type": "markdown", + "id": "7e6ad026-239c-4515-aa32-5c9c6f89dee7", + "metadata": {}, + "source": [ + "We get a whole list of numbers! This is one of the _rows_ of the above array -- technically, what we've just done is called \"_slicing_\" (more on that later).\n", + "\n", + "So how do we access an individual element?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "86fce8ad-5d53-4d78-9214-d8264c8ea167", + "metadata": {}, + "outputs": [], + "source": [ + "measurements[2, 0]" + ] + }, + { + "cell_type": "markdown", + "id": "d9a94c9c-0129-4f9a-b1c0-06a9bb03201d", + "metadata": {}, + "source": [ + "Notice how we now have _two indices_, separated by a comma. The first index selects the day and the second index selects the time of day. Note how in the printed representation above, the _first index_ corresponds to the _row_ and the _second index_ corresponds to the _column_. This is the same as the convention used in linear algebra for indexing elements of a matrix.\n", + "\n", + "On their own, however, these indices don't really tell us much. For instance, how do we know what time of day a `0` corresponds to? Luckily, we've already stored this information in another array:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb638a6f-9a2b-474d-bb1b-0709d122e500", + "metadata": {}, + "outputs": [], + "source": [ + "times[0]" + ] + }, + { + "cell_type": "markdown", + "id": "7e387455-1af5-47eb-be0c-713c3914bdd5", + "metadata": {}, + "source": [ + "So 9am. Later on, you'll learn how to use the `pandas` library to label our data axes in a way that is both easier to use and to understand, but for now it's simpler if we just stick to NumPy arrays." + ] + }, + { + "cell_type": "markdown", + "id": "5ec84e8e-29d5-4542-b1db-49956b221fdb", + "metadata": {}, + "source": [ + "Now it's **your turn**. How would you access the measurement made at 11am on Day 4? How about 5pm on Day 1?" + ] + }, + { + "cell_type": "markdown", + "id": "1e6f33ef-5f0e-471a-a1f5-cc0f83c322ac", + "metadata": {}, + "source": [ + "## Slicing" + ] + }, + { + "cell_type": "markdown", + "id": "57e837d6-ed5d-44ee-a69b-9823fff20444", + "metadata": {}, + "source": [ + "Before, we saw that indexing our 2-d array with a single number actually gave us an entire _row_ of the array. This is a special case of a behaviour called \"slicing\", which is a way to access multiple elements of an array at once.\n", + "\n", + "What if we wanted to access an entire _column_ of the array instead? (In this case, all the measurements made at a given time of each day)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "be7922fc-9ce8-454e-9c24-4e9b528308df", + "metadata": {}, + "outputs": [], + "source": [ + "measurements[:, 2]" + ] + }, + { + "cell_type": "markdown", + "id": "ecf40f14-3476-43a1-97e0-16b88cc47eaf", + "metadata": {}, + "source": [ + "This gives us all measurements made at 12:30 on each of the 5 days:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d481d7e8-e9b9-42b7-a65a-9374c4b429ac", + "metadata": {}, + "outputs": [], + "source": [ + "times[2]" + ] + }, + { + "cell_type": "markdown", + "id": "dc38e5e4-9731-46cc-b0e4-eb1c7c417ccd", + "metadata": {}, + "source": [ + "Notice this syntax looks very similar to the two-index form we used to access individual elements above. We've just replaced one of the indices (the row index) with a colon (`:`), which tells NumPy to give us _all_ the rows for the selected column index.\n", + "\n", + "We can also do this to select rows:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07e07474-754a-4135-9960-de2d6a061e78", + "metadata": {}, + "outputs": [], + "source": [ + "measurements[2, :]" + ] + }, + { + "cell_type": "markdown", + "id": "09c24074-4720-46bc-966a-5cb2caf3c348", + "metadata": {}, + "source": [ + "which gives us the same result as the first indexing statement we tried (`measurements[2]`). In fact, if you specify fewer _indices_ than the array has _dimensions_, NumPy will automatically add colons (\"select all\") at the end, corresponding to the remaining (unspecified) dimensions." + ] + }, + { + "cell_type": "markdown", + "id": "13d273d9-4306-4ab8-84a0-b22a52d9ec82", + "metadata": {}, + "source": [ + "## Axes 🪓🪓🪓" + ] + }, + { + "cell_type": "markdown", + "id": "cb88caa0-6438-450f-9500-0e5d77b52931", + "metadata": {}, + "source": [ + "(no, not that kind...)" + ] + }, + { + "cell_type": "markdown", + "id": "322dbc96-33dc-4f1e-92f8-49df2642ac44", + "metadata": {}, + "source": [ + "We've used the term \"indices\" and \"dimensions\" somewhat interchangeably a few times, and now, unfortunately, we'll be introducing another near-synonym: **axes** (plural of \"axis\"). This is the term that the NumPy documentation formally uses to refer to each of the dimensions of an array. For instance, in a statement such as:\n", + "\n", + " measurements[2, 0]\n", + "\n", + "we say we're selecting _index_ 2 along _axis 0_ (remember, in Python we almost always start counting from zero...), and _index_ 0 along _axis_ 1. The array has two _dimensions_ in total. (Confused yet?)\n", + "\n", + "Why is all this terminology relevant? For one, you'll need it to understand the NumPy documentation. Let's take a look at the documentation for a simple function:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b230b206-8cf6-4a53-a19c-b9cf67da3df3", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "?np.mean" + ] + }, + { + "cell_type": "markdown", + "id": "74e6aa53-491c-4595-949c-92c34222b3f3", + "metadata": {}, + "source": [ + "There's a lot of information there we still don't need, but let's focus on the paragraph:\n", + "\n", + " Returns the average of the array elements. The average is taken over\n", + " the flattened array by default, otherwise over the specified axis.\n", + " ...\n", + "\n", + "What does this mean? First, let's see what this default behaviour is:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11ab63d1-da2a-418a-ae05-019f021c7dc8", + "metadata": {}, + "outputs": [], + "source": [ + "np.mean(measurements)" + ] + }, + { + "cell_type": "markdown", + "id": "7ceca933-ef41-40f7-b299-d865462f8d32", + "metadata": {}, + "source": [ + "It's taken the average over the _whole array_, without regard to the structure or dimensions (hence, \"flattened\"). But part of the reason we organized it into two dimensions was that we could keep track of this structure, i.e. look at the day and time of measurement independently. What if we want to take the average only over the _time of day_, while keeping the _days_ themselves independent?" + ] + }, + { + "cell_type": "markdown", + "id": "41ff6400-3b7d-40f8-b306-8ef8caff5881", + "metadata": {}, + "source": [ + "In NumPy terminology, we'd be taking the average (mean) _along the axis_ representing time of day. Since we use the second axis to select the time of day, this means we're averaging along axis 1 (we count from zero, remember)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "863c882b-b930-4c2a-8031-e6aadaf7b760", + "metadata": {}, + "outputs": [], + "source": [ + "np.mean(measurements, axis=1)" + ] + }, + { + "cell_type": "markdown", + "id": "a8b1d4d5-7a4b-474a-b901-763ca2a50f85", + "metadata": {}, + "source": [ + "Other summary statistics functions work in a similar way:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "153ddfa9-adc5-40d8-ad24-7fe766157641", + "metadata": {}, + "outputs": [], + "source": [ + "# Standard deviation with the \"N-1\" correction for small sample sizes\n", + "# This is sometimes called \"Bessel's correction\"\n", + "np.std(measurements, axis=1, ddof=1)" + ] + }, + { + "cell_type": "markdown", + "id": "96cd2a4a-ec8a-4636-8278-2f86b8fe2739", + "metadata": {}, + "source": [ + "It seems there's a fair amount of variation over the course of a single day. What about between the individual days? And let's keep the times of day separate to see what that variation might look like." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c569f63c-1519-4f58-85ea-3b21e5088507", + "metadata": {}, + "outputs": [], + "source": [ + "measurement_time_means = np.mean(measurements, axis=0)\n", + "measurement_time_means" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b12f0812-f3c4-4b45-a8dc-ad207664dc97", + "metadata": {}, + "outputs": [], + "source": [ + "np.std(measurements, axis=0, ddof=1)" + ] + }, + { + "cell_type": "markdown", + "id": "d90b2491-d6e7-4118-bdb5-f2d936c808ab", + "metadata": {}, + "source": [ + "Now, given what you know about statistics: Is there a statistically significant difference between the temperatures measured at different times of day?\n", + "\n", + "Let's take the smallest and largest temperatures and do a classic hypothesis test. We'll use the _standard deviation of the mean_ here, since we're comparing two means:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3608c492-ae66-4422-a572-d042cbcc5022", + "metadata": {}, + "outputs": [], + "source": [ + "st_means = np.std(measurements, axis=0, ddof=1) / np.sqrt(5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51e24f04-9210-4f5a-85ff-e93c765dfe76", + "metadata": {}, + "outputs": [], + "source": [ + "st_means" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "155f0b90-4af9-4f4b-bbc8-de590c34d84e", + "metadata": {}, + "outputs": [], + "source": [ + "# Compute the \"t-score\"\n", + "(21.702 - 19.494) / np.sqrt(0.085**2 + 0.125**2)" + ] + }, + { + "cell_type": "markdown", + "id": "4d456d53-2cfa-46a1-99b5-8bc0b3fe7ed2", + "metadata": {}, + "source": [ + "This suggests the difference between the two values is more than 14 times the standard deviation of a hypothetical Gaussian distribution, if we assume that both values were drawn from the same distribution. This seems highly unlikely (it would definitely pass the \"$p$-test\", as the \"$p$-value\" is less than the magical value of 0.05 at differences larger than about 3 times the standard deviation). Therefore, we can reject the \"null hypothesis\" and say that the two values are clearly different.\n", + "\n", + "(There's a _lot_ of statistical rigor being glossed over here, not the least of which being that we're using _incredibly small_ sample sizes here, so the typical tools of statistics don't really work, and also we should be using a Student's $t$-test rather than assuming a Gaussian distribution -- the main point is, the two averages are _clearly_ different, and almost any rigorous statistical test you could apply here would tell you as much.)" + ] + }, + { + "cell_type": "markdown", + "id": "8a10beea-de5c-4e30-bf11-758d41ef43c9", + "metadata": {}, + "source": [ + "## Getting unknown indices" + ] + }, + { + "cell_type": "markdown", + "id": "2e5d0632-6ea3-4115-824d-44d6cc8d7a97", + "metadata": {}, + "source": [ + "In the test above, we just manually copied and pasted the largest and smallest array values from visual inspection. This is fine for a short demo, but in real applications with lots of data we'll need a more systematic, automatic approach.\n", + "\n", + "We already know how to get the maximum and minimum array _values_ -- there are NumPy functions that do this:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0f132ce4-3474-4c26-96d5-ac400f3679c1", + "metadata": {}, + "outputs": [], + "source": [ + "np.max(measurement_time_means)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "492ab1a5-de56-4a44-91f3-6d08d65120cf", + "metadata": {}, + "outputs": [], + "source": [ + "np.min(measurement_time_means)" + ] + }, + { + "cell_type": "markdown", + "id": "749ed217-4a26-4afb-807e-b4787fe2dc16", + "metadata": {}, + "source": [ + "But what if we want to find out _where_ in the array these values occur? Luckily, there are NumPy functions for this too, they just have less intuitive names:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9939b289-27eb-4416-b15e-dcab8c09086b", + "metadata": {}, + "outputs": [], + "source": [ + "# Think \"argument of the max\", as in \"index\" of maximum value\n", + "np.argmax(measurement_time_means)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9f3a8264-9af6-4ce0-8204-48ac0dd0d934", + "metadata": {}, + "outputs": [], + "source": [ + "measurement_time_means[np.argmax(measurement_time_means)]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fca0b382-e806-41e8-87d2-97ee86f0effc", + "metadata": {}, + "outputs": [], + "source": [ + "np.argmin(measurement_time_means)" + ] + }, + { + "cell_type": "markdown", + "id": "75560f1a-9bdd-41ce-8469-48390bdbddd5", + "metadata": {}, + "source": [ + "These functions are handy for finding the _corresponding value_ in an array of the same size, where the axis you're indexing represents the same thing. For instance: What if we want to know the time of day that the maximum and minimum (mean) temperature occurs?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "427c0f0b-e755-410f-9caa-3e7dd715e8f4", + "metadata": {}, + "outputs": [], + "source": [ + "times[np.argmax(measurement_time_means)]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc2528da-6332-46db-919a-351c2bf3fa2b", + "metadata": {}, + "outputs": [], + "source": [ + "times[np.argmin(measurement_time_means)]" + ] + }, + { + "cell_type": "markdown", + "id": "640880a6-1bd3-4594-8d70-2c12f416cfe1", + "metadata": {}, + "source": [ + "So our highest (average) temperature is measured at 5pm and the lowest is at 9am." + ] + }, + { + "cell_type": "markdown", + "id": "ba892745-a144-41ba-8736-bb998fc5f2f2", + "metadata": {}, + "source": [ + "Now, it's **your turn**! Please _use_ the `argmin` and `argmax` functions to perform the hypothesis test above. As a reminder, we need to:\n", + "\n", + "- Find the maximum and minimum values of the `measurement_time_means` array\n", + "- Find the corresponding _standard deviation of the mean_ in the `st_means` array\n", + "- Compute the difference between the maximum and minimum (mean) temperatures\n", + "- Compute the standard deviation of the (hypothetical) Gaussian distribution of differences by adding the _variances_: $\\sigma_\\mathrm{diff} = \\sqrt{\\sigma_1^2 + \\sigma_2^2}$\n", + "- Divide the difference by the combined standard deviation to get the $t$-score. You should get the same answer (about 14.6) as above." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bf89e6fd-f958-41d1-a7eb-150c3a273db2", + "metadata": {}, + "outputs": [], + "source": [ + "temp_max = np.max(measurement_time_means)\n", + "st_mean_max = st_means[np.argmax(measurement_time_means)]\n", + "\n", + "# Do the same for the min\n", + "\n", + "# Compute the temperature difference\n", + "\n", + "# Compute the combined standard deviation\n", + "\n", + "# Compute the t-score" + ] + }, + { + "cell_type": "markdown", + "id": "1eeb23a1-bb2b-4210-b78a-a36f0c726a64", + "metadata": {}, + "source": [ + "# TODO\n", + "\n", + "- Argmax/min in multiple dimensions?\n", + "- Application: Find the center of geometry (COG) of a molecule given its coordinates. Subtract this from the coordinates (broadcasting!) to get the coordinates in the COG frame.\n", + "- Introduce broadcasting!\n", + "- Application: Now compute the center of mass (COM) by weighting the coordinates by the corresponding atomic masses.\n", + "- Any other indexing / multi-D / slicing topics or applications?" + ] + }, + { + "cell_type": "markdown", + "id": "1236ae69-c1c3-40e0-bff9-7dcbe8fa3636", + "metadata": {}, + "source": [ + "# Data generation code (should stay hidden)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69d7d5c2-abce-492e-b7ee-04e9751d8dc2", + "metadata": {}, + "outputs": [], + "source": [ + "base_hours = np.array([9.0, 11.0, 12.5, 13.5, 15.0, 17.0, 19.0])\n", + "base_trend = np.cos((base_hours - 4) * np.pi / 12.) * -1.8 + 20.0\n", + "noise_points = np.random.normal(size=(5, 7)) * 0.15\n", + "meas_pts = base_trend + noise_points" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab92c71d-fa5c-4a9f-a7e2-1494a17cbd59", + "metadata": {}, + "outputs": [], + "source": [ + "# Simulate a systematic measurement error one one day only\n", + "meas_pts[3] -= 0.4" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a96bf7d-e304-4cd1-a24f-56f297064f7d", + "metadata": {}, + "outputs": [], + "source": [ + "meas_pts" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52b74e6d-6744-4acd-a17f-9df9c76b1948", + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(base_hours, base_trend)\n", + "for series in meas_pts:\n", + " plt.scatter(base_hours, series)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "358cf0e0-a197-4c38-b3bb-aad77748c1f3", + "metadata": {}, + "outputs": [], + "source": [ + "print(np.array2string(meas_pts, precision=2, separator=', ', floatmode='fixed'))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b9a64e44-1823-440c-b02f-d70126b94a3d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.13.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/lessons/common_libs/Venus data.csv b/lessons/common_libs/Venus data.csv new file mode 100644 index 0000000..e205166 --- /dev/null +++ b/lessons/common_libs/Venus data.csv @@ -0,0 +1,79 @@ +,altitude,so,so2 +1,-0.704689723,6.10E-16,7.35E-06 +2,-0.665537672,6.14E-16,7.35E-06 +3,-0.560130865,6.38E-16,7.35E-06 +4,-0.338212662,7.16E-16,7.35E-06 +5,0.04588663,8.12E-16,7.35E-06 +6,0.636510833,9.03E-16,7.35E-06 +7,1.475348372,9.73E-16,7.35E-06 +8,2.600597941,1.02E-15,7.36E-06 +9,4.04613478,1.06E-15,7.39E-06 +10,5.840365711,1.07E-15,7.44E-06 +11,8.004692432,1.27E-15,7.56E-06 +12,10.55303372,5.92E-15,7.72E-06 +13,13.49135509,2.57E-14,7.91E-06 +14,16.81617891,6.80E-14,8.11E-06 +15,20.50942658,1.33E-13,8.27E-06 +16,24.44175194,2.84E-13,8.37E-06 +17,28.33343924,6.29E-13,8.43E-06 +18,32.01034726,1.10E-14,8.47E-06 +19,35.47595331,1.08E-15,8.47E-06 +20,38.71806531,3.80E-16,8.30E-06 +21,41.71853186,1.26E-16,7.90E-06 +22,44.50716306,1.23E-15,7.36E-06 +23,47.13362277,1.08E-14,6.92E-06 +24,49.60762433,7.45E-14,6.73E-06 +25,51.92295942,3.59E-13,6.65E-06 +26,54.07841631,1.55E-12,6.57E-06 +27,56.0802577,6.21E-12,6.45E-06 +28,57.93635846,1.46E-11,6.20E-06 +29,59.66297308,1.19E-11,5.58E-06 +30,61.28797567,2.49E-12,4.49E-06 +31,62.84736579,6.18E-12,3.25E-06 +32,64.41679145,1.61E-10,2.20E-06 +33,66.05791283,6.82E-10,1.38E-06 +34,67.75125984,1.32E-09,7.87E-07 +35,69.45006449,1.55E-09,4.30E-07 +36,71.12910436,1.55E-09,2.44E-07 +37,72.78328276,1.47E-09,1.60E-07 +38,74.42006023,1.41E-09,1.26E-07 +39,76.06583954,1.52E-09,1.11E-07 +40,77.73644499,1.69E-09,1.04E-07 +41,79.41103965,1.91E-09,9.87E-08 +42,81.05759183,2.12E-09,9.49E-08 +43,82.66393287,2.34E-09,9.35E-08 +44,84.22272226,2.64E-09,9.46E-08 +45,85.72809876,3.08E-09,9.58E-08 +46,87.39159687,3.76E-09,9.39E-08 +47,89.52876629,4.99E-09,9.01E-08 +48,92.09026302,7.54E-09,8.97E-08 +49,94.95427289,1.27E-08,8.88E-08 +50,98.00461311,1.46E-08,8.49E-08 +51,100.3931795,1.49E-08,7.89E-08 +52,102.2482482,1.41E-08,7.50E-08 +53,104.202286,1.75E-08,6.84E-08 +54,106.2514884,2.43E-08,6.02E-08 +55,108.367703,3.22E-08,5.17E-08 +56,110.5543634,4.18E-08,4.19E-08 +57,112.844633,5.25E-08,3.08E-08 +58,115.1585347,6.07E-08,2.19E-08 +59,117.3241908,6.62E-08,1.54E-08 +60,119.3478514,6.99E-08,1.07E-08 +61,121.2903091,7.22E-08,6.78E-09 +62,123.215108,7.30E-08,3.70E-09 +63,125.1267531,7.18E-08,1.84E-09 +64,126.9761047,6.87E-08,9.27E-10 +65,128.9080548,6.42E-08,4.77E-10 +66,130.9197488,5.87E-08,2.36E-10 +67,132.9497676,5.30E-08,1.16E-10 +68,135.0520522,4.72E-08,5.81E-11 +69,137.2246967,4.11E-08,2.41E-11 +70,139.5137683,3.48E-08,8.62E-12 +71,141.972967,2.87E-08,3.08E-12 +72,144.7091226,2.27E-08,1.22E-12 +73,147.8488383,1.70E-08,5.20E-13 +74,151.5060422,1.20E-08,2.54E-13 +75,155.7536542,7.86E-09,1.44E-13 +76,160.6153844,4.82E-09,8.65E-14 +77,166.0589755,2.81E-09,5.09E-14 +78,172.0472616,1.62E-09,2.61E-14 diff --git a/lessons/common_libs/Vit C in Orange Juice.csv b/lessons/common_libs/Vit C in Orange Juice.csv new file mode 100644 index 0000000..7bc1d85 --- /dev/null +++ b/lessons/common_libs/Vit C in Orange Juice.csv @@ -0,0 +1,121 @@ +Freshly squeezed orange juice - Unpasteurised (mg/100 mL),Premium (Industry pasteurised) juice (mg/100 mL),Budget (UHT) juice (mg/ 100 mL),Organic Juice (mg/ 100mL) +82.2016,62.0464,32.8016,63.232 +98.0096,62.244,36.556,56.316 +95.836,65.8008,31.8136,59.0824 +101.0724,64.22,41.5948,60.8608 +82.992,59.0824,34.7776,63.6272 +83.98,63.726,33.4932,59.8728 +77.064,64.3188,43.6696,76.9652 +101.27,64.714,32.604,65.9984 +82.004,60.0704,31.2208,64.0224 +97.6144,81.8064,36.556,73.112 +76.6688,67.5792,28.0592,56.316 +91.1924,54.5376,27.664,48.6096 +94.9468,63.4296,33.592,66.3936 +70.5432,51.376,51.5736,21.5384 +72.124,53.846,22.724,53.352 +87.1416,55.5256,27.664,50.5856 +99.788,64.22,35.568,65.6032 +91.884,63.726,34.58,61.256 +70.3456,60.8608,32.0112,60.0704 +78.8424,68.172,52.7592,44.46 +91.6864,55.7232,25.8856,52.7592 +87.0428,67.184,33.6908,45.6456 +98.8,65.9984,37.4452,61.256 +91.4888,56.7112,28.8496,50.388 +85.5608,67.184,33.7896,57.1064 +82.2016,63.4296,37.7416,63.0344 +78.2496,55.1304,17.1912,52.5616 +84.3752,61.6512,31.616,45.8432 +94.4528,63.8248,35.3704,64.0224 +94.848,53.352,17.784,56.6124 +91.4888,54.1424,13.4368,54.34 +95.836,59.28,29.146,64.22 +67.5792,57.5016,21.736,51.1784 +71.4324,45.2504,6.916,42.5828 +72.9144,57.304,30.5292,50.388 +99.1952,58.8848,28.2568,61.256 +113.62,51.376,8.892,47.424 +90.1056,52.364,21.5384,51.7712 +101.9616,64.8128,34.3824,62.4416 +82.2016,61.3548,34.1848,43.5708 +120.2396,74.4952,31.2208,81.3124 +70.3456,60.0704,35.3704,61.6512 +86.5488,61.1572,34.4812,53.0556 +85.7584,65.8996,33.8884,65.3068 +88.7224,60.268,25.2928,50.9808 +79.04,63.4296,33.7896,66.196 +79.2376,57.1064,38.1368,48.6096 +90.5008,64.0224,32.0112,64.6152 +86.944,60.268,30.628,54.34 +96.824,66.196,33.592,63.3308 +0,64.22,29.64,63.232 +70.3456,62.6392,34.58,65.208 +95.836,60.268,33.592,59.28 +71.63,57.4028,14.326,50.5856 +104.728,103.9376,28.652,64.22 +84.5728,59.0824,21.736,52.9568 +98.0096,67.184,39.52,61.256 +84.968,63.8248,33.3944,72.124 +82.004,52.7592,41.496,73.112 +96.824,41.496,23.712,58.292 +83.7824,62.244,33.3944,64.6152 +96.824,62.4416,30.8256,57.6992 +95.4408,63.6272,31.0232,58.9836 +94.0576,64.8128,36.4572,64.0224 +86.3512,62.0464,33.1968,64.0224 +83.98,64.4176,33.4932,60.268 +77.558,73.7048,42.6816,76.076 +98.8,65.208,34.086,65.208 +84.968,64.0224,32.0112,64.0224 +94.0576,79.4352,36.7536,65.702 +77.8544,66.3936,24.5024,56.9088 +89.1176,55.1304,22.9216,46.0408 +95.9348,63.6272,30.8256,66.196 +70.3456,51.7712,51.5736,20.9456 +75.088,53.9448,23.1192,53.352 +86.7464,55.822,28.158,51.376 +98.8,65.208,34.1848,62.244 +90.896,62.6392,35.4692,61.4536 +81.2136,64.4176,27.2688,64.4176 +80.4232,68.3696,47.0288,44.5588 +92.6744,57.304,25.2928,52.7592 +87.1416,64.22,33.9872,45.6456 +98.6024,66.196,37.544,62.244 +92.6744,57.304,30.628,51.1784 +88.7224,67.3816,33.9872,54.5376 +80.6208,61.256,41.496,57.5016 +82.3992,52.9568,17.784,56.316 +83.3872,55.328,32.604,45.448 +95.0456,64.8128,34.1848,0 +96.824,52.5616,15.808,52.7592 +92.872,53.1544,13.4368,54.5376 +90.402,51.376,29.64,60.268 +67.7768,58.0944,20.3528,52.364 +69.16,50.4868,7.904,42.3852 +72.7168,57.304,30.628,50.388 +99.5904,61.256,27.4664,61.0584 +123.5,59.28,11.856,46.436 +89.8092,52.2652,19.76,52.1664 +98.8,63.0344,36.1608,60.8608 +82.8932,60.6632,35.074,45.7444 +119.7456,78.9412,31.2208,79.534 +70.7408,59.0824,33.592,62.4416 +82.6956,60.762,33.2956,53.352 +85.6596,65.8996,33.6908,65.5044 +90.896,58.292,23.9096,48.8072 +84.2764,63.726,34.6788,64.22 +79.6328,56.9088,35.1728,46.436 +92.0816,64.4176,31.122,65.8008 +86.944,61.256,31.8136,53.7472 +91.884,64.22,33.098,63.0344 +79.6328,63.232,28.4544,57.6992 +72.9144,61.256,34.9752,66.7888 +94.7492,61.256,32.604,57.304 +72.618,58.1932,12.844,0 +95.0456,101.764,19.76,65.208 +84.5728,60.0704,20.3528,52.7592 +97.6144,65.208,37.544,59.0824 +84.968,64.22,36.7536,69.16 +87.932,61.256,37.544,68.172 +96.824,47.424,27.664,59.28 diff --git a/lessons/common_libs/intro_to_pandas.ipynb b/lessons/common_libs/intro_to_pandas.ipynb new file mode 100644 index 0000000..987d805 --- /dev/null +++ b/lessons/common_libs/intro_to_pandas.ipynb @@ -0,0 +1,327 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4e9376f84a7c26bc", + "metadata": {}, + "source": [ + "# Introduction to the Pandas Library" + ] + }, + { + "cell_type": "markdown", + "id": "16a10868d3450642", + "metadata": {}, + "source": [ + "*pandas* is a library within python that is designed to be used for data analysis. It is similar to Excel as it can handle large datasets, but with\n", + " the advantage of being able to manipulate the data in a programmable way.\n", + " You can\n", + "find the pandas documentation [here](https://pandas.pydata.org/docs/).\n", + "\n", + "\n", + "There is an [introductory video available](https://youtu.be/_T8LGqJtuGc) that tries to teach the basics of pands in just 10 minutes!" + ] + }, + { + "cell_type": "markdown", + "id": "5ddeb90892d82a5b", + "metadata": {}, + "source": [ + "### Prerequisites\n", + "- variables and data types\n", + "- libraries (not sure if this is needed)\n", + "- Boolean operators\n", + "- print\n", + "- f-strings" + ] + }, + { + "cell_type": "markdown", + "id": "a73114b516278ac5", + "metadata": {}, + "source": [ + "### Learning Outcomes\n", + "- Read and write files\n", + "- Understand what a dataframe is\n", + "- Check files are imported correctly\n", + "- Select a subset of a DataFrame\n", + "- Add new columns to a dataframe\n", + "- Calculate summary statistics\n" + ] + }, + { + "cell_type": "markdown", + "id": "5409de65537887d8", + "metadata": {}, + "source": [ + "The community standard alias for the pandas package is *pd*, which is assumed in the pandas documentation and in a lot of code you may see online." + ] + }, + { + "cell_type": "code", + "id": "705306f1027fa7e", + "metadata": {}, + "source": "import pandas as pd", + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "159944926f25cdc9", + "metadata": {}, + "source": "## Reading files" + }, + { + "cell_type": "markdown", + "id": "9f8ce7a24299e71c", + "metadata": {}, + "source": [ + "In pandas, it is useful to read data into a [**DataFrame**](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html#pandas.DataFrame),\n", + "which is similar to an Excel spreadsheet:\n", + "\n", + "![Pandas DataFrame](DataFrame.png)\n", + "\n", + "There are many ways to read data into pandas depending on the file type, but for regular delimited files,\n", + " the function [`read_csv`](https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html) can be used." + ] + }, + { + "cell_type": "code", + "id": "6ef4f4222b561d3e", + "metadata": {}, + "source": [ + "data = pd.read_csv(\"periodic_table.csv\")\n", + "data" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "946227594d5d4492", + "metadata": {}, + "source": [ + "> This function assumes the data is comma separated, for other separators you can specify it using the delimiter parameter. If the separator is not a\n", + "regular character (e.g. a tab, multiple spaces), an internet search should tell you what string to use. E.g. for a *tab* separated file:\n", + ">\n", + "> ```data_tab = pd.read_csv(\"**need to get a file**\", delimiter=\"\\t\")```\n", + ">\n", + "> There are other parameters available, to specify the headers, the datatype etc. See [the documentation](https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html) for full details.\n" + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "### Viewing the data", + "id": "613367f256897f36" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "Now that we have imported the data, it is important to view it is fully understand how it is formatted and ensure we imported it correctly. As you\n", + "may have noticed, when we try to display the dataframe, only some of the rows display. This is because only the first and last 5 rows will be shown\n", + " by default. There are functions we can use to display specific\n", + "parts of the\n", + "dataframe:\n", + "\n", + "- `data.head()` shows rows from the top of the file\n", + "- `data.tail()` shows rows from the bottom of the file\n", + "- `data.columns` shows the column names (header)\n", + "\n", + "If a number is given to `head` and `tail`, it will display that many rows.\n", + "\n", + "It can also be useful to check how pandas *interpreted* the data, and then change it if necessary. The data type can be checked using `.dtypes` and\n", + "it can be changed using `.astype()`.\n", + "\n", + "To display the datatype of all columns, we can run the function on the whole dataframe:" + ], + "id": "c00ce268787d2503" + }, + { + "metadata": {}, + "cell_type": "code", + "source": "data.dtypes", + "id": "de5e7c4b8c29071a", + "outputs": [], + "execution_count": null + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "Or we can instead run the function on only one column:", + "id": "5d9551818a2553db" + }, + { + "metadata": {}, + "cell_type": "code", + "source": "data[\"AtomicNumber\"].dtype", + "id": "e4f7fa55f0ad8042", + "outputs": [], + "execution_count": null + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "To change the data type, we need to reassign that column. E.g. to change the \"Name\" data to a string:", + "id": "b870cf77a1aea35f" + }, + { + "metadata": {}, + "cell_type": "code", + "source": [ + "print(f'Data type before change: {data[\"Name\"].dtype}')\n", + "data[\"Name\"] = data[\"Name\"].astype(\"string\")\n", + "print(f'Data type after change: {data[\"Name\"].dtype}')" + ], + "id": "d976fecb52130b29", + "outputs": [], + "execution_count": null + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## Exercise\n", + "\n", + "Display the first 8 elements." + ], + "id": "822ab5f3e84a6ff2" + }, + { + "metadata": {}, + "cell_type": "code", + "source": "# Add your answer here", + "id": "bce6df361acf974", + "outputs": [], + "execution_count": null + }, + { + "metadata": {}, + "cell_type": "code", + "source": [ + "# Answer\n", + "data.head(8)" + ], + "id": "ac14452b9f70836e", + "outputs": [], + "execution_count": null + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "What element has atomic number 110? Hint: The table has 118 elements in it.", + "id": "ba7c9cb041afd40d" + }, + { + "metadata": {}, + "cell_type": "code", + "source": "# Add your answer here", + "id": "1c4beea42f5bb2d8", + "outputs": [], + "execution_count": null + }, + { + "metadata": {}, + "cell_type": "code", + "source": [ + "# Answer\n", + "data.tail(9)\n", + "\n", + "# The element with an atomic number of 110 is Darmstadtium." + ], + "id": "82f5627d2fea26b7", + "outputs": [], + "execution_count": null + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "Change the \"Symbol\" data to strings. Check the data type of the column after.", + "id": "9885f5ed07d28703" + }, + { + "metadata": {}, + "cell_type": "code", + "source": "# Add your answer here", + "id": "7fa9904a9de0f284", + "outputs": [], + "execution_count": null + }, + { + "metadata": {}, + "cell_type": "code", + "source": [ + "# Answer\n", + "data[\"Symbol\"] = data[\"Symbol\"].astype(\"string\")\n", + "print(f'Data type after change: {data[\"Symbol\"].dtype}')" + ], + "id": "d6403b10cf05d3b9", + "outputs": [], + "execution_count": null + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## Writing files\n", + "\n", + "As with reading files, there are many ways to write data to a file depending on the file type wanted, but for regular delimited files,\n", + " the function [`to_csv`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_csv.html) can be used.\n", + "\n", + "As DataFrames have an index column, we have to decide if we want to keep this or not. We can do this using the `index` parameter. To **NOT**\n", + "include the index column, use `index=False`." + ], + "id": "420135f8853d1421" + }, + { + "metadata": {}, + "cell_type": "code", + "source": "data.to_csv(\"periodic_table_out.csv\", index=False)", + "id": "484f5eeecf6e9533", + "outputs": [], + "execution_count": null + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "> As with reading files, we can specify what separator we want the data to be written using `sep`. There are many other useful parameters for\n", + "> specifying what data to save and how to save it. See [the documentation](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_csv.html) for more infromation." + ], + "id": "8cb03b854e801781" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "# To Do\n", + "- select a subset of a df\n", + "- create new columns\n", + "- calculate statistics" + ], + "id": "73f5ded338418595" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/lessons/common_libs/periodic_table.csv b/lessons/common_libs/periodic_table.csv new file mode 100644 index 0000000..4185845 --- /dev/null +++ b/lessons/common_libs/periodic_table.csv @@ -0,0 +1,119 @@ +"AtomicNumber","Symbol","Name","AtomicMass","CPKHexColor","ElectronConfiguration","Electronegativity","AtomicRadius","IonizationEnergy","ElectronAffinity","OxidationStates","StandardState","MeltingPoint","BoilingPoint","Density","GroupBlock","YearDiscovered" +1,"H","Hydrogen",1.0080,"FFFFFF","1s1",2.2,120,13.598,0.754,"+1, -1","Gas",13.81,20.28,0.00008988,"Nonmetal",1766 +2,"He","Helium",4.00260,"D9FFFF","1s2","",140,24.587,"","0","Gas",0.95,4.22,0.0001785,"Noble gas",1868 +3,"Li","Lithium",7.0,"CC80FF","[He]2s1",0.98,182,5.392,0.618,"+1","Solid",453.65,1615,0.534,"Alkali metal",1817 +4,"Be","Beryllium",9.012183,"C2FF00","[He]2s2",1.57,153,9.323,"","+2","Solid",1560,2744,1.85,"Alkaline earth metal",1798 +5,"B","Boron",10.81,"FFB5B5","[He]2s2 2p1",2.04,192,8.298,0.277,"+3","Solid",2348,4273,2.37,"Metalloid",1808 +6,"C","Carbon",12.011,"909090","[He]2s2 2p2",2.55,170,11.260,1.263,"+4, +2, -4","Solid",3823,4098,2.2670,"Nonmetal","Ancient" +7,"N","Nitrogen",14.007,"3050F8","[He] 2s2 2p3",3.04,155,14.534,"","+5, +4, +3, +2, +1, -1, -2, -3","Gas",63.15,77.36,0.0012506,"Nonmetal",1772 +8,"O","Oxygen",15.999,"FF0D0D","[He]2s2 2p4",3.44,152,13.618,1.461,"-2","Gas",54.36,90.2,0.001429,"Nonmetal",1774 +9,"F","Fluorine",18.99840316,"90E050","[He]2s2 2p5",3.98,135,17.423,3.339,"-1","Gas",53.53,85.03,0.001696,"Halogen",1670 +10,"Ne","Neon",20.180,"B3E3F5","[He]2s2 2p6","",154,21.565,"","0","Gas",24.56,27.07,0.0008999,"Noble gas",1898 +11,"Na","Sodium",22.9897693,"AB5CF2","[Ne]3s1",0.93,227,5.139,0.548,"+1","Solid",370.95,1156,0.97,"Alkali metal",1807 +12,"Mg","Magnesium",24.305,"8AFF00","[Ne]3s2",1.31,173,7.646,"","+2","Solid",923,1363,1.74,"Alkaline earth metal",1808 +13,"Al","Aluminum",26.981538,"BFA6A6","[Ne]3s2 3p1",1.61,184,5.986,0.441,"+3","Solid",933.437,2792,2.70,"Post-transition metal","Ancient" +14,"Si","Silicon",28.085,"F0C8A0","[Ne]3s2 3p2",1.9,210,8.152,1.385,"+4, +2, -4","Solid",1687,3538,2.3296,"Metalloid",1854 +15,"P","Phosphorus",30.97376200,"FF8000","[Ne]3s2 3p3",2.19,180,10.487,0.746,"+5, +3, -3","Solid",317.3,553.65,1.82,"Nonmetal",1669 +16,"S","Sulfur",32.07,"FFFF30","[Ne]3s2 3p4",2.58,180,10.360,2.077,"+6, +4, -2","Solid",388.36,717.75,2.067,"Nonmetal","Ancient" +17,"Cl","Chlorine",35.45,"1FF01F","[Ne]3s2 3p5",3.16,175,12.968,3.617,"+7, +5, +1, -1","Gas",171.65,239.11,0.003214,"Halogen",1774 +18,"Ar","Argon",39.9,"80D1E3","[Ne]3s2 3p6","",188,15.760,"","0","Gas",83.8,87.3,0.0017837,"Noble gas",1894 +19,"K","Potassium",39.0983,"8F40D4","[Ar]4s1",0.82,275,4.341,0.501,"+1","Solid",336.53,1032,0.89,"Alkali metal",1807 +20,"Ca","Calcium",40.08,"3DFF00","[Ar]4s2",1,231,6.113,"","+2","Solid",1115,1757,1.54,"Alkaline earth metal","Ancient" +21,"Sc","Scandium",44.95591,"E6E6E6","[Ar]4s2 3d1",1.36,211,6.561,0.188,"+3","Solid",1814,3109,2.99,"Transition metal",1879 +22,"Ti","Titanium",47.867,"BFC2C7","[Ar]4s2 3d2",1.54,187,6.828,0.079,"+4, +3, +2","Solid",1941,3560,4.5,"Transition metal",1791 +23,"V","Vanadium",50.9415,"A6A6AB","[Ar]4s2 3d3",1.63,179,6.746,0.525,"+5, +4, +3, +2","Solid",2183,3680,6.0,"Transition metal",1801 +24,"Cr","Chromium",51.996,"8A99C7","[Ar]3d5 4s1",1.66,189,6.767,0.666,"+6, +3, +2","Solid",2180,2944,7.15,"Transition metal",1797 +25,"Mn","Manganese",54.93804,"9C7AC7","[Ar]4s2 3d5",1.55,197,7.434,"","+7, +4, +3, +2","Solid",1519,2334,7.3,"Transition metal",1774 +26,"Fe","Iron",55.84,"E06633","[Ar]4s2 3d6",1.83,194,7.902,0.163,"+3, +2","Solid",1811,3134,7.874,"Transition metal","Ancient" +27,"Co","Cobalt",58.93319,"F090A0","[Ar]4s2 3d7",1.88,192,7.881,0.661,"+3, +2","Solid",1768,3200,8.86,"Transition metal",1735 +28,"Ni","Nickel",58.693,"50D050","[Ar]4s2 3d8",1.91,163,7.640,1.156,"+3, +2","Solid",1728,3186,8.912,"Transition metal",1751 +29,"Cu","Copper",63.55,"C88033","[Ar]4s1 3d10",1.9,140,7.726,1.228,"+2, +1","Solid",1357.77,2835,8.933,"Transition metal","Ancient" +30,"Zn","Zinc",65.4,"7D80B0","[Ar]4s2 3d10",1.65,139,9.394,"","+2","Solid",692.68,1180,7.134,"Transition metal",1746 +31,"Ga","Gallium",69.723,"C28F8F","[Ar]4s2 3d10 4p1",1.81,187,5.999,0.3,"+3","Solid",302.91,2477,5.91,"Post-transition metal",1875 +32,"Ge","Germanium",72.63,"668F8F","[Ar]4s2 3d10 4p2",2.01,211,7.900,1.35,"+4, +2","Solid",1211.4,3106,5.323,"Metalloid",1886 +33,"As","Arsenic",74.92159,"BD80E3","[Ar]4s2 3d10 4p3",2.18,185,9.815,0.81,"+5, +3, -3","Solid",1090,887,5.776,"Metalloid","Ancient" +34,"Se","Selenium",78.97,"FFA100","[Ar]4s2 3d10 4p4",2.55,190,9.752,2.021,"+6, +4, -2","Solid",493.65,958,4.809,"Nonmetal",1817 +35,"Br","Bromine",79.90,"A62929","[Ar]4s2 3d10 4p5",2.96,183,11.814,3.365,"+5, +1, -1","Liquid",265.95,331.95,3.11,"Halogen",1826 +36,"Kr","Krypton",83.80,"5CB8D1","[Ar]4s2 3d10 4p6",3,202,14.000,"","0","Gas",115.79,119.93,0.003733,"Noble gas",1898 +37,"Rb","Rubidium",85.468,"702EB0","[Kr]5s1",0.82,303,4.177,0.468,"+1","Solid",312.46,961,1.53,"Alkali metal",1861 +38,"Sr","Strontium",87.62,"00FF00","[Kr]5s2",0.95,249,5.695,"","+2","Solid",1050,1655,2.64,"Alkaline earth metal",1790 +39,"Y","Yttrium",88.90584,"94FFFF","[Kr]5s2 4d1",1.22,219,6.217,0.307,"+3","Solid",1795,3618,4.47,"Transition metal",1794 +40,"Zr","Zirconium",91.22,"94E0E0","[Kr]5s2 4d2",1.33,186,6.634,0.426,"+4","Solid",2128,4682,6.52,"Transition metal",1789 +41,"Nb","Niobium",92.90637,"73C2C9","[Kr]5s1 4d4",1.6,207,6.759,0.893,"+5, +3","Solid",2750,5017,8.57,"Transition metal",1801 +42,"Mo","Molybdenum",95.95,"54B5B5","[Kr]5s1 4d5",2.16,209,7.092,0.746,"+6","Solid",2896,4912,10.2,"Transition metal",1778 +43,"Tc","Technetium",96.90636,"3B9E9E","[Kr]5s2 4d5",1.9,209,7.28,0.55,"+7, +6, +4","Solid",2430,4538,11,"Transition metal",1937 +44,"Ru","Ruthenium",101.1,"248F8F","[Kr]5s1 4d7",2.2,207,7.361,1.05,"+3","Solid",2607,4423,12.1,"Transition metal",1827 +45,"Rh","Rhodium",102.9055,"0A7D8C","[Kr]5s1 4d8",2.28,195,7.459,1.137,"+3","Solid",2237,3968,12.4,"Transition metal",1803 +46,"Pd","Palladium",106.42,"6985","[Kr]4d10",2.2,202,8.337,0.557,"+3, +2","Solid",1828.05,3236,12.0,"Transition metal",1803 +47,"Ag","Silver",107.868,"C0C0C0","[Kr]5s1 4d10",1.93,172,7.576,1.302,"+1","Solid",1234.93,2435,10.501,"Transition metal","Ancient" +48,"Cd","Cadmium",112.41,"FFD98F","[Kr]5s2 4d10",1.69,158,8.994,"","+2","Solid",594.22,1040,8.69,"Transition metal",1817 +49,"In","Indium",114.818,"A67573","[Kr]5s2 4d10 5p1",1.78,193,5.786,0.3,"+3","Solid",429.75,2345,7.31,"Post-transition metal",1863 +50,"Sn","Tin",118.71,"668080","[Kr]5s2 4d10 5p2",1.96,217,7.344,1.2,"+4, +2","Solid",505.08,2875,7.287,"Post-transition metal","Ancient" +51,"Sb","Antimony",121.760,"9E63B5","[Kr]5s2 4d10 5p3",2.05,206,8.64,1.07,"+5, +3, -3","Solid",903.78,1860,6.685,"Metalloid","Ancient" +52,"Te","Tellurium",127.6,"D47A00","[Kr]5s2 4d10 5p4",2.1,206,9.010,1.971,"+6, +4, -2","Solid",722.66,1261,6.232,"Metalloid",1782 +53,"I","Iodine",126.9045,"940094","[Kr]5s2 4d10 5p5",2.66,198,10.451,3.059,"+7, +5, +1, -1","Solid",386.85,457.55,4.93,"Halogen",1811 +54,"Xe","Xenon",131.29,"429EB0","[Kr]5s2 4d10 5p6",2.6,216,12.130,"","0","Gas",161.36,165.03,0.005887,"Noble gas",1898 +55,"Cs","Cesium",132.9054520,"57178F","[Xe]6s1",0.79,343,3.894,0.472,"+1","Solid",301.59,944,1.93,"Alkali metal",1860 +56,"Ba","Barium",137.33,"00C900","[Xe]6s2",0.89,268,5.212,"","+2","Solid",1000,2170,3.62,"Alkaline earth metal",1808 +57,"La","Lanthanum",138.9055,"70D4FF","[Xe]6s2 5d1",1.1,240,5.577,0.5,"+3","Solid",1191,3737,6.15,"Lanthanide",1839 +58,"Ce","Cerium",140.116,"FFFFC7","[Xe]6s2 4f1 5d1",1.12,235,5.539,0.5,"+4, +3","Solid",1071,3697,6.770,"Lanthanide",1803 +59,"Pr","Praseodymium",140.90766,"D9FFC7","[Xe]6s2 4f3",1.13,239,5.464,"","+3","Solid",1204,3793,6.77,"Lanthanide",1885 +60,"Nd","Neodymium",144.24,"C7FFC7","[Xe]6s2 4f4",1.14,229,5.525,"","+3","Solid",1294,3347,7.01,"Lanthanide",1885 +61,"Pm","Promethium",144.91276,"A3FFC7","[Xe]6s2 4f5","",236,5.55,"","+3","Solid",1315,3273,7.26,"Lanthanide",1945 +62,"Sm","Samarium",150.4,"8FFFC7","[Xe]6s2 4f6",1.17,229,5.644,"","+3, +2","Solid",1347,2067,7.52,"Lanthanide",1879 +63,"Eu","Europium",151.964,"61FFC7","[Xe]6s2 4f7","",233,5.670,"","+3, +2","Solid",1095,1802,5.24,"Lanthanide",1901 +64,"Gd","Gadolinium",157.25,"45FFC7","[Xe]6s2 4f7 5d1",1.2,237,6.150,"","+3","Solid",1586,3546,7.90,"Lanthanide",1880 +65,"Tb","Terbium",158.92535,"30FFC7","[Xe]6s2 4f9","",221,5.864,"","+3","Solid",1629,3503,8.23,"Lanthanide",1843 +66,"Dy","Dysprosium",162.500,"1FFFC7","[Xe]6s2 4f10",1.22,229,5.939,"","+3","Solid",1685,2840,8.55,"Lanthanide",1886 +67,"Ho","Holmium",164.93033,"00FF9C","[Xe]6s2 4f11",1.23,216,6.022,"","+3","Solid",1747,2973,8.80,"Lanthanide",1878 +68,"Er","Erbium",167.26,"","[Xe]6s2 4f12",1.24,235,6.108,"","+3","Solid",1802,3141,9.07,"Lanthanide",1843 +69,"Tm","Thulium",168.93422,"00D452","[Xe]6s2 4f13",1.25,227,6.184,"","+3","Solid",1818,2223,9.32,"Lanthanide",1879 +70,"Yb","Ytterbium",173.05,"00BF38","[Xe]6s2 4f14","",242,6.254,"","+3, +2","Solid",1092,1469,6.90,"Lanthanide",1878 +71,"Lu","Lutetium",174.9667,"00AB24","[Xe]6s2 4f14 5d1",1.27,221,5.426,"","+3","Solid",1936,3675,9.84,"Lanthanide",1907 +72,"Hf","Hafnium",178.49,"4DC2FF","[Xe]6s2 4f14 5d2",1.3,212,6.825,"","+4","Solid",2506,4876,13.3,"Transition metal",1923 +73,"Ta","Tantalum",180.9479,"4DA6FF","[Xe]6s2 4f14 5d3",1.5,217,7.89,0.322,"+5","Solid",3290,5731,16.4,"Transition metal",1802 +74,"W","Tungsten",183.84,"2194D6","[Xe]6s2 4f14 5d4",2.36,210,7.98,0.815,"+6","Solid",3695,5828,19.3,"Transition metal",1783 +75,"Re","Rhenium",186.207,"267DAB","[Xe]6s2 4f14 5d5",1.9,217,7.88,0.15,"+7, +6, +4","Solid",3459,5869,20.8,"Transition metal",1925 +76,"Os","Osmium",190.2,"266696","[Xe]6s2 4f14 5d6",2.2,216,8.7,1.1,"+4, +3","Solid",3306,5285,22.57,"Transition metal",1803 +77,"Ir","Iridium",192.22,"175487","[Xe]6s2 4f14 5d7",2.2,202,9.1,1.565,"+4, +3","Solid",2719,4701,22.42,"Transition metal",1803 +78,"Pt","Platinum",195.08,"D0D0E0","[Xe]6s1 4f14 5d9",2.28,209,9,2.128,"+4, +2","Solid",2041.55,4098,21.46,"Transition metal",1735 +79,"Au","Gold",196.96657,"FFD123","[Xe]6s1 4f14 5d10",2.54,166,9.226,2.309,"+3, +1","Solid",1337.33,3129,19.282,"Transition metal","Ancient" +80,"Hg","Mercury",200.59,"B8B8D0","[Xe]6s2 4f14 5d10",2,209,10.438,"","+2, +1","Liquid",234.32,629.88,13.5336,"Transition metal","Ancient" +81,"Tl","Thallium",204.383,"A6544D","[Xe]6s2 4f14 5d10 6p1",1.62,196,6.108,0.2,"+3, +1","Solid",577,1746,11.8,"Post-transition metal",1861 +82,"Pb","Lead",207,"575961","[Xe]6s2 4f14 5d10 6p2",2.33,202,7.417,0.36,"+4, +2","Solid",600.61,2022,11.342,"Post-transition metal","Ancient" +83,"Bi","Bismuth",208.98040,"9E4FB5","[Xe]6s2 4f14 5d10 6p3",2.02,207,7.289,0.946,"+5, +3","Solid",544.55,1837,9.807,"Post-transition metal",1753 +84,"Po","Polonium",208.98243,"AB5C00","[Xe]6s2 4f14 5d10 6p4",2,197,8.417,1.9,"+4, +2","Solid",527,1235,9.32,"Metalloid",1898 +85,"At","Astatine",209.98715,"754F45","[Xe]6s2 4f14 5d10 6p5",2.2,202,9.5,2.8,"7, 5, 3, 1, -1","Solid",575,"",7,"Halogen",1940 +86,"Rn","Radon",222.01758,"428296","[Xe]6s2 4f14 5d10 6p6","",220,10.745,"","0","Gas",202,211.45,0.00973,"Noble gas",1900 +87,"Fr","Francium",223.01973,"420066","[Rn]7s1",0.7,348,3.9,0.47,"+1","Solid",300,"","","Alkali metal",1939 +88,"Ra","Radium",226.02541,"007D00","[Rn]7s2",0.9,283,5.279,"","+2","Solid",973,1413,5,"Alkaline earth metal",1898 +89,"Ac","Actinium",227.02775,"70ABFA","[Rn]7s2 6d1",1.1,260,5.17,"","+3","Solid",1324,3471,10.07,"Actinide",1899 +90,"Th","Thorium",232.038,"00BAFF","[Rn]7s2 6d2",1.3,237,6.08,"","+4","Solid",2023,5061,11.72,"Actinide",1828 +91,"Pa","Protactinium",231.03588,"00A1FF","[Rn]7s2 5f2 6d1",1.5,243,5.89,"","+5, +4","Solid",1845,"",15.37,"Actinide",1913 +92,"U","Uranium",238.0289,"008FFF","[Rn]7s2 5f3 6d1",1.38,240,6.194,"","+6, +5, +4, +3","Solid",1408,4404,18.95,"Actinide",1789 +93,"Np","Neptunium",237.048172,"0080FF","[Rn]7s2 5f4 6d1",1.36,221,6.266,"","+6, +5, +4, +3","Solid",917,4175,20.25,"Actinide",1940 +94,"Pu","Plutonium",244.06420,"006BFF","[Rn]7s2 5f6",1.28,243,6.06,"","+6, +5, +4, +3","Solid",913,3501,19.84,"Actinide",1940 +95,"Am","Americium",243.061380,"545CF2","[Rn]7s2 5f7",1.3,244,5.993,"","+6, +5, +4, +3","Solid",1449,2284,13.69,"Actinide",1944 +96,"Cm","Curium",247.07035,"785CE3","[Rn]7s2 5f7 6d1",1.3,245,6.02,"","+3","Solid",1618,3400,13.51,"Actinide",1944 +97,"Bk","Berkelium",247.07031,"8A4FE3","[Rn]7s2 5f9",1.3,244,6.23,"","+4, +3","Solid",1323,"",14,"Actinide",1949 +98,"Cf","Californium",251.07959,"A136D4","[Rn]7s2 5f10",1.3,245,6.30,"","+3","Solid",1173,"","","Actinide",1950 +99,"Es","Einsteinium",252.0830,"B31FD4","[Rn]7s2 5f11",1.3,245,6.42,"","+3","Solid",1133,"","","Actinide",1952 +100,"Fm","Fermium",257.09511,"B31FBA","[Rn] 5f12 7s2",1.3,"",6.50,"","+3","Solid",1800,"","","Actinide",1952 +101,"Md","Mendelevium",258.09843,"B30DA6","[Rn]7s2 5f13",1.3,"",6.58,"","+3, +2","Solid",1100,"","","Actinide",1955 +102,"No","Nobelium",259.10100,"BD0D87","[Rn]7s2 5f14",1.3,"",6.65,"","+3, +2","Solid",1100,"","","Actinide",1957 +103,"Lr","Lawrencium",266.120,"C70066","[Rn]7s2 5f14 6d1",1.3,"","","","+3","Solid",1900,"","","Actinide",1961 +104,"Rf","Rutherfordium",267.122,"CC0059","[Rn]7s2 5f14 6d2","","","","","+4","Solid","","","","Transition metal",1964 +105,"Db","Dubnium",268.126,"D1004F","[Rn]7s2 5f14 6d3","","","","","5, 4, 3","Solid","","","","Transition metal",1967 +106,"Sg","Seaborgium",269.128,"D90045","[Rn]7s2 5f14 6d4","","","","","6, 5, 4, 3, 0","Solid","","","","Transition metal",1974 +107,"Bh","Bohrium",270.133,"E00038","[Rn]7s2 5f14 6d5","","","","","7, 5, 4, 3","Solid","","","","Transition metal",1976 +108,"Hs","Hassium",269.1336,"E6002E","[Rn]7s2 5f14 6d6","","","","","8, 6, 5, 4, 3, 2","Solid","","","","Transition metal",1984 +109,"Mt","Meitnerium",277.154,"EB0026","[Rn]7s2 5f14 6d7 (calculated)","","","","","9, 8, 6, 4, 3, 1","Solid","","","","Transition metal",1982 +110,"Ds","Darmstadtium",282.166,"","[Rn]7s2 5f14 6d8 (predicted)","","","","","8, 6, 4, 2, 0","Expected to be a Solid","","","","Transition metal",1994 +111,"Rg","Roentgenium",282.169,"","[Rn]7s2 5f14 6d9 (predicted)","","","","","5, 3, 1, -1","Expected to be a Solid","","","","Transition metal",1994 +112,"Cn","Copernicium",286.179,"","[Rn]7s2 5f14 6d10 (predicted)","","","","","2, 1, 0","Expected to be a Solid","","","","Transition metal",1996 +113,"Nh","Nihonium",286.182,"","[Rn]5f14 6d10 7s2 7p1 (predicted)","","","","","","Expected to be a Solid","","","","Post-transition metal",2004 +114,"Fl","Flerovium",290.192,"","[Rn]7s2 7p2 5f14 6d10 (predicted)","","","","","6, 4,2, 1, 0","Expected to be a Solid","","","","Post-transition metal",1998 +115,"Mc","Moscovium",290.196,"","[Rn]7s2 7p3 5f14 6d10 (predicted)","","","","","3, 1","Expected to be a Solid","","","","Post-transition metal",2003 +116,"Lv","Livermorium",293.205,"","[Rn]7s2 7p4 5f14 6d10 (predicted)","","","","","+4, +2, -2","Expected to be a Solid","","","","Post-transition metal",2000 +117,"Ts","Tennessine",294.211,"","[Rn]7s2 7p5 5f14 6d10 (predicted)","","","","","+5, +3, +1, -1","Expected to be a Solid","","","","Halogen",2010 +118,"Og","Oganesson",295.216,"","[Rn]7s2 7p6 5f14 6d10 (predicted)","","","","","+6, +4, +2, +1, 0, -1","Expected to be a Gas","","","","Noble gas",2006 diff --git a/lessons/common_libs/periodic_table_out.csv b/lessons/common_libs/periodic_table_out.csv new file mode 100644 index 0000000..3565424 --- /dev/null +++ b/lessons/common_libs/periodic_table_out.csv @@ -0,0 +1,119 @@ +AtomicNumber,Symbol,Name,AtomicMass,CPKHexColor,ElectronConfiguration,Electronegativity,AtomicRadius,IonizationEnergy,ElectronAffinity,OxidationStates,StandardState,MeltingPoint,BoilingPoint,Density,GroupBlock,YearDiscovered +1,H,Hydrogen,1.008,FFFFFF,1s1,2.2,120.0,13.598,0.754,"+1, -1",Gas,13.81,20.28,8.988e-05,Nonmetal,1766 +2,He,Helium,4.0026,D9FFFF,1s2,,140.0,24.587,,0,Gas,0.95,4.22,0.0001785,Noble gas,1868 +3,Li,Lithium,7.0,CC80FF,[He]2s1,0.98,182.0,5.392,0.618,+1,Solid,453.65,1615.0,0.534,Alkali metal,1817 +4,Be,Beryllium,9.012183,C2FF00,[He]2s2,1.57,153.0,9.323,,+2,Solid,1560.0,2744.0,1.85,Alkaline earth metal,1798 +5,B,Boron,10.81,FFB5B5,[He]2s2 2p1,2.04,192.0,8.298,0.277,+3,Solid,2348.0,4273.0,2.37,Metalloid,1808 +6,C,Carbon,12.011,909090,[He]2s2 2p2,2.55,170.0,11.26,1.263,"+4, +2, -4",Solid,3823.0,4098.0,2.267,Nonmetal,Ancient +7,N,Nitrogen,14.007,3050F8,[He] 2s2 2p3,3.04,155.0,14.534,,"+5, +4, +3, +2, +1, -1, -2, -3",Gas,63.15,77.36,0.0012506,Nonmetal,1772 +8,O,Oxygen,15.999,FF0D0D,[He]2s2 2p4,3.44,152.0,13.618,1.461,-2,Gas,54.36,90.2,0.001429,Nonmetal,1774 +9,F,Fluorine,18.99840316,90E050,[He]2s2 2p5,3.98,135.0,17.423,3.339,-1,Gas,53.53,85.03,0.001696,Halogen,1670 +10,Ne,Neon,20.18,B3E3F5,[He]2s2 2p6,,154.0,21.565,,0,Gas,24.56,27.07,0.0008999,Noble gas,1898 +11,Na,Sodium,22.9897693,AB5CF2,[Ne]3s1,0.93,227.0,5.139,0.548,+1,Solid,370.95,1156.0,0.97,Alkali metal,1807 +12,Mg,Magnesium,24.305,8AFF00,[Ne]3s2,1.31,173.0,7.646,,+2,Solid,923.0,1363.0,1.74,Alkaline earth metal,1808 +13,Al,Aluminum,26.981538,BFA6A6,[Ne]3s2 3p1,1.61,184.0,5.986,0.441,+3,Solid,933.437,2792.0,2.7,Post-transition metal,Ancient +14,Si,Silicon,28.085,F0C8A0,[Ne]3s2 3p2,1.9,210.0,8.152,1.385,"+4, +2, -4",Solid,1687.0,3538.0,2.3296,Metalloid,1854 +15,P,Phosphorus,30.973762,FF8000,[Ne]3s2 3p3,2.19,180.0,10.487,0.746,"+5, +3, -3",Solid,317.3,553.65,1.82,Nonmetal,1669 +16,S,Sulfur,32.07,FFFF30,[Ne]3s2 3p4,2.58,180.0,10.36,2.077,"+6, +4, -2",Solid,388.36,717.75,2.067,Nonmetal,Ancient +17,Cl,Chlorine,35.45,1FF01F,[Ne]3s2 3p5,3.16,175.0,12.968,3.617,"+7, +5, +1, -1",Gas,171.65,239.11,0.003214,Halogen,1774 +18,Ar,Argon,39.9,80D1E3,[Ne]3s2 3p6,,188.0,15.76,,0,Gas,83.8,87.3,0.0017837,Noble gas,1894 +19,K,Potassium,39.0983,8F40D4,[Ar]4s1,0.82,275.0,4.341,0.501,+1,Solid,336.53,1032.0,0.89,Alkali metal,1807 +20,Ca,Calcium,40.08,3DFF00,[Ar]4s2,1.0,231.0,6.113,,+2,Solid,1115.0,1757.0,1.54,Alkaline earth metal,Ancient +21,Sc,Scandium,44.95591,E6E6E6,[Ar]4s2 3d1,1.36,211.0,6.561,0.188,+3,Solid,1814.0,3109.0,2.99,Transition metal,1879 +22,Ti,Titanium,47.867,BFC2C7,[Ar]4s2 3d2,1.54,187.0,6.828,0.079,"+4, +3, +2",Solid,1941.0,3560.0,4.5,Transition metal,1791 +23,V,Vanadium,50.9415,A6A6AB,[Ar]4s2 3d3,1.63,179.0,6.746,0.525,"+5, +4, +3, +2",Solid,2183.0,3680.0,6.0,Transition metal,1801 +24,Cr,Chromium,51.996,8A99C7,[Ar]3d5 4s1,1.66,189.0,6.767,0.666,"+6, +3, +2",Solid,2180.0,2944.0,7.15,Transition metal,1797 +25,Mn,Manganese,54.93804,9C7AC7,[Ar]4s2 3d5,1.55,197.0,7.434,,"+7, +4, +3, +2",Solid,1519.0,2334.0,7.3,Transition metal,1774 +26,Fe,Iron,55.84,E06633,[Ar]4s2 3d6,1.83,194.0,7.902,0.163,"+3, +2",Solid,1811.0,3134.0,7.874,Transition metal,Ancient +27,Co,Cobalt,58.93319,F090A0,[Ar]4s2 3d7,1.88,192.0,7.881,0.661,"+3, +2",Solid,1768.0,3200.0,8.86,Transition metal,1735 +28,Ni,Nickel,58.693,50D050,[Ar]4s2 3d8,1.91,163.0,7.64,1.156,"+3, +2",Solid,1728.0,3186.0,8.912,Transition metal,1751 +29,Cu,Copper,63.55,C88033,[Ar]4s1 3d10,1.9,140.0,7.726,1.228,"+2, +1",Solid,1357.77,2835.0,8.933,Transition metal,Ancient +30,Zn,Zinc,65.4,7D80B0,[Ar]4s2 3d10,1.65,139.0,9.394,,+2,Solid,692.68,1180.0,7.134,Transition metal,1746 +31,Ga,Gallium,69.723,C28F8F,[Ar]4s2 3d10 4p1,1.81,187.0,5.999,0.3,+3,Solid,302.91,2477.0,5.91,Post-transition metal,1875 +32,Ge,Germanium,72.63,668F8F,[Ar]4s2 3d10 4p2,2.01,211.0,7.9,1.35,"+4, +2",Solid,1211.4,3106.0,5.323,Metalloid,1886 +33,As,Arsenic,74.92159,BD80E3,[Ar]4s2 3d10 4p3,2.18,185.0,9.815,0.81,"+5, +3, -3",Solid,1090.0,887.0,5.776,Metalloid,Ancient +34,Se,Selenium,78.97,FFA100,[Ar]4s2 3d10 4p4,2.55,190.0,9.752,2.021,"+6, +4, -2",Solid,493.65,958.0,4.809,Nonmetal,1817 +35,Br,Bromine,79.9,A62929,[Ar]4s2 3d10 4p5,2.96,183.0,11.814,3.365,"+5, +1, -1",Liquid,265.95,331.95,3.11,Halogen,1826 +36,Kr,Krypton,83.8,5CB8D1,[Ar]4s2 3d10 4p6,3.0,202.0,14.0,,0,Gas,115.79,119.93,0.003733,Noble gas,1898 +37,Rb,Rubidium,85.468,702EB0,[Kr]5s1,0.82,303.0,4.177,0.468,+1,Solid,312.46,961.0,1.53,Alkali metal,1861 +38,Sr,Strontium,87.62,00FF00,[Kr]5s2,0.95,249.0,5.695,,+2,Solid,1050.0,1655.0,2.64,Alkaline earth metal,1790 +39,Y,Yttrium,88.90584,94FFFF,[Kr]5s2 4d1,1.22,219.0,6.217,0.307,+3,Solid,1795.0,3618.0,4.47,Transition metal,1794 +40,Zr,Zirconium,91.22,94E0E0,[Kr]5s2 4d2,1.33,186.0,6.634,0.426,+4,Solid,2128.0,4682.0,6.52,Transition metal,1789 +41,Nb,Niobium,92.90637,73C2C9,[Kr]5s1 4d4,1.6,207.0,6.759,0.893,"+5, +3",Solid,2750.0,5017.0,8.57,Transition metal,1801 +42,Mo,Molybdenum,95.95,54B5B5,[Kr]5s1 4d5,2.16,209.0,7.092,0.746,+6,Solid,2896.0,4912.0,10.2,Transition metal,1778 +43,Tc,Technetium,96.90636,3B9E9E,[Kr]5s2 4d5,1.9,209.0,7.28,0.55,"+7, +6, +4",Solid,2430.0,4538.0,11.0,Transition metal,1937 +44,Ru,Ruthenium,101.1,248F8F,[Kr]5s1 4d7,2.2,207.0,7.361,1.05,+3,Solid,2607.0,4423.0,12.1,Transition metal,1827 +45,Rh,Rhodium,102.9055,0A7D8C,[Kr]5s1 4d8,2.28,195.0,7.459,1.137,+3,Solid,2237.0,3968.0,12.4,Transition metal,1803 +46,Pd,Palladium,106.42,6985,[Kr]4d10,2.2,202.0,8.337,0.557,"+3, +2",Solid,1828.05,3236.0,12.0,Transition metal,1803 +47,Ag,Silver,107.868,C0C0C0,[Kr]5s1 4d10,1.93,172.0,7.576,1.302,+1,Solid,1234.93,2435.0,10.501,Transition metal,Ancient +48,Cd,Cadmium,112.41,FFD98F,[Kr]5s2 4d10,1.69,158.0,8.994,,+2,Solid,594.22,1040.0,8.69,Transition metal,1817 +49,In,Indium,114.818,A67573,[Kr]5s2 4d10 5p1,1.78,193.0,5.786,0.3,+3,Solid,429.75,2345.0,7.31,Post-transition metal,1863 +50,Sn,Tin,118.71,668080,[Kr]5s2 4d10 5p2,1.96,217.0,7.344,1.2,"+4, +2",Solid,505.08,2875.0,7.287,Post-transition metal,Ancient +51,Sb,Antimony,121.76,9E63B5,[Kr]5s2 4d10 5p3,2.05,206.0,8.64,1.07,"+5, +3, -3",Solid,903.78,1860.0,6.685,Metalloid,Ancient +52,Te,Tellurium,127.6,D47A00,[Kr]5s2 4d10 5p4,2.1,206.0,9.01,1.971,"+6, +4, -2",Solid,722.66,1261.0,6.232,Metalloid,1782 +53,I,Iodine,126.9045,940094,[Kr]5s2 4d10 5p5,2.66,198.0,10.451,3.059,"+7, +5, +1, -1",Solid,386.85,457.55,4.93,Halogen,1811 +54,Xe,Xenon,131.29,429EB0,[Kr]5s2 4d10 5p6,2.6,216.0,12.13,,0,Gas,161.36,165.03,0.005887,Noble gas,1898 +55,Cs,Cesium,132.905452,57178F,[Xe]6s1,0.79,343.0,3.894,0.472,+1,Solid,301.59,944.0,1.93,Alkali metal,1860 +56,Ba,Barium,137.33,00C900,[Xe]6s2,0.89,268.0,5.212,,+2,Solid,1000.0,2170.0,3.62,Alkaline earth metal,1808 +57,La,Lanthanum,138.9055,70D4FF,[Xe]6s2 5d1,1.1,240.0,5.577,0.5,+3,Solid,1191.0,3737.0,6.15,Lanthanide,1839 +58,Ce,Cerium,140.116,FFFFC7,[Xe]6s2 4f1 5d1,1.12,235.0,5.539,0.5,"+4, +3",Solid,1071.0,3697.0,6.77,Lanthanide,1803 +59,Pr,Praseodymium,140.90766,D9FFC7,[Xe]6s2 4f3,1.13,239.0,5.464,,+3,Solid,1204.0,3793.0,6.77,Lanthanide,1885 +60,Nd,Neodymium,144.24,C7FFC7,[Xe]6s2 4f4,1.14,229.0,5.525,,+3,Solid,1294.0,3347.0,7.01,Lanthanide,1885 +61,Pm,Promethium,144.91276,A3FFC7,[Xe]6s2 4f5,,236.0,5.55,,+3,Solid,1315.0,3273.0,7.26,Lanthanide,1945 +62,Sm,Samarium,150.4,8FFFC7,[Xe]6s2 4f6,1.17,229.0,5.644,,"+3, +2",Solid,1347.0,2067.0,7.52,Lanthanide,1879 +63,Eu,Europium,151.964,61FFC7,[Xe]6s2 4f7,,233.0,5.67,,"+3, +2",Solid,1095.0,1802.0,5.24,Lanthanide,1901 +64,Gd,Gadolinium,157.25,45FFC7,[Xe]6s2 4f7 5d1,1.2,237.0,6.15,,+3,Solid,1586.0,3546.0,7.9,Lanthanide,1880 +65,Tb,Terbium,158.92535,30FFC7,[Xe]6s2 4f9,,221.0,5.864,,+3,Solid,1629.0,3503.0,8.23,Lanthanide,1843 +66,Dy,Dysprosium,162.5,1FFFC7,[Xe]6s2 4f10,1.22,229.0,5.939,,+3,Solid,1685.0,2840.0,8.55,Lanthanide,1886 +67,Ho,Holmium,164.93033,00FF9C,[Xe]6s2 4f11,1.23,216.0,6.022,,+3,Solid,1747.0,2973.0,8.8,Lanthanide,1878 +68,Er,Erbium,167.26,,[Xe]6s2 4f12,1.24,235.0,6.108,,+3,Solid,1802.0,3141.0,9.07,Lanthanide,1843 +69,Tm,Thulium,168.93422,00D452,[Xe]6s2 4f13,1.25,227.0,6.184,,+3,Solid,1818.0,2223.0,9.32,Lanthanide,1879 +70,Yb,Ytterbium,173.05,00BF38,[Xe]6s2 4f14,,242.0,6.254,,"+3, +2",Solid,1092.0,1469.0,6.9,Lanthanide,1878 +71,Lu,Lutetium,174.9667,00AB24,[Xe]6s2 4f14 5d1,1.27,221.0,5.426,,+3,Solid,1936.0,3675.0,9.84,Lanthanide,1907 +72,Hf,Hafnium,178.49,4DC2FF,[Xe]6s2 4f14 5d2,1.3,212.0,6.825,,+4,Solid,2506.0,4876.0,13.3,Transition metal,1923 +73,Ta,Tantalum,180.9479,4DA6FF,[Xe]6s2 4f14 5d3,1.5,217.0,7.89,0.322,+5,Solid,3290.0,5731.0,16.4,Transition metal,1802 +74,W,Tungsten,183.84,2194D6,[Xe]6s2 4f14 5d4,2.36,210.0,7.98,0.815,+6,Solid,3695.0,5828.0,19.3,Transition metal,1783 +75,Re,Rhenium,186.207,267DAB,[Xe]6s2 4f14 5d5,1.9,217.0,7.88,0.15,"+7, +6, +4",Solid,3459.0,5869.0,20.8,Transition metal,1925 +76,Os,Osmium,190.2,266696,[Xe]6s2 4f14 5d6,2.2,216.0,8.7,1.1,"+4, +3",Solid,3306.0,5285.0,22.57,Transition metal,1803 +77,Ir,Iridium,192.22,175487,[Xe]6s2 4f14 5d7,2.2,202.0,9.1,1.565,"+4, +3",Solid,2719.0,4701.0,22.42,Transition metal,1803 +78,Pt,Platinum,195.08,D0D0E0,[Xe]6s1 4f14 5d9,2.28,209.0,9.0,2.128,"+4, +2",Solid,2041.55,4098.0,21.46,Transition metal,1735 +79,Au,Gold,196.96657,FFD123,[Xe]6s1 4f14 5d10,2.54,166.0,9.226,2.309,"+3, +1",Solid,1337.33,3129.0,19.282,Transition metal,Ancient +80,Hg,Mercury,200.59,B8B8D0,[Xe]6s2 4f14 5d10,2.0,209.0,10.438,,"+2, +1",Liquid,234.32,629.88,13.5336,Transition metal,Ancient +81,Tl,Thallium,204.383,A6544D,[Xe]6s2 4f14 5d10 6p1,1.62,196.0,6.108,0.2,"+3, +1",Solid,577.0,1746.0,11.8,Post-transition metal,1861 +82,Pb,Lead,207.0,575961,[Xe]6s2 4f14 5d10 6p2,2.33,202.0,7.417,0.36,"+4, +2",Solid,600.61,2022.0,11.342,Post-transition metal,Ancient +83,Bi,Bismuth,208.9804,9E4FB5,[Xe]6s2 4f14 5d10 6p3,2.02,207.0,7.289,0.946,"+5, +3",Solid,544.55,1837.0,9.807,Post-transition metal,1753 +84,Po,Polonium,208.98243,AB5C00,[Xe]6s2 4f14 5d10 6p4,2.0,197.0,8.417,1.9,"+4, +2",Solid,527.0,1235.0,9.32,Metalloid,1898 +85,At,Astatine,209.98715,754F45,[Xe]6s2 4f14 5d10 6p5,2.2,202.0,9.5,2.8,"7, 5, 3, 1, -1",Solid,575.0,,7.0,Halogen,1940 +86,Rn,Radon,222.01758,428296,[Xe]6s2 4f14 5d10 6p6,,220.0,10.745,,0,Gas,202.0,211.45,0.00973,Noble gas,1900 +87,Fr,Francium,223.01973,420066,[Rn]7s1,0.7,348.0,3.9,0.47,+1,Solid,300.0,,,Alkali metal,1939 +88,Ra,Radium,226.02541,007D00,[Rn]7s2,0.9,283.0,5.279,,+2,Solid,973.0,1413.0,5.0,Alkaline earth metal,1898 +89,Ac,Actinium,227.02775,70ABFA,[Rn]7s2 6d1,1.1,260.0,5.17,,+3,Solid,1324.0,3471.0,10.07,Actinide,1899 +90,Th,Thorium,232.038,00BAFF,[Rn]7s2 6d2,1.3,237.0,6.08,,+4,Solid,2023.0,5061.0,11.72,Actinide,1828 +91,Pa,Protactinium,231.03588,00A1FF,[Rn]7s2 5f2 6d1,1.5,243.0,5.89,,"+5, +4",Solid,1845.0,,15.37,Actinide,1913 +92,U,Uranium,238.0289,008FFF,[Rn]7s2 5f3 6d1,1.38,240.0,6.194,,"+6, +5, +4, +3",Solid,1408.0,4404.0,18.95,Actinide,1789 +93,Np,Neptunium,237.048172,0080FF,[Rn]7s2 5f4 6d1,1.36,221.0,6.266,,"+6, +5, +4, +3",Solid,917.0,4175.0,20.25,Actinide,1940 +94,Pu,Plutonium,244.0642,006BFF,[Rn]7s2 5f6,1.28,243.0,6.06,,"+6, +5, +4, +3",Solid,913.0,3501.0,19.84,Actinide,1940 +95,Am,Americium,243.06138,545CF2,[Rn]7s2 5f7,1.3,244.0,5.993,,"+6, +5, +4, +3",Solid,1449.0,2284.0,13.69,Actinide,1944 +96,Cm,Curium,247.07035,785CE3,[Rn]7s2 5f7 6d1,1.3,245.0,6.02,,+3,Solid,1618.0,3400.0,13.51,Actinide,1944 +97,Bk,Berkelium,247.07031,8A4FE3,[Rn]7s2 5f9,1.3,244.0,6.23,,"+4, +3",Solid,1323.0,,14.0,Actinide,1949 +98,Cf,Californium,251.07959,A136D4,[Rn]7s2 5f10,1.3,245.0,6.3,,+3,Solid,1173.0,,,Actinide,1950 +99,Es,Einsteinium,252.083,B31FD4,[Rn]7s2 5f11,1.3,245.0,6.42,,+3,Solid,1133.0,,,Actinide,1952 +100,Fm,Fermium,257.09511,B31FBA,[Rn] 5f12 7s2,1.3,,6.5,,+3,Solid,1800.0,,,Actinide,1952 +101,Md,Mendelevium,258.09843,B30DA6,[Rn]7s2 5f13,1.3,,6.58,,"+3, +2",Solid,1100.0,,,Actinide,1955 +102,No,Nobelium,259.101,BD0D87,[Rn]7s2 5f14,1.3,,6.65,,"+3, +2",Solid,1100.0,,,Actinide,1957 +103,Lr,Lawrencium,266.12,C70066,[Rn]7s2 5f14 6d1,1.3,,,,+3,Solid,1900.0,,,Actinide,1961 +104,Rf,Rutherfordium,267.122,CC0059,[Rn]7s2 5f14 6d2,,,,,+4,Solid,,,,Transition metal,1964 +105,Db,Dubnium,268.126,D1004F,[Rn]7s2 5f14 6d3,,,,,"5, 4, 3",Solid,,,,Transition metal,1967 +106,Sg,Seaborgium,269.128,D90045,[Rn]7s2 5f14 6d4,,,,,"6, 5, 4, 3, 0",Solid,,,,Transition metal,1974 +107,Bh,Bohrium,270.133,E00038,[Rn]7s2 5f14 6d5,,,,,"7, 5, 4, 3",Solid,,,,Transition metal,1976 +108,Hs,Hassium,269.1336,E6002E,[Rn]7s2 5f14 6d6,,,,,"8, 6, 5, 4, 3, 2",Solid,,,,Transition metal,1984 +109,Mt,Meitnerium,277.154,EB0026,[Rn]7s2 5f14 6d7 (calculated),,,,,"9, 8, 6, 4, 3, 1",Solid,,,,Transition metal,1982 +110,Ds,Darmstadtium,282.166,,[Rn]7s2 5f14 6d8 (predicted),,,,,"8, 6, 4, 2, 0",Expected to be a Solid,,,,Transition metal,1994 +111,Rg,Roentgenium,282.169,,[Rn]7s2 5f14 6d9 (predicted),,,,,"5, 3, 1, -1",Expected to be a Solid,,,,Transition metal,1994 +112,Cn,Copernicium,286.179,,[Rn]7s2 5f14 6d10 (predicted),,,,,"2, 1, 0",Expected to be a Solid,,,,Transition metal,1996 +113,Nh,Nihonium,286.182,,[Rn]5f14 6d10 7s2 7p1 (predicted),,,,,,Expected to be a Solid,,,,Post-transition metal,2004 +114,Fl,Flerovium,290.192,,[Rn]7s2 7p2 5f14 6d10 (predicted),,,,,"6, 4,2, 1, 0",Expected to be a Solid,,,,Post-transition metal,1998 +115,Mc,Moscovium,290.196,,[Rn]7s2 7p3 5f14 6d10 (predicted),,,,,"3, 1",Expected to be a Solid,,,,Post-transition metal,2003 +116,Lv,Livermorium,293.205,,[Rn]7s2 7p4 5f14 6d10 (predicted),,,,,"+4, +2, -2",Expected to be a Solid,,,,Post-transition metal,2000 +117,Ts,Tennessine,294.211,,[Rn]7s2 7p5 5f14 6d10 (predicted),,,,,"+5, +3, +1, -1",Expected to be a Solid,,,,Halogen,2010 +118,Og,Oganesson,295.216,,[Rn]7s2 7p6 5f14 6d10 (predicted),,,,,"+6, +4, +2, +1, 0, -1",Expected to be a Gas,,,,Noble gas,2006 diff --git a/lessons/common_libs/python-in-chem_pyplot_basics_SM.ipynb b/lessons/common_libs/python-in-chem_pyplot_basics_SM.ipynb new file mode 100644 index 0000000..84c169b --- /dev/null +++ b/lessons/common_libs/python-in-chem_pyplot_basics_SM.ipynb @@ -0,0 +1,466 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "8ea296df-22a6-4136-a2fc-901fb1c81f68", + "metadata": { + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "# Matplotlib Pyplot Basics\n", + "\n", + "
\n", + "\n", + "## Pre-requesites\n", + "\n", + "- Variables\n", + "- Lists\n", + "- ...\n", + "- ...\n", + "- ...\n", + "- ...\n", + "\n", + "
\n", + "\n", + "## Learning Outcomes\n", + "\n", + "- Plot scatter and line plots of lists of data\n", + "- Include axis labels\n", + "- Modify some of the appearances of the plots \n", + "\n", + "One of the important applications of Python is to create high quality visualisations such as graphs. There are multiple libraries that can be used for producing plots, but one of the most widely used in chemistry is `matplotlib`.\n", + "\n", + "\n", + "The library `matplotlib` has multiple modules. The module of interest here is `pyplot` and its primary function is generating data plots. This module has a widely used alias, `plt`, and can be imported using the following line of code.\n", + "\n", + "`import matplotlib.pyplot as plt`\n", + "\n", + "### Line plots\n", + "\n", + "One of the most important commands within the `pyplot` module is `plt.plot(x,y)`. This command instructs Python to produce a line plot of data contained in the list with variable name `x` on the horizontal axis and the data contained in the list with variable name `y` on the vertical axis." + ] + }, + { + "cell_type": "markdown", + "id": "b22a7fac-c022-4a7f-93d1-9995bb2b488e", + "metadata": { + "slideshow": { + "slide_type": "" + }, + "tags": [ + "instructions" + ] + }, + "source": [ + "### Activity 1 Plotting a line graph\n", + "\n", + "\n", + "The code below implements `pyplot` to plot a line graph of the following atomic radii data.\n", + "\n", + "**Table 1** Atomic radii of second row p-block elements\n", + "\n", + "|Element |\tGroup\t| Atomic radii / pm |\n", + "|---|---|---|\n", + "|$\\text{B}$|\t13\t|$88$|\n", + "|$\\text{C}$|\t14\t|$77$|\n", + "|$\\text{N}$|\t15\t|$74$|\n", + "|$\\text{O}$|\t16\t|$73$|\n", + "|$\\text{F}$|\t17\t|$71$|\n", + "|$\\text{Ne}$|\t18\t|$71$|\n", + "\n", + "(a)\tEnter the data contained in the list for the `radii` variable.\n", + "\n", + "(b)\tChange the strings contained in the `plt.xlabel(\"horizontal axis title\")` and `plt.ylabel(\"vertical axis title\")` to reflect the data that is being plotted\n", + "\n", + "Possible (c) ..... discuss the trend?????\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "33eee2a9-87e2-4392-b5ac-17b797f550d9", + "metadata": { + "slideshow": { + "slide_type": "" + }, + "tags": [ + "student" + ] + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "import matplotlib.pyplot as plt\n", + "\n", + "group = [13,14,15,16,17,18]\n", + "#radii = []\n", + "radii = [88,77,74,73,71,71]\n", + "\n", + "plt.plot(group,radii)\n", + "plt.xlabel(\"horizontal axis title\")\n", + "plt.ylabel(\"vertical axis title\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "cfd6e7b2", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "#Possible answer to Activity 1\n", + "\n", + "import matplotlib.pyplot as plt\n", + "\n", + "group = [13,14,15,16,17,18]\n", + "radii = [88,77,74,73,71,71]\n", + "\n", + "plt.plot(group,radii)\n", + "plt.xlabel(\"Group\")\n", + "plt.ylabel(\"Atomic radii / pm\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "217704b2-aeb8-4db0-9a1d-f3e81947b2de", + "metadata": { + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "The commands `plt.xlabel(\" \")` and `plt.ylabel(\" \")` are used to include labels for the horizontal and vertical axes, respectively.\n", + "\n", + "The axis labels are strings inside the brackets, between speech marks in the same way strings are used in the `print()` function.\n", + "\n", + "The command `plt.show()` instructs pyplot to display the graph. \n", + "(SM: this seems overly simplistic but i'm not completely sure the difference between interactive and non-interactive mode. \n", + "\n", + "
\n", + "\n", + "### Scatter plots\n", + "\n", + "Another option instead if a line plot is to use a scatter plot. For this option in `pyplot` use the command:\n", + "`plt.scatter(x,y)`\n", + "where `x` is the variable name of the list to be plotted on the x-axis, and `y` the variable name of the list to be plotted on the y-axis.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "a641c831-ce97-4bd8-9c8b-1169eb369b71", + "metadata": { + "slideshow": { + "slide_type": "" + }, + "tags": [ + "instructions" + ] + }, + "source": [ + "### Activity 2 Plotting a scatter graph\n", + "\n", + "\n", + "Table 2 contains the atomic radii of the third row p-block elements. hydrides. In the cell below complete the code to generate a sactter plot of this data, with group on the horizontal axis and atomic radii on the vertical axis.\n", + "\n", + "(*Hint:* it is not necessary to write the code from scratch. It is perfectly acceptable to copy the code from activity 1 and modify it to include the desired data.)\n", + "\n", + "
\n", + "\n", + "**Table 2** Atomic radii of third row p-block elements\n", + "\n", + "|Element |\tGroup\t| Atomic radii / pm |\n", + "|---|---|---|\n", + "|$\\text{Al}$|\t13\t|$125$|\n", + "|$\\text{Si}$|\t14\t|$118$|\n", + "|$\\text{P}$|\t15\t|$110$|\n", + "|$\\text{S}$|\t16\t|$104$|\n", + "|$\\text{Cl}$|\t17\t|$99$|\n", + "|$\\text{Ar}$|\t18\t|$98$|\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "89b96bae-bc5a-43f3-a966-9385d2ee8fbc", + "metadata": { + "slideshow": { + "slide_type": "" + }, + "tags": [ + "student" + ] + }, + "outputs": [], + "source": [ + "\n", + "import matplotlib.pyplot as plt\n", + "\n", + "group = \n", + "radii = \n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "abe65330", + "metadata": { + "slideshow": { + "slide_type": "" + }, + "tags": [ + "solution" + ] + }, + "outputs": [], + "source": [ + "#Possible answer to Activity 2\n", + "\n", + "import matplotlib.pyplot as plt\n", + "\n", + "group = [13,14,15,16,17,18]\n", + "radii = [125,118,110,104,99,98]\n", + "\n", + "plt.scatter(group,radii)\n", + "plt.xlabel(\"Group\")\n", + "plt.ylabel(\"Atomic radii / pm\")\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "id": "a55c01ba-3804-4026-b278-faf4fdad8b78", + "metadata": {}, + "source": [ + "### Plotting multiple datasets\n", + "\n", + "To plot multiple sets of data on the same graph you include more than one of the\n", + "`plt.plot()` and/or the `plt.scatter()` commands.\n", + "\n", + "As multiple sets of data are to be plotted a legend should be included to indicate what each series represents. In the same `plt.plot()`/`plt.scatter()` code, after specifying the data to be plotted on the horizontal and vertical axes within the brackets, a comma should be added and then the option `label=(\"\")` used. A string can then be included between the speech marks to label the series. For example, to plot a scatter graph of the lists `x` and `y` with the series name `Series A` you would use the following command:\n", + "`plt.scatter(x,y, label=\"Series A\")`\n", + "\n", + "By default, the legend option is not turned on in `matplotlib`. To show the legends you need to include the line `plt.legend()`.\n" + ] + }, + { + "cell_type": "markdown", + "id": "221e04f1", + "metadata": {}, + "source": [ + "### Activity 3 Plotting multiple datasets and including legends\n", + "\n", + "Complete the code in the cell below to generate a plot that contains the atomic radii of both the second and third row elements of the p-block. Remember to include a legend." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "67345c3a", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "group = []\n", + "radii_2nd_period = []\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b45182f", + "metadata": {}, + "outputs": [], + "source": [ + "#Possible answer to Activity 3\n", + "\n", + "import matplotlib.pyplot as plt\n", + "\n", + "group = [13,14,15,16,17,18]\n", + "radii_2nd_period = [88,77,74,73,71,71]\n", + "radii_3rd_period = [125,118,110,104,99,98]\n", + "\n", + "plt.scatter(group,radii_2nd_period, label=\"2nd Period\")\n", + "plt.scatter(group,radii_3rd_period, label=\"3rd Period\")\n", + "plt.xlabel(\"Group\")\n", + "plt.ylabel(\"Atomic radii / pm\")\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "abef10e9", + "metadata": {}, + "source": [ + "## Further customisation options\n", + "\n", + "### Changing the colour on graphs\n", + "\n", + "There are many options within `matplotlib` to modify the appearance of a graph. For example, you may want to change the colour of lines or data points in your graph. This may not seem like an important aspect of coding, but this can be useful if you are creating multiple charts for reports or presentations, and you want consistency between them. \n", + "\n", + "`matplotlib` chooses default colours for plotting multiple datasets: the first `plt.plot()`/`plt.scatter()` routine will use the colour blue, the second will use orange, and so on.\n", + "\n", + "Changing the colour of a line or scatter plot in Python requires a small addition to the `plt.plot()` or `plt.scatter()` routines. This command is `color=\"\"`, where this is preceeded by a comma (similar to the syntax of `label=\"\"` command in the same routines). \n", + "\n", + "Note that the syntax in `matplotlib` uses the American spelling for ‘color’, instead of the British spelling.\n", + "\n", + "For example, if you wanted to change the colour of the scatter plots from blue to red in the completed code from activity 3 the entire line would appear\n", + "\n", + " plt.scatter(group,radii_2nd_period, label=\"2nd Period\", color=\"red\")\n", + "\n", + "This will however change the next plotted series to the default blue, so to fully customise you would need to state the colours for each series.\n", + "\n", + "Most of the common colours you could name are included in `matplotlib`. For a full list of the available colours you can check the [Matplotlib documentation]." + ] + }, + { + "cell_type": "markdown", + "id": "d4c09ef7", + "metadata": {}, + "source": [ + "### Gridlines\n", + "\n", + "There are instances where you may want to include gridlines on your plots. To include major grdilines you would use the command:\n", + "\n", + " plt.grid()\n", + "\n", + "If you wanted to include major gridlines and minor gridlines you would use the two following commands:\n", + "\n", + " plt.grid(which='both')\n", + " plt.minorticks_on()\n", + "\n", + "Where the second command turns on the minor ticks on both axis, and the 'both' in the plt.grid() command indicates both the minor and major gridlines. Further options can be found in the Matplotlib documentation (https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.grid.html)" + ] + }, + { + "cell_type": "markdown", + "id": "630154f7", + "metadata": {}, + "source": [ + "### Exporting plots as image files\n", + "\n", + "Once you have successfully created graphs with Python, you need to be able to save them for later use or to include them in other resources.\n", + "\n", + "`matplotlib` has a command for this:\n", + "\n", + " plt.savefig(\"file_name.png\")\n", + "\n", + "Here, `\"file_name.png\"` is the name you choose for the saved graph. It will be saved in a `.png` format.\n", + "\n", + "It is also possible to save a graph as a PDF file by changing the `.png` extension in the previous routine to `.pdf`.\n", + "\n", + "Note the `plt.savefig()` command must go *before* the `plt.show()` command. If you do not do this, then the saved image file will be blank. \n", + "\n", + "\n", + "\n", + "$$$$ SM - This is how it works in jupyterlab, not sure how it will work elsewhere $$$$" + ] + }, + { + "cell_type": "markdown", + "id": "d6857f12", + "metadata": {}, + "source": [ + "### Superscripts and subscripts on plots\n", + "\n", + "When displaying strings on plots generated using `matplotlib`, such as axis labels and legends, you may noticed that you have not been able to add formatting, this is because strings are displayed in plain text. This missing formatting is important when labelling scientific data, particularly for units or chemical formulas.\n", + "\n", + "As an example, consider the line of code to label the y axis with the concentration of some reaction species, [A], with the incorrect formatting for the units of concentration. \n", + "\n", + " plt.ylabel(\"[A]/mol dm-3\")\n", + " \n", + "To correctly display the ‘$-3$’ in superscript you can use the `pyplot` command:\n", + "\n", + " plt.ylabel(\"[A]/mol dm$^{-3}$\")\n", + " \n", + "In this command:\n", + "\n", + "* the first and second dollar signs, `$`, indicate the start and end of and the text you want to be formatted (the dollar signs will not be printed in the string)\n", + "* the curly braces, `{}`, contain the text you want to apply formatting to\n", + "* the caret, `^`, goes before the curly braces and is used to indicate the text within the braces should be a superscript.\n", + "\n", + "\n", + "Another common formatting option you will need is subscript. This is especially important when it comes to chemical formulas. Subscripts use a similar syntax to superscripts, but use an underscore `_` instead of the caret `^`.\n", + "\n", + "So if in the above example A was nitrogen dioxide you would use the following command:\n", + " \n", + " plt.ylabel(\"[NO$_{2}$]/mol dm$^{-3}$\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "0f09f12d", + "metadata": {}, + "source": [ + "## Todo\n", + "\n", + "Add more activities related to the options above" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c96f413a", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/lessons/files.md b/lessons/files.md new file mode 100644 index 0000000..78632af --- /dev/null +++ b/lessons/files.md @@ -0,0 +1,3 @@ +# Using Files + +This section will teach you how to read and write files using Python. diff --git a/lessons/files/elements.csv b/lessons/files/elements.csv new file mode 100644 index 0000000..7eafedb --- /dev/null +++ b/lessons/files/elements.csv @@ -0,0 +1,4 @@ +Name,Symbol,Number +Hydrogen,H,1 +Helium,He,2 +Lithium,Li,3 diff --git a/lessons/files/gas_const.txt b/lessons/files/gas_const.txt new file mode 100644 index 0000000..7afce3e --- /dev/null +++ b/lessons/files/gas_const.txt @@ -0,0 +1 @@ +The gas constant is: 8.314 J/K.mol \ No newline at end of file diff --git a/lessons/files/molecule.txt b/lessons/files/molecule.txt new file mode 100644 index 0000000..0e18691 --- /dev/null +++ b/lessons/files/molecule.txt @@ -0,0 +1 @@ +C2H6 diff --git a/lessons/files/reading_files.ipynb b/lessons/files/reading_files.ipynb new file mode 100644 index 0000000..7da41c0 --- /dev/null +++ b/lessons/files/reading_files.ipynb @@ -0,0 +1,291 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "1767a58b", + "metadata": {}, + "source": [ + "# **Reading Files**\n", + "\n", + "## Prerequisites:\n", + "- Variables\n", + "- Iterables(?)\n", + "- Loops\n", + "\n", + "## Learning Outcomes:\n", + "- Open files using Python's built-in functions and extract their contents to variables\n", + "- Use the CSV module to read data from CSV files" + ] + }, + { + "cell_type": "markdown", + "id": "f4882898", + "metadata": {}, + "source": [ + "## Reading Files\n", + "\n", + "One of the common uses of Python in chemistry is to analyse large amounts of data. \n", + "This might be data gathered during an experiment that has been stored in a number of files, and Python has a number of built-in functions to read (and write) files. \n", + "In this section, we will explore how to read different types of files, including text files and CSV files, using Python's built-in capabilities.\n", + "\n", + "Let's start with a opening a simple text file and reading its contents:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ff6944a", + "metadata": {}, + "outputs": [], + "source": [ + "file = open('molecule.txt', 'r')\n", + "contents = file.read()\n", + "file.close()\n", + "print(contents)" + ] + }, + { + "cell_type": "markdown", + "id": "6d821f38", + "metadata": {}, + "source": [ + "After running the cell above, you should see the contents of the `molecule.txt` file in the cell output. \n", + "If you don't see the output, make sure that the file is in the same directory as this notebook. \n", + "You can also verify the output by checking the file's contents in a text editor.\n", + "\n", + "The first line of the code cell above opens the file `molecule.txt` using the `open()` function and saves it to a special file-reading Python *object* we have called `file`.\n", + "The `open()` function takes at least one argument which is either the file name (if in the same working directory) or the full filepath of the file.\n", + "It can also take a second argument to specify the mode in which the file is opened (e.g., `'r'` for reading, `'w'` for writing, etc.).\n", + "If you don't specify a mode, the file is opened in read mode by default.\n", + "\n", + "The second line of the code cell reads the entire contents of the file using the `read()` method of the file object and stores it in a variable called `contents`. \n", + "\n", + "The third line closes the file using the `close()` method and is considered good practice.\n", + "Otherwise we might leave it open, which can lead to various issues (e.g., file access errors).\n", + "\n", + "Finally, the last line prints the contents of the `contents` variable." + ] + }, + { + "cell_type": "markdown", + "id": "900f642e", + "metadata": {}, + "source": [ + "### Reading Files with `with`\n", + "We can also use the `with` statement to open files, which will automatically close the file for us when we are done with it.\n", + "This is a more \"Pythonic\" way to handle files and is generally recommended.\n", + "\n", + "Let's take a look at the same example using the `with` statement:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f63f3d19", + "metadata": {}, + "outputs": [], + "source": [ + "with open('molecule.txt', 'r') as file:\n", + " contents = file.read()\n", + "\n", + "print(contents)" + ] + }, + { + "cell_type": "markdown", + "id": "06bbb57c", + "metadata": {}, + "source": [ + "As before, we open the `molecule.txt` file and read its contents.\n", + "The difference is that we use the `with` statement to open the file, which automatically closes it when we are done with it (i.e., when we exit the `with` block).\n", + "\n", + "We now have a way to read files in Python, and use their contents as *variables* in our code." + ] + }, + { + "cell_type": "markdown", + "id": "8ec1d24a", + "metadata": {}, + "source": [ + "## Reading CSV Files\n", + "CSV (Comma Separated Values) files are a common format for storing tabular data, such as data from experiments or simulations.\n", + "Each line in a CSV file represents a row of data, and each value in the row is separated by a comma (you can easily verify this by opening up a CSV file in a text editor).\n", + "Python has a built-in module called `csv` that makes it easy to read (and write) CSV files.\n", + "\n", + "Let's take a look at how to read a CSV file using the `csv` module:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3ca51d4d", + "metadata": {}, + "outputs": [], + "source": [ + "import csv\n", + "\n", + "with open('elements.csv') as file:\n", + " csv_reader = csv.reader(file)\n", + " for row in csv_reader:\n", + " print(row)" + ] + }, + { + "cell_type": "markdown", + "id": "7ae13696", + "metadata": {}, + "source": [ + "Here, we first import the built-in `csv` module to allow us to easily parse CSV files.\n", + "\n", + "Next we open the `elements.csv` file using the `with` statement as we have seen before.\n", + "Note that we are opening the file in read mode without needing to specify it explicitly.\n", + "\n", + "The `csv.reader()` function takes the file object as an argument and returns a CSV reader object that can be used to *iterate* over the rows in the CSV file.\n", + "\n", + "Finally, we use a `for` loop to iterate over the rows in the CSV file and print the contents of each row.\n", + "The csv_reader object allows us to access each row as a list of values, making it easy to work with the data." + ] + }, + { + "cell_type": "markdown", + "id": "760dcb9a", + "metadata": {}, + "source": [ + "## Exercises\n", + "\n", + "### Manipulate data\n", + "Use f-strings to print the contents of the `elements.csv` file in a more readable format.\n", + "Don't forget about the header row!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53a6fb7d", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "633a2836", + "metadata": {}, + "source": [ + "Example answer (skipping the header entirely):\n", + "```python\n", + "import csv\n", + "\n", + "with open('elements.csv') as csvfile:\n", + " csv_reader = csv.reader(csvfile)\n", + " next(csv_reader) # Skip the header row\n", + " for row in csv_reader:\n", + " print(f\"Name: {row[0]}, Symbol: {row[1]}, Atomic Number: {row[2]}\")\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "c67c1875", + "metadata": {}, + "source": [ + "### Using the file path\n", + "Try to open a file that is not in the same directory as this notebook and print its contents." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "de2abab4", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "3430cc73", + "metadata": {}, + "source": [ + "TODO: Example answer" + ] + }, + { + "cell_type": "markdown", + "id": "10c5379d", + "metadata": {}, + "source": [ + "### Loop through multiple files\n", + "TODO: Task involving looping through multiple files with a predictable filename (e.g. `001.csv`) and reading their contents." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "002dbb28", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "c1114d99", + "metadata": {}, + "source": [ + "TODO: Example answer" + ] + }, + { + "cell_type": "markdown", + "id": "619f5799", + "metadata": {}, + "source": [ + "## Debugging\n", + "The code below contains a bug and will not run.\n", + "See if you can fix it by reading the error message and using the information it provides." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "818250af", + "metadata": {}, + "outputs": [], + "source": [ + "with open('molecule.csv', 'r') as file:\n", + " text = file.read()\n", + "\n", + "print(text)" + ] + }, + { + "cell_type": "markdown", + "id": "f58d91db", + "metadata": {}, + "source": [ + "## TODO\n", + "- Discuss carriage returns and other special characters?\n", + "- Explain the distinction between text and binary files?" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/lessons/files/spectrum.dat b/lessons/files/spectrum.dat new file mode 100644 index 0000000..e0c2c25 --- /dev/null +++ b/lessons/files/spectrum.dat @@ -0,0 +1,9 @@ +nm abs +240 0.123 +250 0.132 +260 0.346 +270 0.563 +280 0.998 +290 0.377 +300 0.007 +310 0.002 diff --git a/lessons/files/writing_files.ipynb b/lessons/files/writing_files.ipynb new file mode 100644 index 0000000..1ce922f --- /dev/null +++ b/lessons/files/writing_files.ipynb @@ -0,0 +1,257 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "R-GtgLtZw1hH" + }, + "source": [ + "# **Writing files**" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yjL3LTCFJXwl" + }, + "source": [ + "## **Learning Outcomes**\n", + "\n", + "The learning outcomes are as follows:\n", + "\n", + "1. Saving data into a newly created file\n", + "2. Add additional data into an existing file." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hTDYb2QRyNeb" + }, + "source": [ + "## **Pre-requisites**\n", + "\n", + "Variables
\n", + "FOR loops
\n", + "Writing f-strings
\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xUUYv_pr1Sbt" + }, + "source": [ + "## **Writing files**\n", + "\n", + "It is often necesary to be able to save chemical data, images etc. that have been generated as a result of data processing etc., which is known as 'writing'. You can choose either to write your data to:\n", + "(i) a new file, or\n", + "(ii) alternatively add (aka append) to an existing file.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BVX99iEZ3Rc2" + }, + "source": [ + "## **Writing data to a new file**\n", + "\n", + "In Python, in order to write data to a new file, you must first create a file, ensuring the the file is writable.\n", + "\n", + "In order to create a file, you can use the command 'open'. Following this (in ( ) brackets) you need to supply the name of the file that you want to create, followed by a comma and then indicate that you wish to *write* to the new file (as opposed to e.g. read) by using the tag 'w'.\n", + "\n", + "A simple example of this is given below:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JRvmRpz13Q0o" + }, + "outputs": [], + "source": [ + "file = open('gas_const.txt', 'w')\n", + "\n", + "R = 8.314\n", + "file.write(\"The gas constant is: \" + str(R) + \" J/K.mol\")\n", + "\n", + "file.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "KI8esPi893AW" + }, + "source": [ + "We have defined and assigned a value to the variable, R, that is to be written to the file. R will be written to the file as a string. We have constructed the string \"The gas constant is: 8.314 J/K.mol\" which is then written to the file using the file.write command. Lastly the file is closed.\n", + "\n", + "Google Colab: This simple file has been saved in a temporary storage location. You can have a look at the file that's just been written by selecting the File icon on the left-hand side of the Colab page. Within the 'Content' file, you should be able to see the file. Click on the three vertical dots on the right-hand side of the file, download and open.\n", + "**NOTICE FOR EDITORS: we appreciate that we've written this for Google Colab - so we will need to re-write this section**" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JQCkCjKt9UI7" + }, + "source": [ + "The way in which data is written to a file depends on the type of data itself. So... FINISH" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "uYsrtUqF_k_s" + }, + "source": [ + "## **Writing a simple structured file**\n", + "\n", + "XXXX\n", + "\n", + "In the example below, the ... FINISH" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "VPqkYrd1zla5" + }, + "outputs": [], + "source": [ + "file = open('spectrum.dat', 'w')\n", + "\n", + "wavelength = [240, 250, 260, 270, 280, 290]\n", + "absorbance = [0.123, 0.132, 0.346, 0.563, 0.998, 0.377, 0.021]\n", + "file.write(f\"nm \\t abs \\n\")\n", + "for i in range(len(wavelength)):\n", + " file.write(f\"{wavelength[i]} \\t {absorbance[i]}\\n\")\n", + "\n", + "file.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "YBO7aNknGp7b" + }, + "source": [ + "In the above example, the 'f' in the file.write commands... FINISH" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "RscVg7DyHKVW" + }, + "source": [ + "## **Appending to an existing file**\n", + "\n", + "You can also write data to an existsing file. In the example below, we will append some more data to the spectrum data created above.\n", + "\n", + "... FINISH" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "xpAqJWu2_ss2" + }, + "outputs": [], + "source": [ + "file = open('spectrum.dat', 'a')\n", + "\n", + "wavelength = [300, 310]\n", + "absorbance = [0.007, 0.002]\n", + "\n", + "for i in range(len(wavelength)):\n", + " file.write(f\"{wavelength[i]} \\t {absorbance[i]}\\n\")\n", + "\n", + "file.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Kp8OJXO1_oMr" + }, + "source": [ + "## **User-defined save paths**\n", + "\n", + "Although a library is required for a file dialogue pop-up, ... FINISH ALSO NEED TO CREATE CODE FOR THIS." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "aVs6rJBuJLiw" + }, + "source": [ + "## **Exercises**\n", + "\n", + "**Exercise 1**
\n", + "Take the day of the month in which you were born (e.g. this would be 10 is you were born on the 10th April), and create a file named 'element.txt' and write the name of the element corresponding to the atomic number matching this.

\n", + "\n", + "**Exercise 2**
\n", + "Determine the group that the element identified in Exercise 1 below to and append this information to your file.

\n", + "\n", + "**Exercise 3:**
\n", + "Three moles of an ideal gas are ontained within a frictionless piston at 298.15 K. Use Python to calculate the volume of the gas at the following four different pressures:
\n", + "1.00 kPa
\n", + "10.00 kPa
\n", + "50.00 kPa
\n", + "100.00 kPa
\n", + "and output the results in a file, formatted as two columns of numbers (to two d.p.), with the first column being pressure and the second being volume." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "tOX5HbrsJR02" + }, + "source": [ + "## **Learning Outcomes**\n", + "\n", + "FINISH" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "colab": { + "authorship_tag": "ABX9TyOe2vlSb52narfb6tegF/97", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/lessons/loops_functions/For_Loop_Lesson.ipynb b/lessons/loops_functions/For_Loop_Lesson.ipynb new file mode 100644 index 0000000..655f488 --- /dev/null +++ b/lessons/loops_functions/For_Loop_Lesson.ipynb @@ -0,0 +1,381 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "UuDCTZ7LX9Jb" + }, + "source": [ + "# The `for` loop\n", + "\n", + "## Prerequisites:\n", + "- Variables\n", + "- Comparison\n", + "- `if` statements" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2VRPDborAVn1" + }, + "source": [ + "

The `for` loop

\n", + "
\n", + "\n", + "\n", + "

One area where you will see a real benefit of using programming in your work is when you need to repeat a task over and over again. For example maybe you need to process the same type of data file many times with different values. This can take a lot of time one by one but Python can really come to your rescue and save you hours. Plus all your lab colleagues will be beating a path to your door to ask for your help. You will soon become the lab data processing guru!

\n", + "
\n", + "
\n", + " \n", + "
\n", + "
\n", + "\n", + "

One of the easiest way to perform this task is to use a 'for' loop

\n", + "\n", + "

Here is an example:

\n", + "\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "VSiGQd0PKsxD" + }, + "outputs": [], + "source": [ + "molecules = [\"H2\", \"H2O\", \"CH4\"]\n", + "\n", + "for mol in molecules:\n", + " print(mol)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hwu0INZoK5FO" + }, + "source": [ + "If you run the cell above, you should see three strings printed despite having only used a single `print()` statement. Let's look at this closer.\n", + "\n", + "We begin by defining a list of strings:\n", + "```python\n", + "molecules = [\"H2\", \"H2O\", \"CH4\"]\n", + "```\n", + "\n", + "We then start a loop with the line:\n", + "```python\n", + "for mol in molecules:\n", + "```\n", + "- `for` indicates that we will begin a loop.\n", + "- `mol` is a new variable that we are currently defining.\n", + "- `in molecules` indicates that we want to do repeat the operations in the loop once per element in the list `molecules`.\n", + "- `:` signals the beginning of the loop.\n", + "\n", + "After this line of code, `print(mol)` prints the contents of the `mol` variable to the screen.\n", + "\n", + "Notice how `print(mol)` has some leading spaces (typed with the `` key). We say that this piece of code is _indented_, meaning that it has one `` space separating it from the left side of the screen.\n", + "\n", + "When we write indented code below a line starting with `for`, all of that code gets repeated within the `for` loop. Conveniently, while we are within this loop, the variable `mol` will adopt the values of each element of `molecules` in sequence, changing at every loop.\n", + "\n", + "This is why `print(mol)` is effectively becoming `print(\"H2\")`, `print(\"H2O\")`, and `print(\"CH4\")` one after another.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
Task 1: Understanding a Loop \n", + "\n", + " Take a look at this code block and answer the questions\n", + "\n", + ">``` Python\n", + ">\n", + ">gas_list = ['Nitrogen', 'Oxygen', 'Fluorine']\n", + ">for gas in gas_list:\n", + "> print(gas)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "MULTIPLE CHOICE QUESTION\n", + "\n", + "- The loop will print the name of each gas on a separate line (correct)\n", + "- the loop will print one line with all the gas names\n", + "- The variable gas takes on each value of gas list in turn (correct)\n", + "- the variable gas_list changes each time around the loop" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
Task 2: Understanding a Loop \n", + "\n", + "In the lab you are making methyl benzoate according using the scheme below. Five scientists repeat the reaction starting with 3 g of benzoic acid and get of 2.5 g, 2.7 g, 3.1 g, 1.6 g and 4 g of product\n", + "\n", + "\n", + "\n", + "Lets use your understanding of for loops to quickly work out the yields for each person" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "product_mass_list = [2.5,2.7,3.1,1.6,4]\n", + "starting_mass = 3 # grams\n", + "theoretical_yield = (_______/_______)*136\n", + "for product_mass in product_mass_list:\n", + " percent_yield = (_________ / ___________) * 100\n", + " # the print statement uses the f-string syntax to format the output of the calculation - see lesson XX\n", + " print(f\"Percent yield: {percent_yield:.0f}%\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
Click here to see a possible solution to Task 2 \n", + "\n", + ">```Python\n", + ">product_mass_list = [2.5,2.7,3.1,1.6,4]\n", + ">starting_mass = 3 # grams\n", + ">theoretical_yield = (starting_mass/122)*136\n", + ">for product_mass in product_mass_list:\n", + "> percent_yield = (product_mass / theoretical_yield) * 100\n", + "> # the print statement uses the f-string syntax to format the output of the calculation - see >lesson XX\n", + "> print(f\"Percent yield: {percent_yield:.0f}%\")\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
Task 3: Understanding a Loop \n", + "\n", + "You have a series of temperature measurements from your reaction in degrees C and you want to print them out in Kelvin. One of your colleagues writes some code but it doesn't seem to be working. Can you identify the problem and fix the code?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Your colleagues code\n", + "\n", + "# The code below is not working. Can you fix it?\n", + "temperature_measurements = [27.3, 28.1, 26.9, 27.5, 28.0]\n", + "for temperature_C in temperature_measurements:\n", + " temperature_K = temperature_C + 273.15\n", + "print(f\"Temperature: {temperature_K}°C\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
Click here to see a possible solution to Task 3 \n", + "\n", + "Remember that the items that you want to do each time you go around the for loop need to be indented. In the example the print statement is not indented and so is not executed each time, but only one the loop is finished. You can fix the code just by indenting the print statement with the tab key.\n", + ">```Python\n", + ">temperature_measurements = [27.3, 28.1, 26.9, 27.5, 28.0]\n", + ">for temperature_C in temperature_measurements:\n", + "> temperature_K = temperature_C + 273.15\n", + "> print(f\"Temperature: {temperature_K}°C\")\n", + ">```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You seem to be really getting the hang ofd these for loops. Well done!\n", + "\n", + "When we are talking about for loops more generally we use the following terms:\n", + "- **Discrete variable**: a variable changes its value at every iteration of the loop (e.g. `temperature_C` in task 3).\n", + "- **Iterator**: a variable containing multiple values, which can be used in a `for` loop (e.g. `temperature_measurements` in the last example). Lists are the most common kind of operator in Python.\n", + "\n", + "The general syntax of a `for` loop is:\n", + "```python\n", + "for discrete_variable in iterator:\n", + " . # some\n", + " . # indented\n", + " . # code\n", + "```\n", + "\n", + "You can write Python code of any length inside a `for` loop as long as you respect its indentation. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
Task 4: Understanding a Loop \n", + "\n", + "Run the code below and answer the following questions to check your understanding" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "natural_amino_acids = [\"Alanine\", \"Arginine\", \"Asparagine\", \"Aspartic acid\", \"Cysteine\", \"Glutamic acid\", \"Glutamine\", \"Glycine\", \"Histidine\", \"Isoleucine\", \"Leucine\", \"Lysine\", \"Methionine\", \"Phenylalanine\", \"Proline\", \"Serine\", \"Threonine\", \"Tryptophan\", \"Tyrosine\", \"Valine\"]\n", + "for amino_acid in natural_amino_acids:\n", + " print(f\"Amino acid: {amino_acid}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "MULTIPLE CHOICE QUESTION\n", + "\n", + "- The discrete variable is amino acid (correct)\n", + "- The discrete variable is amino acids\n", + "- The iterator is amino_acid\n", + "- The iterator is amino_acids (correct)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
Task 5: Using loops \n", + "\n", + "When chemists want to store molecular structures in a computer they can store in an encoded way called SMILES strings. You don't need to understand what these mean but just to know that libraries that can handle chemical structure can read them. The code below will import the RDKit package and print the structure of benzoic acid. The code works by passing the SMILES string for benzoic acid to the function display_molecule that then draws it out. Check out the functions lesson if you want to understand more about functions, but for this lesson all you just need to follow the syntax below" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from rdkit import Chem\n", + "\n", + "def display_molecule (smiles_string):\n", + " mol = Chem.MolFromSmiles(smiles_string)\n", + " img=Chem.Draw.MolToImage(mol)\n", + " display(img)\n", + "\n", + "# display the structure of benzoic acid\n", + "benzoic_acid_miles = \"C1=CC=C(C=C1)C(=O)O\"\n", + "display_molecule(benzoic_acid_miles)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
Task 5 continued \n", + "Now you know how to print one molecule lets use your understanding of for loops to print lots of molecules. Here are a list of the smiles strings of some interesting molecules, Dolutegravir a very important anti-hiv drug, Atovaquone which treats malaria and paclitaxol that is an important \n", + "\n", + "\n", + "
\n", + "
    \n", + "
  • C[C@@H]1CCO[C@@H]2N1C(=O)C3=C(C(=O)C(=CN3C2)C(=O)NCC4=C(C=C(C=C4)F)F)O\n", + "
  • C1CC(CCC1C2=CC=C(C=C2)Cl)C3=C(C4=CC=CC=C4C(=O)C3=O)O\n", + "
  • CC1=C2[C@H](C(=O)[C@@]3([C@H](C[C@@H]4[C@]([C@H]3[C@@H]([C@@](C2(C)C)(C[C@@H]1OC(=O)[C@@H]([C@H](C5=CC=CC=C5)NC(=O)C6=CC=CC=C6)O)O)OC(=O)C7=CC=CC=C7)(CO4)OC(=O)C)O)C)OC(=O)C\n", + "
\n", + "
\n", + "Using the concepts above write a for loop that will draw the structrue of all 3 molecules. You need to:\n", + "- define a list of the smiles strings\n", + "- loop through the list and display each molecule using the display_molecule function" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "molecule_smiles = ['C[C@@H]1CCO[C@@H]2N1C(=O)C3=C(C(=O)C(=CN3C2)C(=O)NCC4=C(C=C(C=C4)F)F)O',\n", + "'C1CC(CCC1C2=CC=C(C=C2)Cl)C3=C(C4=CC=CC=C4C(=O)C3=O)O',\n", + "'CC1=C2[C@H](C(=O)[C@@]3([C@H](C[C@@H]4[C@]([C@H]3[C@@H]([C@@](C2(C)C)(C[C@@H]1OC(=O)[C@@H]([C@H](C5=CC=CC=C5)NC(=O)C6=CC=CC=C6)O)O)OC(=O)C7=CC=CC=C7)(CO4)OC(=O)C)O)C)OC(=O)C']\n", + "\n", + "for smiles in molecule_smiles:\n", + " display_molecule(smiles)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
Click here to see a possible solution to Task 5 \n", + "\n", + ">```Python\n", + ">molecule_smiles = ['C[C@@H]1CCO[C@@H]2N1C(=O)C3=C(C(=O)C(=CN3C2)C(=O)NCC4=C(C=C(C=C4)F)F)O',\n", + ">'C1CC(CCC1C2=CC=C(C=C2)Cl)C3=C(C4=CC=CC=C4C(=O)C3=O)O',\n", + ">'CC1=C2[C@H](C(=O)[C@@]3([C@H](C[C@@H]4[C@]([C@H]3[C@@H]([C@@](C2(C)C)(C[C@@H]1OC(=O)[C@@H]([C@H]>>>(C5=CC=CC=C5)NC(=O)C6=CC=CC=C6)O)O)OC(=O)C7=CC=CC=C7)(CO4)OC(=O)C)O)C)OC(=O)C']\n", + ">\n", + ">for smiles in molecule_smiles:\n", + "> display_molecule(smiles)\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Ejspk6fFPXFK" + }, + "source": [ + "## TODO\n", + "A second part of the lesson covering the following.\n", + "- Iterating with `range()`\n", + "- Using a loop to generate a list (and maybe list comprehension)\n", + "- Nesting loops\n", + "\n", + "The format should be the same as before: first a lesson, then a series of exercises.\n", + "\n", + "Any lesson should start with requirements and end with TODO if it isn't finished. Try to always be on the lookout for ties to Chemistry in your lesson and exercises.\n", + "\n", + "Explain potential error messages and consider debugging exercises." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "tpuihpop9duI" + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/lessons/loops_functions/PyinC_while_loops_WIP.ipynb b/lessons/loops_functions/PyinC_while_loops_WIP.ipynb new file mode 100644 index 0000000..f5092d3 --- /dev/null +++ b/lessons/loops_functions/PyinC_while_loops_WIP.ipynb @@ -0,0 +1,182 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# The ```while``` Loop" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites: \n", + "- logic/boolean \n", + "- comparison\n", + "- `if` statements\n", + "- `for` loops\n", + "\n", + "## Learning Objectives (WIP)\n", + "- Understand how to construct and use `while` loops\n", + "- Know how to control iterations in a loop\n", + "\n", + "## The `while` Loop\n", + "\n", + "A `while` loop is similar to a `for` loop [LINK] with the main difference being it will continuosly loop while a condition is `True`. As as example see the cell below which prints integers from 1 to 5." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "count=0\n", + "while count<5:\n", + " count+=1\n", + " print(count)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The first line defines our starting value and the second initiates our loop.\n", + "```python\n", + "while(count<5):\n", + "```\n", + "Looking closer at this line we have:\n", + "\n", + "- `while` which signals we want to start a loop\n", + "- `count<5` is our conditional statement\n", + "- `:` signals the start of the loop\n", + "\n", + "If our conditional statement is `True` the code prints out the current value of `count` and increases it by one for each iteration using the `+=` operator.\n", + "\n", + "In general `while` loops take the structure:\n", + "\n", + "```python\n", + "while condition:\n", + " code \n", + " block\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 1?\n", + "1. create a `while` loop to print even integers from zero to 10" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## MORE WIP NOTES \n", + "- wait for input\n", + "- `break` or `continue` \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Infinite `while` loops\n", + "\n", + "When constructing `while` loops be wary of your condition, one common bug can be creating a loop that runs forever:\n", + "\n", + "```python\n", + "count = 5\n", + "while count != 0:\n", + " print(count)\n", + " count -= 2\n", + "```\n", + "Bug fix? or explain that condition is never met?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "WIP EXAMPLE -- search through file until wanted line is found" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Password example??\n", + "\n", + "MAX_ATTEMPTS = 3\n", + "\n", + "correct_password = \"secret123\"\n", + "attempts = 0\n", + "\n", + "while True:\n", + " password = input(\"Password: \").strip()\n", + " attempts += 1\n", + "\n", + " if password == correct_password:\n", + " print(\"Login successful! Welcome!\")\n", + " break\n", + "\n", + " if attempts >= MAX_ATTEMPTS:\n", + " print(\"Too many failed attempts.\")\n", + " break\n", + " else:\n", + " print(f\"Incorrect password. {MAX_ATTEMPTS - attempts} attempts left.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## TO DO\n", + "- Useful chemical applications/exercises?\n", + "- `break`, `continue`\n", + "- loop while its condition remains True\n", + "- applications? -> program inputs, chemical?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/lessons/loops_functions/functions_and_scope.ipynb b/lessons/loops_functions/functions_and_scope.ipynb new file mode 100644 index 0000000..b3be580 --- /dev/null +++ b/lessons/loops_functions/functions_and_scope.ipynb @@ -0,0 +1,471 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "db5b621f-285a-4035-86f8-129e4382a8b5", + "metadata": {}, + "source": [ + "# Functions and Scope\n", + "\n", + "## Prerequisites:\n", + "\n", + "- Variables and Data Types\n", + "- Mathematical Operators\n", + "- Conditional Execution\n", + "- Loops\n", + "- Lists, Dictionaries and Tuples\n", + "\n", + "## Learning Objectives:\n", + "\n", + "- To learn how to re-run code which will be used often\n", + "- To understand the purpose of a function\n", + "- Understanding how function arguments work\n", + "- Understanding how functions return information\n", + " \n", + " \n" + ] + }, + { + "cell_type": "markdown", + "id": "1c23b1aa-bffb-4400-867c-042a065273f8", + "metadata": {}, + "source": [ + "When running Python scripts, we often use statements to change or read the values of variables. Take the following code, for instance, which looks to add up the values of numbers in a list. Here we can use it to generate the molecular mass of a molecule from a list of atomic masses. The script iterates through the list, and adds each element in it to a running total variable, which at the end of the function contains the total:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c60cd53-dab9-4810-9ec2-6bc1914af9a9", + "metadata": {}, + "outputs": [], + "source": [ + "m1 = [12,12,1,1,1,1]\n", + "\n", + "m1_total = 0\n", + "\n", + "for i in m1:\n", + " m1_total += i\n", + "\n", + "print(m1_total)\n" + ] + }, + { + "cell_type": "markdown", + "id": "6603b780-f776-4993-9f61-b02a303b5e8a", + "metadata": {}, + "source": [ + "This code works well to add up the numbers in the list, and if we're just doing this once, will serve perfectly fine. However, if you had another list you needed to add up this way, you would need to write this expression again. If you had 100 lists, you could be spending a lot of time writing just these few lines of code." + ] + }, + { + "cell_type": "markdown", + "id": "c4c048a9-fa8c-43d2-ae91-48939a2d02c2", + "metadata": {}, + "source": [ + "## Defining functions:\n", + "\n", + "Functions offer a way for us to package up frequently-run code into an easily callable package, which we can call repeatedly. Let's now wrap the code used to add up the list elements in a function, called `add_up`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d03d38ba-1447-4f03-86b0-6c09c09297af", + "metadata": {}, + "outputs": [], + "source": [ + "def add_up(list_of_atoms):\n", + " total = 0\n", + " for atom in list_of_atoms:\n", + " total += atom\n", + " return total\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "59c43866-bfd3-4e98-abe9-fa41d97cf5b1", + "metadata": {}, + "source": [ + "To turn our adding up into a function, we have added a line before and after. To start with, we have added the statement `def add_up(list_of_atoms):` to the start of our code. This tells Python that we are defining a function, and that it is to treat all indented lines following the colon as part of the function. The `list_of_atoms` contained within the brackets is the function's _argument_. Functions can take many arguments (or none) but this function just takes one: the list which we are asking it to add up. \n", + "\n", + "Following the iterative adding process, the function is asked to `return` the total. Whatever is on the return line of the function is what the function will give back once it has finished running. Occasionally functions will just end in `return`, but generally something should be put on this line so that the function can pass it back. \n", + "\n", + "Below, we use our new `add_up` function to perform the same operation on `l1` and store the result in variable `x`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4a30ee2e-a69a-4495-b681-cb58d2437655", + "metadata": {}, + "outputs": [], + "source": [ + "x = add_up(m1)\n", + "\n", + "print(x)" + ] + }, + { + "cell_type": "markdown", + "id": "d417fb60-282e-4457-a911-c0f94b50afb4", + "metadata": {}, + "source": [ + "Here you may be asking why we need the `return total` statement in our code, as we should be able to reference just the variable `total` which is used as our running total during the function's loop. However, if we try that, we will get an error:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8a25e4c-cd67-4ae3-a784-a8f7b1078cd2", + "metadata": {}, + "outputs": [], + "source": [ + "x = add_up(m1)\n", + "\n", + "print(total)" + ] + }, + { + "cell_type": "markdown", + "id": "fc7bffb4-2db8-4ab2-9570-49a13975ec9b", + "metadata": {}, + "source": [ + "Here, Python is telling us that the variable named `total` is not defined. This highlights an important feature of functions in Python. Functions only return what is included on the return line, and any other variables which we define in them which are not returned are lost once the function has finished executing. However, this is not true the other way around. Functions *do* have access to variables which have not been given to them explicitly as arguments. See below that we can initialise a variable `foo` which contains the string `\"bar\"`. We can then also initialise the function `readfoo()` which takes no arguments, but prints the value of the variable `foo`. If we call this function, we can see that the string `bar` is printed to the console. This shows us that even though we did not explicitly pass the variable `foo` to our function, it was able to find the value of the variable `foo` and output it to the console anyway. This is because `foo`, having been declared in our main script, is a *global* variable, in contrast to function variables, which are *local* variables. Remember that if you see an error like this in your code output, it is likely because you have referenced a value which only exists inside the function from outside of it. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b8cdf670-d3e8-4504-8240-4628fd65ec6a", + "metadata": {}, + "outputs": [], + "source": [ + "foo = \"bar\"\n", + "\n", + "\n", + "def readfoo():\n", + " print(foo)\n", + " return\n", + "\n", + "readfoo() # Note here that even though readfoo takes no arguments, we still need to supply some empty brackets after it when calling it.\n" + ] + }, + { + "cell_type": "markdown", + "id": "10374f42-0a0f-4457-b3b7-b0f8443d3fd9", + "metadata": {}, + "source": [ + "## Calling functions:\n", + "\n", + "Now that we've written our `add_up` function, we can use it to add up lots of lists very quickly. Here, we can define a list of lists, then iterate through that to provide a list of their totals. To call the function, all we need to do is write the name of the function, and enclose the list on which we would like it to operate in the brackets:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6f554c80-ff5a-4db0-b432-ef087b1d5252", + "metadata": {}, + "outputs": [], + "source": [ + "many_sets_of_atoms = [\n", + " [12,12,1,1,1,1],\n", + " [12,1,1,1,12,16,12,1,1,1],\n", + " [12,12,12,12,12,12]\n", + "]\n", + "\n", + "totals = []\n", + "\n", + "for atom_set in many_sets_of_atoms:\n", + " set_total = add_up(atom_set)\n", + " totals.append(set_total)\n", + "\n", + "\n", + "print(totals)" + ] + }, + { + "cell_type": "markdown", + "id": "8e0c9d02-ebf4-4467-83d5-d281a3cb6132", + "metadata": {}, + "source": [ + "In the example above, we are actually calling two functions every time our loop executes. The first is the `add_up` function which we have written, but the second is a the function we use to add the number to the list. We call the `list.append()` function, which adds its argument to the end of the list. Note here that the dot `.` between the `totals` and `append` is a signifier that this append function is specifically associated with the list stored in the `totals` variable. This type of function is quite common in Python, but is outside the scope of this lesson. For now, the important thing to note from this is that due to this association, we do not need to pass the `totals` list as an argument to the `append` function. \n", + "\n", + "Python has a huge amount of pre-set functions, many of which you may have already used. The `print()` and `type()` functions are ubiquitious in Python programming, but there are also many other functions which are pre-packaged in Python. In fact, the function that we have been looking at so far, `add_up()` replicates the behaviour of the inbuilt Python `sum()` function. " + ] + }, + { + "cell_type": "markdown", + "id": "cfd2f639-6eb3-4378-8c31-8f391d7ddbdf", + "metadata": {}, + "source": [ + "## More complex functions\n", + "\n", + "So far we have covered basic functions, but there are more complex facets to function writing. In this section, we will look at a few of these facets, although there are many more which will not be covered here.\n", + "\n", + "### Multiple return conditions\n", + "\n", + "Functions we have written so far have only had one return statment right at the end. This is not, however, a requirement. A function can have a return statement anywhere, and it can have more than one. This is usually encountered when functions contain if statements, where depending on whether the conditions are met, different sections of the function may execute. Take the below function, for example, which checks if a supplied letter is a vowel or not:\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "03ea1aea-92db-4b13-97cd-ef159f206cd3", + "metadata": {}, + "outputs": [], + "source": [ + "def is_vowel(letter):\n", + " if type(letter) is not str or len(letter) != 1:\n", + " print(\"Input must be a single character\")\n", + " return None\n", + " elif letter in [\"a\",\"e\",\"i\",\"o\",\"u\"]:\n", + " return True\n", + " else:\n", + " return False" + ] + }, + { + "cell_type": "markdown", + "id": "354eeb4c-e5bf-42ed-b877-9550d7f30730", + "metadata": {}, + "source": [ + "There are three different possible return values in the above function, depending on the input. The first conditional statement confirms that a single character has been passed to the function as a string. There are more sophisticated ways to handle this sort of error, but these are outside the scope of this lesson. The key thing here is that based on this test, we can have the function return `None` rather than true or false, if an incompatible input is supplied. Following this, the function uses if/else tests to check if the single character is a vowel or not. \n", + "\n", + "We can also return more than one thing on the return line. If we define a function which uses the inbuilt python `min()` and `max()` functions to return the largest and smallest items in a list, we can return both in one statement:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1fcf6271-7e69-43c3-bd14-de1e1aff0c7f", + "metadata": {}, + "outputs": [], + "source": [ + "def minmax(number_list):\n", + " min_value = min(number_list)\n", + " max_value = max(number_list)\n", + " return min_value, max_value" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "279c982c-39a6-4414-a5e9-487979d3eb8e", + "metadata": {}, + "outputs": [], + "source": [ + "x = minmax([1,2,3])\n", + "\n", + "print(x)\n", + "\n", + "y,z = minmax([1,2,3])\n", + "\n", + "print(y)\n", + "print(z)" + ] + }, + { + "cell_type": "markdown", + "id": "9db49603-743b-43ee-9351-3a3cf09a8008", + "metadata": {}, + "source": [ + "As you can see above, when we store the output of this function in a single variable, it is returned as a tuple containing both values. However, in Python we can also use the multiple assignment variable unpacking feature to assign the minimum and maximum values in a single statement. This sort of behaviour is useful when we want to return and assign multiple variables from a single function." + ] + }, + { + "cell_type": "markdown", + "id": "14e8bd90-4002-4b5e-92eb-8a6fe0eee1a1", + "metadata": {}, + "source": [ + "# Debugging\n", + "\n", + "The following code chunks have errors in them. See what output the chunk is currently providing, and fix the errors to give the expected output" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47374f25-3d38-4b46-9442-acdff2dddd26", + "metadata": {}, + "outputs": [], + "source": [ + "def say_hello():\n", + " print(\"Hello World\")\n", + "\n", + "\n", + "say_hello\n", + "\n", + "#Expected output: Hello World" + ] + }, + { + "cell_type": "markdown", + "id": "4b8b293d-cc79-40e9-a83c-b8f75454aec2", + "metadata": {}, + "source": [ + "# Exercises:\n", + "\n", + "1. Write a function that takes one argument, `num`, and returns `True` if it is even and `False` if it is odd. \n", + "\n", + "Remember that the modulo operator (%) returns the remainder of the left hand quantity when divided by the right hand quantity." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "950d5308-327c-41f4-9560-3d96e72996e2", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "abf7a379-edaf-4d04-857a-ba5ffccd01c4", + "metadata": {}, + "source": [ + "2. Using your function above, write a function which takes a list of integers, and returns only the even integers of this list" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cbe33a5b-28c9-433f-a8ab-8bea29570d2b", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "7a07fe93-0917-4b8b-ac26-cc6c13353b25", + "metadata": {}, + "source": [ + "3. The function `add_up()` defined earlier in the document accepted a list of atomic masses. However, molecules are more generally referred to using formulae rather than lists of masses. Write a series of functions as directed in the comments in the cell below to allow calculation of molecular masses from molecular formulae for simple organic molecules:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "991aba54-f8ab-4431-aba2-36fd3843401a", + "metadata": {}, + "outputs": [], + "source": [ + "# Write a function to look up the atomic mass of an atom based on its chemical symbol. Use the dictionary below to reference the masses. \n", + "# Don't worry about other elements for the time being, you can assume that these are the only elements that matter (pretend you're an organic chemist)\n", + "\n", + "atom_masses = {\n", + " \"C\" : 12,\n", + " \"H\" : 1,\n", + " \"O\" : 16,\n", + " \"N\" : 14\n", + "}\n", + "\n", + "\n", + "\n", + "\n", + "# Now write a function to take a list of atomic numbers, and apply your function above to each element in turn to provide a list of masses\n", + "\n", + "\n", + "\n", + "# Finally, define a function which calls the two above in combination, accepting a list of elemental symbols and returning a mass value\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1aa7bd24-0487-4ff2-b961-b2ba35850f11", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "203732e1-509b-436a-a2b3-fcde5b3d8ab6", + "metadata": {}, + "source": [ + "# Answers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e14aea88-2dd4-486a-8a11-ba69db8256c5", + "metadata": {}, + "outputs": [], + "source": [ + "# Problem 1:\n", + "\n", + "def is_even(num):\n", + " if num%0 == 0:\n", + " return True\n", + " else:\n", + " return False\n", + "# Problem 2:\n", + "\n", + "def keep_evens(num_list):\n", + " evens = []\n", + " for num in num_list:\n", + " if is_even(num):\n", + " evens.append(num)\n", + "\n", + " return evens\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "26af8885-0ec8-4421-8947-89f371cf350f", + "metadata": {}, + "source": [ + "TODO:\n", + "\n", + "- More relation to chemistry in some of the later examples?\n", + "- Discussion of use of *args etc to supply multiple arguments to a function\n", + "- Answer to Q3\n", + "- More debugging exercises\n", + "- Discussion of recursion?\n", + "- Defining functions within functions - further discussion of scope\n", + "- Default arguments\n", + "\n", + "Please email theo.tanner@chem.ox.ac.uk with any questions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a571c19b-6970-4073-8a24-4cf10d757fb8", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.12.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/lessons/manipulating_variables.md b/lessons/manipulating_variables.md new file mode 100644 index 0000000..f588326 --- /dev/null +++ b/lessons/manipulating_variables.md @@ -0,0 +1,3 @@ +# Manipulating Variables + +These lessons introduce different types of variables used in Python, and how to manipulate them. diff --git a/lessons/organising_code.md b/lessons/organising_code.md new file mode 100644 index 0000000..b461946 --- /dev/null +++ b/lessons/organising_code.md @@ -0,0 +1,3 @@ +# Organising Code + +These lessons describe how to write code efficiently by organising it into loops and functions. diff --git a/lessons/variables/Conditions.ipynb b/lessons/variables/Conditions.ipynb new file mode 100644 index 0000000..40aa518 --- /dev/null +++ b/lessons/variables/Conditions.ipynb @@ -0,0 +1,869 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "bfa23092-475a-4e40-a6cd-538bb1b16a5a", + "metadata": {}, + "source": [ + "# Comparisons and Conditional Statements" + ] + }, + { + "cell_type": "markdown", + "id": "27111d44-d8ba-4393-bb63-7a1521a4a956", + "metadata": {}, + "source": [ + "## **Requirements**" + ] + }, + { + "cell_type": "markdown", + "id": "98242630-1ee1-4fe6-bd25-d3bd5805c7ee", + "metadata": {}, + "source": [ + "- Variables\n", + "- Mathematical Operations\n", + "- Data types" + ] + }, + { + "cell_type": "markdown", + "id": "63b3ed50-5670-4fcb-9cd4-81e0a50b650e", + "metadata": {}, + "source": [ + "## **Learning Objectives**" + ] + }, + { + "cell_type": "markdown", + "id": "b56ee7b2-cffc-471e-9fd2-bf2b2c437894", + "metadata": {}, + "source": [ + "- To understand how in python we can compare objects to each other.\n", + "- To understand how we can use logical statements to perform multiple comparisons or assessments at once.\n", + "- To see how we can build statements and scripts that can do different tasks when we give them different inputs." + ] + }, + { + "cell_type": "markdown", + "id": "9e1407f3-8962-4a02-9956-ceaa9523df12", + "metadata": {}, + "source": [ + "## **Lessons**" + ] + }, + { + "cell_type": "markdown", + "id": "dad9b34b-ec0d-4b52-abd3-07b9efc631f4", + "metadata": {}, + "source": [ + "### Comparisons in Python" + ] + }, + { + "cell_type": "markdown", + "id": "423201d6-956c-4bab-973f-981ee93188ef", + "metadata": {}, + "source": [ + "Python has a number of different ways in which it can compare objects, variables or just numbers. These can be very useful both for simple tasks (\"Does H$_2$O have a higher molecular weight than NH$_3$\") and more complex ones (\"How do we know that this peak in an IR spectrum is above the baseline noise?\")\n", + "\n", + "Let us start by looking at a few of the [mathematical operators](https://en.wikipedia.org/wiki/Test_Card_F#/media/File:Testcard_F.jpg) (either identical or very similar to how you would write them down on paper) that can be used directly in Python:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "de0e669c-1c14-47ad-b12d-5b25c0fdaf35", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "4 > 2" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "e5d946d4-36d2-4114-bb2f-326975ee0ee5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "5.1 < 3.6" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "dd5f7b7d-b9c7-411c-bef6-af9154332c9f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "4 >= 4" + ] + }, + { + "cell_type": "markdown", + "id": "732d5859-56b9-48d6-beff-8ee521d46879", + "metadata": {}, + "source": [ + "We can see a few things from the above statements: firstly that running a comparison between two numbers in a code block outputs either 'True' if the expression is indeed true, or 'False' if not. Second, both the greater than (\">\") and less than (\"<\") mathematical operations are identical to those used in standard mathematical notation, while the greater than or equal to operation (\"≥\") is written with two characters, ```>=```. Finally, we can see that this works for both numerical [data types](https://en.wikipedia.org/wiki/Test_Card_F#/media/File:Testcard_F.jpg) in Python - integers and floats. \n", + "\n", + "What if we wanted to check if two values were exactly equal? **Be careful!** We know from our understanding of [variables](https://en.wikipedia.org/wiki/Test_Card_F#/media/File:Testcard_F.jpg) that ```=``` is used in python to assign values to variable names, we cannot use it here. Instead:" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "962ed8f3-bb4e-4826-a348-4d42fb38025e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "4 == 4" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "39103a6d-8149-4a1e-9be8-f59f8231d729", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "4 != 4" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "ff5c56d6-1170-4464-8ce3-23395e43a744", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "3.1 != 3" + ] + }, + { + "cell_type": "markdown", + "id": "c42c319f-594f-47a2-bb2f-535840c1ed80", + "metadata": {}, + "source": [ + "The double equals ```==``` is used to compare if two values are equal, while ```!=``` checks if two values are not equal.\n", + "\n", + "What about other data types? Let us try some examples of strings or lists using the ```==``` comparison operator." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "2331f446-16b9-4b2a-82ca-c7c90aeaa15c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"CH4\" == \"CH4\"" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "3c29dc42-ae21-4a7f-beff-8c115fb3a7c8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"NH3\" == \"H3N\"" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "be03a6a0-eff3-4135-9258-97c46a00221d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[2, 3, 5] == [2, 3, 4]" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "a6d6ecf7-38ca-4fc8-998f-9987dbd5a024", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[\"helium\", \"neon\", \"argon\"] == [\"helium\", \"neon\", \"argon\"]" + ] + }, + { + "cell_type": "markdown", + "id": "4239a695-24f5-4120-b42e-f7ca60b27aa2", + "metadata": {}, + "source": [ + "Note that all parts of the string (including order of characters) and all parts of a list (including the order of elements) need to be identical for the ```==``` operation to return 'True'. There is an alternative comparison that can be made - what if we wanted to distinguish if those two lists not only contained the same elements in the same order but if they are exactly the same object (i.e. rather than just looking the same, they are actually the same 'behind the scenes')? For this, we can use ```is```:" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "6ebfdf09-34fa-4919-a6f1-ba1b6fc12e1f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = [\"N\", \"H\", 3] \n", + "y = [\"N\", \"H\", 3]\n", + "x is y" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "462ee079-297b-4e00-bd37-6ff3df21a4af", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = y\n", + "x is y" + ] + }, + { + "cell_type": "markdown", + "id": "be246bfa-183d-42a7-8388-b0af6bbba21c", + "metadata": {}, + "source": [ + "In the first example, despite the two variables, ```x``` and ```y```, containing the same chemical formula (in the same order), the two are currently two separate instances of variables according to python, so ```x is y``` is False. In the second block, we specifically reassign the variable x to the value of y, and so now the ```is``` comparison is true." + ] + }, + { + "cell_type": "markdown", + "id": "0deade2a-b54e-4888-8b22-48f902c82ce4", + "metadata": {}, + "source": [ + "### Boolean logic operators" + ] + }, + { + "cell_type": "markdown", + "id": "b818dedf-8ad5-4926-89d1-76e721599366", + "metadata": {}, + "source": [ + "Can we make multiple comparisons at the same time - i.e. to check if a number is within a certain range of bounds? Yes, and for this, we need Boolean operators - these are written as words but still make comparisons between two things: ```and```, ```or``` and ```not```. \n", + "\n", + "What does these mean? Let's start with ```and```:" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "302f094f-766c-47fb-95ae-a89eed39ffac", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z = 2\n", + "z < 3 and z > 0.1 " + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "b15d57e0-6260-42a5-94d8-f1e45743a40b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z < 3 and z != 2" + ] + }, + { + "cell_type": "markdown", + "id": "06f35439-6217-4e18-a68b-e4375fa3025a", + "metadata": {}, + "source": [ + "When using ```and```, the statement before the ```and``` and after the ```and``` must **both** be 'True' for the overall result to be 'True', hence why the two code blocks give different answers: while z is less than 3 in both statements, z is equal to 2, and so the second statement in the second code block is 'False'. I.e. if Statement A is True AND Statement B is False, ```A and B``` is False.\n", + "\n", + "What about ```or```?" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "f016ee5a-25b4-4547-857f-b10f5c1d48d3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z < 3 or z > 0.1" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "e97f2cdf-8e79-4eba-b5dc-2cbca8710b8e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z < 3 or z !=2" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "d14bcff8-6b5f-4055-88bb-e18e3a0cafd0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z > 3 or z != 2" + ] + }, + { + "cell_type": "markdown", + "id": "448d821c-a069-455f-9992-a6320bbea6fb", + "metadata": {}, + "source": [ + "With ```or``` - only one of the two comparisons must be true for the whole statement to be 'True', though the whole statement will still be False if neither of the two are True. \n", + "\n", + "You don't need to just have two comparisons!" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "87ab9e7d-dc0d-44d5-9f0e-94b79f728f5f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "w = \"tungsten\"\n", + "w == \"neon\" or w == \"iron\" or w == \"bismuth\" or w == \"tungsten\"" + ] + }, + { + "cell_type": "markdown", + "id": "1c2b08e0-672b-46e7-b92e-ee9a35d69907", + "metadata": {}, + "source": [ + "Finally, not is slightly different - first it should be used before a statement, i.e. (```not a == 2```). \n", + "It can then be used to 'invert' the True or False behaviour of a statement: if a statement was true, not will make it False, or vice versa:" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "f30a769e-184f-4d13-aab3-ccd2a91f6470", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z = 2\n", + "not z <= 2" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "40c9c586-0376-48c5-97cb-279d31c26067", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "not z > 3 or z != 2" + ] + }, + { + "cell_type": "markdown", + "id": "c64ae47b-9a30-4e23-a0f1-476b24106163", + "metadata": {}, + "source": [ + "#### **Note for the future: may be worth linking to outside resources on Boolean logic?**" + ] + }, + { + "cell_type": "markdown", + "id": "79597a1c-5dd4-4426-b21e-eb8135a9bfd0", + "metadata": {}, + "source": [ + "### Conditional Statements" + ] + }, + { + "cell_type": "markdown", + "id": "feabf370-ad13-48b3-aba6-16dc7c74d5c0", + "metadata": {}, + "source": [ + "How are these comparisons useful for working with actual chemical data though? Writing a comparison for every data point would get very tiring! This is where conditional statements come in -- we can use the comparisons we have learned about to check **if** certain relationships are true as part of our data sets, and then either do something or not, or even doing a different operation...\n", + "\n", + "We do this, sensibly, through what are called **if statements**. If statements require specific syntax:\n", + "```\n", + "if :\n", + " what to do if statement is true\n", + "```\n", + "\n", + "When the statement after ```if``` is True, then Python will go on to do whatever is **indented**. Indentation is the way for python to know what is part of the ```if``` statement and what is the rest of the code. As a standard, indenting is 4 spaces before the code line -- many programs like jupyter notebook will automatically do this indenting after the if statement is written and you move to a new line with the Return key.\n", + "\n", + "If what comes after the ```if``` is False, then the indented code is ignored, and Python continues onto whatever the next non-indented lines are. As with loops, there must be a colon after the if statement, and there must be an indentation -- not having these can cause errors." + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "3761936a-7163-41de-813b-580ce83a8857", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Yes, these are the same formula\n" + ] + } + ], + "source": [ + "x = \"CH4\"\n", + "y = \"CH4\"\n", + "if x == y:\n", + " ### This part of the code is indented, and is run if the if statement is true\n", + " print(\"Yes, these are the same formula\")" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "34f11095-cd62-40a6-ad7a-9df4dd7eae14", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The indentation has ended, this code line is always run\n" + ] + } + ], + "source": [ + "x = \"CH4\"\n", + "y = \"NH3\"\n", + "if x == y:\n", + " print(\"Yes, these are the same formula\")\n", + "\n", + "print(\"The indentation has ended, this code line is always run\")" + ] + }, + { + "cell_type": "markdown", + "id": "f5e0ff28-eec5-4508-b5dd-ccea6d24c9e9", + "metadata": {}, + "source": [ + "What if we want to have multiple different categories and multiple different outcomes? We can use ```if... else``` if we want to do one thing if a statement is true, and then something else for for all other possibilities. Alternatively, if we have more than two decisions to make, we can use ```if... elif... else```, with ```elif``` statements acting like other if statements that are checked if they are true. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "b66d509c-f888-45a0-ab94-7c8115852979", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This compound is methane\n" + ] + } + ], + "source": [ + "x = \"CH4\"\n", + "if x == \"CH4\":\n", + " print(\"This compound is methane\")\n", + "elif x != \"NH3\":\n", + " print(\"This compound is not ammonia\")\n", + "else:\n", + " print(\"This compound is ammonia\")" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "64bfd426-81a8-44f3-a54e-cd2f9e99687e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This compound is not ammonia\n" + ] + } + ], + "source": [ + "x = \"H2O\"\n", + "if x == \"CH4\":\n", + " print(\"This compound is methane\")\n", + "elif x != \"NH3\":\n", + " print(\"This compound is not ammonia\")\n", + "else:\n", + " print(\"This compound is ammonia\")" + ] + }, + { + "cell_type": "markdown", + "id": "46cb8ac8-5627-4ddb-a169-552794c2099d", + "metadata": {}, + "source": [ + "Be careful, conditional statements are strictly ordered - if the first ```if``` is True, then that code block will be run, while all further ```elif``` statements are ignored, even if they would also be true!" + ] + }, + { + "cell_type": "markdown", + "id": "0a5899ad-5b4a-439b-bd47-df83a6d37136", + "metadata": {}, + "source": [ + "### **Tasks**" + ] + }, + { + "cell_type": "markdown", + "id": "116cf3f9-74fa-46fe-a06c-ee5cec0a4b9b", + "metadata": {}, + "source": [ + "1. The following commented code needs the correct operator to replace the **BLANK** in the code to output True - what replaces the **BLANK**?" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "a827cfbe-7726-4a42-bb38-0468a752b998", + "metadata": {}, + "outputs": [], + "source": [ + "atomic_no_of_nitrogen = 7\n", + "atomic_no_of_fluorine = 9" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "81dd9a93-9296-4da8-be41-3f4fc6989d56", + "metadata": {}, + "outputs": [], + "source": [ + "# atomic_no_of_nitrogen BLANK atomic_no_of_fluorine" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "b3f749e9-674c-428c-8eeb-df549473ebae", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "### ANSWER: <, <= or != all work\n", + "atomic_no_of_nitrogen < atomic_no_of_fluorine" + ] + }, + { + "cell_type": "markdown", + "id": "5ccf3004-bb13-465f-90b9-a6c871c09f72", + "metadata": {}, + "source": [ + "2. The following code gives an output that doesn't match chemical intuition, can you fix it so that it will output a correct statement?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "768b30a4-d3f7-4abd-97ae-6a27bcfcb9b7", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "120f98bf-03ef-49b8-8338-6081411d2b10", + "metadata": {}, + "source": [ + "### **Learning Outcomes**" + ] + }, + { + "cell_type": "markdown", + "id": "b2a04b94-1118-422a-a616-ff6983cb92fa", + "metadata": {}, + "source": [ + "In this lesson we have learned:\n", + "- How to make comparisons between numbers and variables of different data types, getting Boolean True or False statements\n", + "- How we can use Boolean operators such as ```and``` and ```or``` to compare if multiple statements are True or False in different combinations.\n", + "- How to use ```if...elif...else``` statements to do certain tasks only if certain comparisons or statements are the case." + ] + }, + { + "cell_type": "markdown", + "id": "be1e9adf-0c99-47e1-8fe7-01f461d77e08", + "metadata": {}, + "source": [ + "### TODO" + ] + }, + { + "cell_type": "markdown", + "id": "4163f470-0898-4966-aa1e-fa2f9644278b", + "metadata": {}, + "source": [ + "- add comments to code?\n", + "- note different data type behaviour for is (e.g. strings versus lists as given)\n", + "- Think of more imaginative chemistry related examples for the lessons\n", + "- More tasks!\n", + "- Debugging task - maybe using a complex if not statement giving the wrong output?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "105d0079-c0ae-4a11-bccd-4d84b32ad1b5", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/lessons/variables/Variable_data_types.ipynb b/lessons/variables/Variable_data_types.ipynb new file mode 100644 index 0000000..99b59b1 --- /dev/null +++ b/lessons/variables/Variable_data_types.ipynb @@ -0,0 +1,425 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "VqjrEzS2z1Ol" + }, + "source": [ + "# Variable Data Types\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_iRikrUPUjs3" + }, + "source": [ + "### Learning Outcomes\n", + "\n", + "* Understand how to print basic outputs in python\n", + "* Understand how to identify and verify the type of variable\n", + "* Create and print lists in python\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Kup00O1iVHOG" + }, + "source": [ + "### Prerequisites\n", + "\n", + "- Be able to access Google Colab, Jupyter Notebooks or another piece of software that will allow you to interact and practice the code" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IxCxV-mv0Svg" + }, + "source": [ + "A variable is a place where some information can be held in the code, and can be used in many different ways within a programme." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "65Jiw2TX0QQQ" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "pNvKKeprCw5V" + }, + "source": [ + "## Print Function\n", + "\n", + "Python can specified message using the print function. This is one of the main ways you will output information." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "VQe62zJIDd2s" + }, + "outputs": [], + "source": [ + "message = \"we love chemistry\"\n", + "print(message)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6K3DweS-SJkH" + }, + "source": [ + "You can use the print function to print answers to calculations. Remember to use brackets for more complex calculations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "mIQZr9GdSSzy" + }, + "outputs": [], + "source": [ + "print(54*145)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "E7oo-rhqLU4O" + }, + "source": [ + "## Type Function\n", + "\n", + "This is a built-in function that is used to return the type of data stored in the objects or variables in the program. For example, if a variable contains a value of 45.5 then the type of that variable is float.\n", + "\n", + "This is useful as when you have multiple data a variable types you check that they are functioning in the correct way." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "e1jc0uR_LXLE" + }, + "outputs": [], + "source": [ + "number = 45.5\n", + "print(type(number))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0LF3cDZLBe82" + }, + "source": [ + "## Naming of variables\n", + "\n", + "There are few strict conventions with the naming of variables, and Python can be incredibly tolerant in this regard. However, for the ease of legibility of code, and minimise mistakes caused by referring to the wrong variable, it is sensible to try and use a clear and consistent approach to variable naming.\n", + "\n", + "### Variable name requirements\n", + "\n", + "\n", + "* Variables can only start with a letter or underscore (_) character and may not start with a number.\n", + "* Can only include upper and lowercase letters, numbers and the underscore character (A-z, 0-9, and _ )\n", + "* Names must not be a [Python keyword](https://docs.python.org/3/reference/lexical_analysis.html#keywords)\n", + "\n", + "### Choosing variable names\n", + "Short, descriptive names are generally a good choice, as variables will often need to be entered in multiple places in code. Names can consist of multiple words, but cannot use spaces. Commonly 'camelCase' is used with variable naming, where a multiple word variable name is closed together (ie the spaces are removed), and the initial letter of each word being capitalised (excluding the first word).\n", + "\n", + "Examples might include:\n", + "\n", + "\n", + "* elementMass\n", + "* elementAtomicNumber\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "VPhG17aLAcBb" + }, + "source": [ + "## Types of variables\n", + "Some of the common variable types are outlined below. For each type of variable, there is a code snippet which shows how the variable is set, the variable is printed, and the type of variable is printed." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "PwADJGso9G7-" + }, + "source": [ + "### Strings\n", + "\n", + "These store a sequence of characters. You signify what characters are stored by writing quotation marks either side of the characters. These can be double or single quotation marks. It will still work either way. Just be consistent." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ObD5OOJswqse" + }, + "outputs": [], + "source": [ + "subject = \"Chemistry\"\n", + "print(subject)\n", + "print(type(subject))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "j2LOZu_qAnti" + }, + "source": [ + "### Numbers" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5Zzn3B9OAq1d" + }, + "source": [ + "#### Integer\n", + "\n", + "This in any whole number e.g. 5. If your variable type is an integer you will see the class output will be displayed as 'int'." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "FV_SqZ4N3edG" + }, + "outputs": [], + "source": [ + "number = 5\n", + "print(number)\n", + "print(type(number))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "tmlYe2PTAzCN" + }, + "source": [ + "#### Float\n", + "\n", + "This is any number where you have a decimal place. If your variable type is a float, you will see the class output will be displayed at 'float'." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "axf-MWdz4V03" + }, + "outputs": [], + "source": [ + "number = 5.3\n", + "print(number)\n", + "print(type(number))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xuiU47q1A3qV" + }, + "source": [ + "#### Standard form\n", + "\n", + "When writing standard form, as is the case for Avogadro's constant you would use e to show that the number is multipled by 10 to the power of 23." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "SF6MngZc5LTw" + }, + "outputs": [], + "source": [ + "avogadro = 6.023e23\n", + "print(avogadro)\n", + "print(type(avogadro))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "aWRMOW5M7b2D" + }, + "source": [ + "#### Complex Numbers\n", + "\n", + "You may not use complex numbers when you first start out on your chemistry course, but you will come across them later in maths and potentially when you study crystallography, quantum mechanics and other areas of science.\n", + "\n", + "When using complex numbers in python, you cannot use $i$ for imaginary numbers, you must use $j$ instead. In teh example below we have the complex number $3+3i$ which is written as $3+3j$ in the code." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "v6df_hB45r-3" + }, + "outputs": [], + "source": [ + "complexNumber=(3+3j)\n", + "print(complexNumber)\n", + "print(type(complexNumber))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "K6aMfYCUAjMn" + }, + "source": [ + "#### Boolean" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gkuDEMKq4csJ" + }, + "outputs": [], + "source": [ + "Answer = True\n", + "print(Answer)\n", + "print(type(Answer))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HFWW4cO9BlLI" + }, + "source": [ + "#### Lists" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "3C66kNgC4sQf" + }, + "outputs": [], + "source": [ + "elements = ['H', 'He']\n", + "print(elements)\n", + "print(type(elements))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "98-HGTmIBoSl" + }, + "source": [ + "#### Dictionaries" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "lAOQrm4LE24D" + }, + "outputs": [], + "source": [ + "ram = {\n", + " \"Hydrogen\": 1.008,\n", + " \"Helium\": 4.002602,\n", + " \"Lithium\": 6.941\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "EbJjHF7fD0Ea" + }, + "outputs": [], + "source": [ + "data = {\n", + "'H' : [(1.007825, 99.9885),(2.014102, 0.0115)],\n", + "'C' : [ (12.0, 98.93),(13.003355, 1.07)],\n", + "'N' : [(14.003074, 99.632),(15.000109, 0.368)],\n", + "'O' : [(15.994915 , 99.757),(16.999132, 0.038),(17.999160,0.205)]\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5Rep96srUZeM" + }, + "source": [ + "### TO-DO List\n", + "\n", + "Add in f-strings - should this be as a separate page?\n", + "\n", + "Add in some more worked examples\n" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/lessons/variables/mathematical-operators.ipynb b/lessons/variables/mathematical-operators.ipynb new file mode 100644 index 0000000..c7a134c --- /dev/null +++ b/lessons/variables/mathematical-operators.ipynb @@ -0,0 +1,221 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Mathematical Operators \n", + "\n", + "## Prerequisites\n", + "\n", + "- Variables and their data types\n", + "- Printing f-strings\n", + "\n", + "## Learning outcomes\n", + "\n", + "- Develop familiarity with basic mathematical operations in Python\n", + "- Understand how to access some additional, more complex mathematical operations. \n", + "\n", + "## Arithmetic\n", + "\n", + "Python is extremely relevant to numerical computing, in particular, thanks to the presence of the Python library [NumPy](https://numpy.org/). \n", + "Therefore, it is useful to outline some of the mathematical operations that can be natively performed with Python. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Python natively supports some mathematical operations. \n", + "\n", + "| Operation | Mathematical Notation | Pythonic Notation |\n", + "| -------- | ------- | ------- |\n", + "| Addition | $a + b$ | `a + b` |\n", + "| Subtraction | $a - b$ | `a - b` |\n", + "| Multiplication | $a \\times b$ | `a * b` |\n", + "| Division | $a \\div b$ | `a / b` |\n", + "| Exponent | $a ^ b$ | `a ** b` |\n", + "| Modulo | $a \\textrm{ mod } b$ | `a % b` |\n", + "\n", + "The modulo operation may be new to you, you may know it as the remainder from the division of two numbers. \n", + "\n", + "As we saw in the example above, a single line of code may have many mathematical operations. \n", + "In this event, Python will follow the standard order of operations for mathematical operations: you make know this as [BODMAS](https://en.wikipedia.org/wiki/Order_of_operations#Mnemonics)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Example: The Quadratic Formula\n", + "\n", + "The quadratic formula is an expression to solve quadratic equations with the form, \n", + "\n", + "$$\n", + "ax^2 + bx + c = 0,\n", + "$$\n", + "\n", + "where, $x$ is an unknown value that we want to find, and $a$, $b$, and $c$ are fixed parameters. \n", + "The quadratic formula states that the value of $x$ is, \n", + "\n", + "$$\n", + "x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}.\n", + "$$\n", + "\n", + "This becomes relevant in chemistry if we consider the following problem: Formic acid is a weak acid with a dissociation constant $K_a$ of 1.8×10-4. \n", + "The dissociation constant relates the concentration of the H+ ions and the amount of acid dissolve, $N$, by the equation: \n", + "\n", + "$$\n", + "K_a = \\frac{[\\textrm{H}^+]^2}{N - [\\textrm{H}^+]}.\n", + "$$\n", + "\n", + "This equation can be reformulated as a quadratic equation, \n", + "\n", + "$$\n", + "[\\textrm{H}^+]^2 + K_a[\\textrm{H}^+] - K_aN = 0.\n", + "$$\n", + "\n", + "Therefore, we can use the quadratic formula to solve for the concentration of hydrogen ions for a given amount of dissolved acid, where $a = 1$, $b=K_a$ and $c=-K_aN$. \n", + "\n", + "We can write Python code to compute [H+] for 0.1 moles of dissolved acid. \n", + "Don't worry if some of the code specifics below are a bit new, the table below explains each of the operators. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "K_a = 1.8e-4\n", + "N = 0.1\n", + "\n", + "a = 1.\n", + "b = K_a\n", + "c = -K_a * N\n", + "\n", + "H_conc_plus = (-b + (b ** 2 - 4 * a * c) ** (1 / 2)) / (2 * a)\n", + "H_conc_minus = (-b - (b ** 2 - 4 * a * c) ** (1 / 2)) / (2 * a)\n", + "\n", + "print(f'H_conc_plus = {H_conc_plus:.5f} M')\n", + "print(f'H_conc_minus = {H_conc_minus:.5f} M')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Clearly, the variable `H_conc_minus` should be disregarded as it is not possible to have a negative concentration. \n", + "This means that the concentration of [H+] is 0.00415 (to 5 decimal places). " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## More Complex Mathematical Operations\n", + "\n", + "The `numpy` module provides access to a range of advanced mathematical functions. \n", + "Information about all of the functions that the `numpy` module has can be found in the [numpy lesson](LINK TO NUMPY LESSON). \n", + "To access a given function, we must *import* it *from* the module. \n", + "Below, we import the base 10 logarithm function, `log10`. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from numpy import log10" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can then use this with the result from above to compute the pH of the solution. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pH = log10(H_conc_plus)\n", + "print(f'pH = {pH:.2f}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise\n", + "Find the velocity, $v$, of a N2 molecule with a mass, $m$ of 4.6×10-26 kg at a temperature, $T$, of 293 K, given the following equation,\n", + "\n", + "$$\n", + "v = \\sqrt{\\frac{3k_bT}{m}}, \n", + "$$\n", + "\n", + "where, $k_b$ is 1.38×10−23 J/K." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Answer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "k_b = 1.38e-23\n", + "T = 293\n", + "m = 4.6e-26\n", + "\n", + "v = ((3 * k_b * T) / m) ** (1 / 2)\n", + "print(f'velocity = {v:.1f} m/s')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Learning outcomes\n", + "\n", + "- Develop familiarity with basic mathematical operations in Python, including `+`, `-`, `*`, `/`. \n", + "- Understand how to access some additiona, more complex mathematical function using the `numpy` module. \n", + "\n", + "# TODO \n", + "\n", + "- Add more exercises for other operations" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From 96ead16d87ae407dfae977fe4ae8ec447ca1185a Mon Sep 17 00:00:00 2001 From: Alan M Lewis <36488126+alanmlewis@users.noreply.github.com> Date: Wed, 28 May 2025 15:57:50 +0100 Subject: [PATCH 2/7] Update _config.yml to allow debugging exercises Co-authored-by: Andrew McCluskey --- _config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/_config.yml b/_config.yml index f4c73a3..e2e2bc8 100644 --- a/_config.yml +++ b/_config.yml @@ -10,6 +10,7 @@ author: The Python in Chemistry Community only_build_toc_files: true execute: execute_notebooks: force + allow_errors: true launch_buttons: notebook_interface: classic From 4fdaa4b5673d7649d61858711bb5b52e75ad8fc1 Mon Sep 17 00:00:00 2001 From: "Alan M. Lewis" Date: Wed, 28 May 2025 17:03:38 +0100 Subject: [PATCH 3/7] Some standardisation of variables lessons --- _toc.yml | 2 +- ...umPy.ipynb => Introduction_to_NumPy.ipynb} | 0 lessons/loops_functions/For_Loop_Lesson.ipynb | 72 +++++++---- lessons/variables/Conditions.ipynb | 73 +++++------ lessons/variables/Variable_data_types.ipynb | 118 +++++++++++++----- .../variables/mathematical-operators.ipynb | 29 +++-- 6 files changed, 188 insertions(+), 106 deletions(-) rename lessons/common_libs/{Introduction to NumPy.ipynb => Introduction_to_NumPy.ipynb} (100%) diff --git a/_toc.yml b/_toc.yml index 15d8b8c..9376e7d 100644 --- a/_toc.yml +++ b/_toc.yml @@ -28,7 +28,7 @@ parts: sections: - file: lessons/common_libs/python-in-chem_pyplot_basics_SM.ipynb - file: lessons/common_libs/Matplotlib_Documentation.ipynb - - file: lessons/common_libs/Introduction to NumPy.ipynb + - file: lessons/common_libs/Introduction_to_NumPy.ipynb - file: lessons/common_libs/NumPy_axes_operations.ipynb - file: lessons/common_libs/intro_to_pandas.ipynb - file: lessons/advanced_libraries.md diff --git a/lessons/common_libs/Introduction to NumPy.ipynb b/lessons/common_libs/Introduction_to_NumPy.ipynb similarity index 100% rename from lessons/common_libs/Introduction to NumPy.ipynb rename to lessons/common_libs/Introduction_to_NumPy.ipynb diff --git a/lessons/loops_functions/For_Loop_Lesson.ipynb b/lessons/loops_functions/For_Loop_Lesson.ipynb index 655f488..d6960e3 100644 --- a/lessons/loops_functions/For_Loop_Lesson.ipynb +++ b/lessons/loops_functions/For_Loop_Lesson.ipynb @@ -8,6 +8,10 @@ "source": [ "# The `for` loop\n", "\n", + "## Learning Outcomes\n", + "- TODO\n", + "- \n", + "\n", "## Prerequisites:\n", "- Variables\n", "- Comparison\n", @@ -27,11 +31,11 @@ "

One area where you will see a real benefit of using programming in your work is when you need to repeat a task over and over again. For example maybe you need to process the same type of data file many times with different values. This can take a lot of time one by one but Python can really come to your rescue and save you hours. Plus all your lab colleagues will be beating a path to your door to ask for your help. You will soon become the lab data processing guru!

\n", "
\n", "
\n", - " \n", + " \n", "
\n", "
\n", "\n", - "

One of the easiest way to perform this task is to use a 'for' loop

\n", + "

One of the easiest way to perform this task is to use a 'for' loop.

\n", "\n", "

Here is an example:

\n", "\n", @@ -58,7 +62,7 @@ "id": "hwu0INZoK5FO" }, "source": [ - "If you run the cell above, you should see three strings printed despite having only used a single `print()` statement. Let's look at this closer.\n", + "The cell above results in three strings printed despite having only used a single `print()` statement. Let's look at this closer.\n", "\n", "We begin by defining a list of strings:\n", "```python\n", @@ -96,7 +100,9 @@ ">\n", ">gas_list = ['Nitrogen', 'Oxygen', 'Fluorine']\n", ">for gas in gas_list:\n", - "> print(gas)" + "> print(gas)\n", + "\n", + "
" ] }, { @@ -117,25 +123,38 @@ "source": [ "
Task 2: Understanding a Loop \n", "\n", - "In the lab you are making methyl benzoate according using the scheme below. Five scientists repeat the reaction starting with 3 g of benzoic acid and get of 2.5 g, 2.7 g, 3.1 g, 1.6 g and 4 g of product\n", + "In the lab you are making methyl benzoate according using the scheme below. Five scientists repeat the reaction starting with 3 g of benzoic acid and get of 2.5 g, 2.7 g, 3.1 g, 1.6 g and 4 g of product.\n", "\n", "\n", "\n", - "Lets use your understanding of for loops to quickly work out the yields for each person" + "Lets use your understanding of for loops to quickly work out the yields for each person.\n", + "
" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "NameError", + "evalue": "name '_______' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_24665/3197947029.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mproduct_mass_list\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m2.5\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2.7\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3.1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1.6\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mstarting_mass\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m3\u001b[0m \u001b[0;31m# grams\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mtheoretical_yield\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0m_______\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0m_______\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0;36m136\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mproduct_mass\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mproduct_mass_list\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mpercent_yield\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0m_________\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0m___________\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0;36m100\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name '_______' is not defined" + ] + } + ], "source": [ "product_mass_list = [2.5,2.7,3.1,1.6,4]\n", "starting_mass = 3 # grams\n", "theoretical_yield = (_______/_______)*136\n", "for product_mass in product_mass_list:\n", " percent_yield = (_________ / ___________) * 100\n", - " # the print statement uses the f-string syntax to format the output of the calculation - see lesson XX\n", + " # the print statement uses the f-string syntax to format the output of the calculation\n", " print(f\"Percent yield: {percent_yield:.0f}%\")\n" ] }, @@ -151,9 +170,10 @@ ">theoretical_yield = (starting_mass/122)*136\n", ">for product_mass in product_mass_list:\n", "> percent_yield = (product_mass / theoretical_yield) * 100\n", - "> # the print statement uses the f-string syntax to format the output of the calculation - see >lesson XX\n", + "> # the print statement uses the f-string syntax to format the output of the calculation\n", "> print(f\"Percent yield: {percent_yield:.0f}%\")\n", - "```" + ">```\n", + "
" ] }, { @@ -162,7 +182,9 @@ "source": [ "
Task 3: Understanding a Loop \n", "\n", - "You have a series of temperature measurements from your reaction in degrees C and you want to print them out in Kelvin. One of your colleagues writes some code but it doesn't seem to be working. Can you identify the problem and fix the code?" + "You have a series of temperature measurements from your reaction in degrees C and you want to print them out in Kelvin. One of your colleagues writes some code but it doesn't seem to be working. Can you identify the problem and fix the code?\n", + "\n", + "
" ] }, { @@ -192,15 +214,15 @@ ">for temperature_C in temperature_measurements:\n", "> temperature_K = temperature_C + 273.15\n", "> print(f\"Temperature: {temperature_K}°C\")\n", - ">```" + ">```\n", + "\n", + "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "You seem to be really getting the hang ofd these for loops. Well done!\n", - "\n", "When we are talking about for loops more generally we use the following terms:\n", "- **Discrete variable**: a variable changes its value at every iteration of the loop (e.g. `temperature_C` in task 3).\n", "- **Iterator**: a variable containing multiple values, which can be used in a `for` loop (e.g. `temperature_measurements` in the last example). Lists are the most common kind of operator in Python.\n", @@ -208,9 +230,9 @@ "The general syntax of a `for` loop is:\n", "```python\n", "for discrete_variable in iterator:\n", - " . # some\n", - " . # indented\n", - " . # code\n", + " # some\n", + " # indented\n", + " # code\n", "```\n", "\n", "You can write Python code of any length inside a `for` loop as long as you respect its indentation. " @@ -222,7 +244,9 @@ "source": [ "
Task 4: Understanding a Loop \n", "\n", - "Run the code below and answer the following questions to check your understanding" + "Run the code below and answer the following questions to check your understanding\n", + "\n", + "
" ] }, { @@ -254,7 +278,9 @@ "source": [ "
Task 5: Using loops \n", "\n", - "When chemists want to store molecular structures in a computer they can store in an encoded way called SMILES strings. You don't need to understand what these mean but just to know that libraries that can handle chemical structure can read them. The code below will import the RDKit package and print the structure of benzoic acid. The code works by passing the SMILES string for benzoic acid to the function display_molecule that then draws it out. Check out the functions lesson if you want to understand more about functions, but for this lesson all you just need to follow the syntax below" + "When chemists want to store molecular structures in a computer they can store in an encoded way called SMILES strings. You don't need to understand what these mean but just to know that libraries that can handle chemical structure can read them. The code below will import the RDKit package and print the structure of benzoic acid. The code works by passing the SMILES string for benzoic acid to the function display_molecule that then draws it out. Check out the functions lesson if you want to understand more about functions, but for this lesson all you just need to follow the syntax below.\n", + "\n", + "
" ] }, { @@ -289,10 +315,14 @@ "
  • C1CC(CCC1C2=CC=C(C=C2)Cl)C3=C(C4=CC=CC=C4C(=O)C3=O)O\n", "
  • CC1=C2[C@H](C(=O)[C@@]3([C@H](C[C@@H]4[C@]([C@H]3[C@@H]([C@@](C2(C)C)(C[C@@H]1OC(=O)[C@@H]([C@H](C5=CC=CC=C5)NC(=O)C6=CC=CC=C6)O)O)OC(=O)C7=CC=CC=C7)(CO4)OC(=O)C)O)C)OC(=O)C\n", "\n", + " \n", "
  • \n", + "\n", "Using the concepts above write a for loop that will draw the structrue of all 3 molecules. You need to:\n", "- define a list of the smiles strings\n", - "- loop through the list and display each molecule using the display_molecule function" + "- loop through the list and display each molecule using the display_molecule function\n", + "\n", + "
    " ] }, { diff --git a/lessons/variables/Conditions.ipynb b/lessons/variables/Conditions.ipynb index 40aa518..e699d6a 100644 --- a/lessons/variables/Conditions.ipynb +++ b/lessons/variables/Conditions.ipynb @@ -10,46 +10,38 @@ }, { "cell_type": "markdown", - "id": "27111d44-d8ba-4393-bb63-7a1521a4a956", + "id": "63b3ed50-5670-4fcb-9cd4-81e0a50b650e", "metadata": {}, "source": [ - "## **Requirements**" + "## Learning Objectives" ] }, { "cell_type": "markdown", - "id": "98242630-1ee1-4fe6-bd25-d3bd5805c7ee", - "metadata": {}, - "source": [ - "- Variables\n", - "- Mathematical Operations\n", - "- Data types" - ] - }, - { - "cell_type": "markdown", - "id": "63b3ed50-5670-4fcb-9cd4-81e0a50b650e", + "id": "b56ee7b2-cffc-471e-9fd2-bf2b2c437894", "metadata": {}, "source": [ - "## **Learning Objectives**" + "- To understand how in python we can compare objects to each other.\n", + "- To understand how we can use logical statements to perform multiple comparisons or assessments at once.\n", + "- To see how we can build statements and scripts that can do different tasks when we give them different inputs." ] }, { "cell_type": "markdown", - "id": "b56ee7b2-cffc-471e-9fd2-bf2b2c437894", + "id": "27111d44-d8ba-4393-bb63-7a1521a4a956", "metadata": {}, "source": [ - "- To understand how in python we can compare objects to each other.\n", - "- To understand how we can use logical statements to perform multiple comparisons or assessments at once.\n", - "- To see how we can build statements and scripts that can do different tasks when we give them different inputs." + "## Prerequisites" ] }, { "cell_type": "markdown", - "id": "9e1407f3-8962-4a02-9956-ceaa9523df12", + "id": "98242630-1ee1-4fe6-bd25-d3bd5805c7ee", "metadata": {}, "source": [ - "## **Lessons**" + "- Variables\n", + "- Mathematical Operations\n", + "- Data types" ] }, { @@ -57,7 +49,7 @@ "id": "dad9b34b-ec0d-4b52-abd3-07b9efc631f4", "metadata": {}, "source": [ - "### Comparisons in Python" + "## Comparisons in Python" ] }, { @@ -67,7 +59,7 @@ "source": [ "Python has a number of different ways in which it can compare objects, variables or just numbers. These can be very useful both for simple tasks (\"Does H$_2$O have a higher molecular weight than NH$_3$\") and more complex ones (\"How do we know that this peak in an IR spectrum is above the baseline noise?\")\n", "\n", - "Let us start by looking at a few of the [mathematical operators](https://en.wikipedia.org/wiki/Test_Card_F#/media/File:Testcard_F.jpg) (either identical or very similar to how you would write them down on paper) that can be used directly in Python:" + "Let us start by looking at a few of the [mathematical operators](./mathematical-operators.ipynb) (either identical or very similar to how you would write them down on paper) that can be used directly in Python:" ] }, { @@ -138,9 +130,9 @@ "id": "732d5859-56b9-48d6-beff-8ee521d46879", "metadata": {}, "source": [ - "We can see a few things from the above statements: firstly that running a comparison between two numbers in a code block outputs either 'True' if the expression is indeed true, or 'False' if not. Second, both the greater than (\">\") and less than (\"<\") mathematical operations are identical to those used in standard mathematical notation, while the greater than or equal to operation (\"≥\") is written with two characters, ```>=```. Finally, we can see that this works for both numerical [data types](https://en.wikipedia.org/wiki/Test_Card_F#/media/File:Testcard_F.jpg) in Python - integers and floats. \n", + "We can see a few things from the above statements: firstly that running a comparison between two numbers in a code block outputs either 'True' if the expression is indeed true, or 'False' if not. Second, both the greater than (\">\") and less than (\"<\") mathematical operations are identical to those used in standard mathematical notation, while the greater than or equal to operation (\"≥\") is written with two characters, ```>=```. Finally, we can see that this works for both numerical [data types](Variable_data_types.ipynb) in Python - integers and floats. \n", "\n", - "What if we wanted to check if two values were exactly equal? **Be careful!** We know from our understanding of [variables](https://en.wikipedia.org/wiki/Test_Card_F#/media/File:Testcard_F.jpg) that ```=``` is used in python to assign values to variable names, we cannot use it here. Instead:" + "What if we wanted to check if two values were exactly equal? **Be careful!** We know from our understanding of [variables](Variable_data_types.ipynb) that ```=``` is used in python to assign values to variable names, we cannot use it here. Instead:" ] }, { @@ -366,7 +358,7 @@ "id": "0deade2a-b54e-4888-8b22-48f902c82ce4", "metadata": {}, "source": [ - "### Boolean logic operators" + "## Boolean logic operators" ] }, { @@ -579,20 +571,12 @@ "not z > 3 or z != 2" ] }, - { - "cell_type": "markdown", - "id": "c64ae47b-9a30-4e23-a0f1-476b24106163", - "metadata": {}, - "source": [ - "#### **Note for the future: may be worth linking to outside resources on Boolean logic?**" - ] - }, { "cell_type": "markdown", "id": "79597a1c-5dd4-4426-b21e-eb8135a9bfd0", "metadata": {}, "source": [ - "### Conditional Statements" + "## Conditional Statements" ] }, { @@ -727,7 +711,7 @@ "id": "0a5899ad-5b4a-439b-bd47-df83a6d37136", "metadata": {}, "source": [ - "### **Tasks**" + "## **Tasks**" ] }, { @@ -751,12 +735,21 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 1, "id": "81dd9a93-9296-4da8-be41-3f4fc6989d56", "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (420637187.py, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"/tmp/ipykernel_23398/420637187.py\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m atomic_no_of_nitrogen BLANK atomic_no_of_fluorine\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], "source": [ - "# atomic_no_of_nitrogen BLANK atomic_no_of_fluorine" + "atomic_no_of_nitrogen BLANK atomic_no_of_fluorine" ] }, { @@ -802,7 +795,7 @@ "id": "120f98bf-03ef-49b8-8338-6081411d2b10", "metadata": {}, "source": [ - "### **Learning Outcomes**" + "## **Learning Outcomes**" ] }, { @@ -821,7 +814,7 @@ "id": "be1e9adf-0c99-47e1-8fe7-01f461d77e08", "metadata": {}, "source": [ - "### TODO" + "## TODO" ] }, { diff --git a/lessons/variables/Variable_data_types.ipynb b/lessons/variables/Variable_data_types.ipynb index 99b59b1..2b642de 100644 --- a/lessons/variables/Variable_data_types.ipynb +++ b/lessons/variables/Variable_data_types.ipynb @@ -16,15 +16,11 @@ "id": "_iRikrUPUjs3" }, "source": [ - "### Learning Outcomes\n", + "## Learning Outcomes\n", "\n", "* Understand how to print basic outputs in python\n", "* Understand how to identify and verify the type of variable\n", - "* Create and print lists in python\n", - "\n", - "\n", - "\n", - "\n" + "* Create and print lists in python\n" ] }, { @@ -33,7 +29,7 @@ "id": "Kup00O1iVHOG" }, "source": [ - "### Prerequisites\n", + "## Prerequisites\n", "\n", "- Be able to access Google Colab, Jupyter Notebooks or another piece of software that will allow you to interact and practice the code" ] @@ -44,18 +40,11 @@ "id": "IxCxV-mv0Svg" }, "source": [ + "## What is a variable?\n", + "\n", "A variable is a place where some information can be held in the code, and can be used in many different ways within a programme." ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "65Jiw2TX0QQQ" - }, - "outputs": [], - "source": [] - }, { "cell_type": "markdown", "metadata": { @@ -177,7 +166,7 @@ "source": [ "### Strings\n", "\n", - "These store a sequence of characters. You signify what characters are stored by writing quotation marks either side of the characters. These can be double or single quotation marks. It will still work either way. Just be consistent." + "These store a sequence of characters. You signify what characters are stored by writing quotation marks either side of the characters. These can be double or single quotation marks, as long as they are consistent - it will still work either way." ] }, { @@ -210,7 +199,7 @@ "source": [ "#### Integer\n", "\n", - "This in any whole number e.g. 5. If your variable type is an integer you will see the class output will be displayed as 'int'." + "This is any whole number, e.g. 5. If your variable type is an integer you will see the class output will be displayed as 'int'." ] }, { @@ -258,7 +247,7 @@ "source": [ "#### Standard form\n", "\n", - "When writing standard form, as is the case for Avogadro's constant you would use e to show that the number is multipled by 10 to the power of 23." + "When writing standard form, as is the case for Avogadro's constant you would use the letter `e` to show that the number is multipled by 10 to the power of 23." ] }, { @@ -284,7 +273,7 @@ "\n", "You may not use complex numbers when you first start out on your chemistry course, but you will come across them later in maths and potentially when you study crystallography, quantum mechanics and other areas of science.\n", "\n", - "When using complex numbers in python, you cannot use $i$ for imaginary numbers, you must use $j$ instead. In teh example below we have the complex number $3+3i$ which is written as $3+3j$ in the code." + "When using complex numbers in python, you cannot use $i$ for imaginary numbers, you must use $j$ instead. In the example below we have the complex number $3+3i$, which is written as $3+3j$ in the code." ] }, { @@ -306,7 +295,9 @@ "id": "K6aMfYCUAjMn" }, "source": [ - "#### Boolean" + "#### Boolean\n", + "\n", + "Boolean variables are the simplest type of variable - they can be equal to either `True` or `False`, and nothing else." ] }, { @@ -328,49 +319,107 @@ "id": "HFWW4cO9BlLI" }, "source": [ - "#### Lists" + "#### Lists\n", + "\n", + "Lists are collections of variables, separated by commas. These variables do not have to be of the same type." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": { "id": "3C66kNgC4sQf" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['H', 'He', 'Li']\n", + "\n" + ] + } + ], "source": [ - "elements = ['H', 'He']\n", + "elements = ['H', 'He', 'Li']\n", "print(elements)\n", "print(type(elements))" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Individual entries within a list can be accessed by writing the variable name, followed by the index of the entry within the list inside square brackets. Note that Python starts counting at 0, not 1, so the first entry in a list has index 0." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "H\n", + "Li\n" + ] + } + ], + "source": [ + "print(elements[0])\n", + "print(elements[2])" + ] + }, { "cell_type": "markdown", "metadata": { "id": "98-HGTmIBoSl" }, "source": [ - "#### Dictionaries" + "#### Dictionaries\n", + "\n", + "Dictionaries are similar to lists, in that they are a collection of information. However, instead of using numbers to index each entry in a dictionary, we use \"keys\" instead, which are usually strings. In the example below the names of the elements are the keys. Using dictionaries usually leads to more human readable code." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": { "id": "lAOQrm4LE24D" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'Hydrogen': 1.008, 'Helium': 4.002602, 'Lithium': 6.941}\n", + "1.008\n" + ] + } + ], "source": [ "ram = {\n", " \"Hydrogen\": 1.008,\n", " \"Helium\": 4.002602,\n", " \"Lithium\": 6.941\n", - "}" + "}\n", + "\n", + "print(ram)\n", + "print(ram['Hydrogen'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise** Can you work out what the data dictionary below is describing?" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": { "id": "EbJjHF7fD0Ea" }, @@ -392,10 +441,17 @@ "source": [ "### TO-DO List\n", "\n", - "Add in f-strings - should this be as a separate page?\n", + "Add in an introduction to f-strings.\n", "\n", "Add in some more worked examples\n" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/lessons/variables/mathematical-operators.ipynb b/lessons/variables/mathematical-operators.ipynb index c7a134c..3a9b251 100644 --- a/lessons/variables/mathematical-operators.ipynb +++ b/lessons/variables/mathematical-operators.ipynb @@ -6,20 +6,19 @@ "source": [ "# Mathematical Operators \n", "\n", - "## Prerequisites\n", - "\n", - "- Variables and their data types\n", - "- Printing f-strings\n", - "\n", "## Learning outcomes\n", "\n", "- Develop familiarity with basic mathematical operations in Python\n", "- Understand how to access some additional, more complex mathematical operations. \n", "\n", + "## Prerequisites\n", + "\n", + "- Variables and their data types\n", + "- Printing f-strings\n", + "\n", "## Arithmetic\n", "\n", - "Python is extremely relevant to numerical computing, in particular, thanks to the presence of the Python library [NumPy](https://numpy.org/). \n", - "Therefore, it is useful to outline some of the mathematical operations that can be natively performed with Python. " + "Python is extremely relevant to numerical computing. Therefore, it is useful to outline some of the mathematical operations that can be natively performed with Python. " ] }, { @@ -37,10 +36,9 @@ "| Exponent | $a ^ b$ | `a ** b` |\n", "| Modulo | $a \\textrm{ mod } b$ | `a % b` |\n", "\n", - "The modulo operation may be new to you, you may know it as the remainder from the division of two numbers. \n", + "The modulo operation may be new to you, you may know it as the remainder from the division of two numbers. Other, more complicated operations are typically also available through Python libraries such as [NumPy](https://numpy.org/), which is introduced below.\n", "\n", - "As we saw in the example above, a single line of code may have many mathematical operations. \n", - "In this event, Python will follow the standard order of operations for mathematical operations: you make know this as [BODMAS](https://en.wikipedia.org/wiki/Order_of_operations#Mnemonics)." + "A single line of code may have many mathematical operations. In this event, Python will follow the standard order of operations for mathematical operations: you might know this as [BODMAS](https://en.wikipedia.org/wiki/Order_of_operations#Mnemonics)." ] }, { @@ -116,9 +114,7 @@ "## More Complex Mathematical Operations\n", "\n", "The `numpy` module provides access to a range of advanced mathematical functions. \n", - "Information about all of the functions that the `numpy` module has can be found in the [numpy lesson](LINK TO NUMPY LESSON). \n", - "To access a given function, we must *import* it *from* the module. \n", - "Below, we import the base 10 logarithm function, `log10`. " + "Information about all of the functions that the `numpy` module has can be found in the [numpy lesson](../common_libs/Introduction_to_NumPy.ipynb). To access a given function, we must `import` it `from` the module. Below, we import the base 10 logarithm function, `log10`. " ] }, { @@ -161,6 +157,13 @@ "where, $k_b$ is 1.38×10−23 J/K." ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, { "cell_type": "markdown", "metadata": {}, From 6a1b6889bfbfae56950a9a16f374bac8cafeb1f6 Mon Sep 17 00:00:00 2001 From: "Alan M. Lewis" Date: Wed, 18 Jun 2025 16:40:55 +0100 Subject: [PATCH 4/7] First go at cleaning For loops --- _config.yml | 4 ++ lessons/loops_functions/For_Loop_Lesson.ipynb | 39 ++++++------ .../PyinC_while_loops_WIP.ipynb | 59 ++++++++++++++---- ...-Overwhelmed with paperwork_1744290627.jpg | Bin 0 -> 260240 bytes lessons/loops_functions/methyl_benzoate.png | Bin 0 -> 19742 bytes .../variables/mathematical-operators.ipynb | 9 ++- 6 files changed, 77 insertions(+), 34 deletions(-) create mode 100644 lessons/loops_functions/StockCake-Overwhelmed with paperwork_1744290627.jpg create mode 100644 lessons/loops_functions/methyl_benzoate.png diff --git a/_config.yml b/_config.yml index e2e2bc8..2a7da1e 100644 --- a/_config.yml +++ b/_config.yml @@ -17,6 +17,10 @@ launch_buttons: binderhub_url: "https://mybinder.org" colab_url: "https://colab.research.google.com" +parse: + myst_enable_extensions: + - html_image + # Define the name of the latex output file for PDF builds latex: latex_documents: diff --git a/lessons/loops_functions/For_Loop_Lesson.ipynb b/lessons/loops_functions/For_Loop_Lesson.ipynb index d6960e3..1c2997c 100644 --- a/lessons/loops_functions/For_Loop_Lesson.ipynb +++ b/lessons/loops_functions/For_Loop_Lesson.ipynb @@ -25,30 +25,32 @@ }, "source": [ "

    The `for` loop

    \n", - "
    \n", - "\n", "\n", "

    One area where you will see a real benefit of using programming in your work is when you need to repeat a task over and over again. For example maybe you need to process the same type of data file many times with different values. This can take a lot of time one by one but Python can really come to your rescue and save you hours. Plus all your lab colleagues will be beating a path to your door to ask for your help. You will soon become the lab data processing guru!

    \n", - "
    \n", - "
    \n", - " \n", - "
    \n", - "
    \n", "\n", - "

    One of the easiest way to perform this task is to use a 'for' loop.

    \n", "\n", - "

    Here is an example:

    \n", + "

    One of the easiest way to perform this task is to use a 'for' loop.

    \n", "\n", - "
    " + "

    Here is an example:

    " ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": { "id": "VSiGQd0PKsxD" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "H2\n", + "H2O\n", + "CH4\n" + ] + } + ], "source": [ "molecules = [\"H2\", \"H2O\", \"CH4\"]\n", "\n", @@ -125,7 +127,7 @@ "\n", "In the lab you are making methyl benzoate according using the scheme below. Five scientists repeat the reaction starting with 3 g of benzoic acid and get of 2.5 g, 2.7 g, 3.1 g, 1.6 g and 4 g of product.\n", "\n", - "\n", + "\"The\n", "\n", "Lets use your understanding of for loops to quickly work out the yields for each person.\n", "" @@ -143,7 +145,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m/tmp/ipykernel_24665/3197947029.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mproduct_mass_list\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m2.5\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2.7\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3.1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1.6\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mstarting_mass\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m3\u001b[0m \u001b[0;31m# grams\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mtheoretical_yield\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0m_______\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0m_______\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0;36m136\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mproduct_mass\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mproduct_mass_list\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mpercent_yield\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0m_________\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0m___________\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0;36m100\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/tmp/ipykernel_18599/3197947029.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mproduct_mass_list\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m2.5\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2.7\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3.1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1.6\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mstarting_mass\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m3\u001b[0m \u001b[0;31m# grams\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mtheoretical_yield\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0m_______\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0m_______\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0;36m136\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mproduct_mass\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mproduct_mass_list\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mpercent_yield\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0m_________\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0m___________\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0;36m100\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mNameError\u001b[0m: name '_______' is not defined" ] } @@ -213,7 +215,7 @@ ">temperature_measurements = [27.3, 28.1, 26.9, 27.5, 28.0]\n", ">for temperature_C in temperature_measurements:\n", "> temperature_K = temperature_C + 273.15\n", - "> print(f\"Temperature: {temperature_K}°C\")\n", + "> print(f\"Temperature: {temperature_K}°C\")\n", ">```\n", "\n", "" @@ -366,12 +368,7 @@ "- Iterating with `range()`\n", "- Using a loop to generate a list (and maybe list comprehension)\n", "- Nesting loops\n", - "\n", - "The format should be the same as before: first a lesson, then a series of exercises.\n", - "\n", - "Any lesson should start with requirements and end with TODO if it isn't finished. Try to always be on the lookout for ties to Chemistry in your lesson and exercises.\n", - "\n", - "Explain potential error messages and consider debugging exercises." + "- Continue statements" ] }, { diff --git a/lessons/loops_functions/PyinC_while_loops_WIP.ipynb b/lessons/loops_functions/PyinC_while_loops_WIP.ipynb index f5092d3..5af8d31 100644 --- a/lessons/loops_functions/PyinC_while_loops_WIP.ipynb +++ b/lessons/loops_functions/PyinC_while_loops_WIP.ipynb @@ -11,19 +11,19 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "## Learning Objectives\n", + "- Understand how to construct and use `while` loops\n", + "- Know how to control iterations in a loop\n", + "\n", "## Prerequisites: \n", - "- logic/boolean \n", - "- comparison\n", + "- boolean variables\n", + "- comparisons\n", "- `if` statements\n", "- `for` loops\n", "\n", - "## Learning Objectives (WIP)\n", - "- Understand how to construct and use `while` loops\n", - "- Know how to control iterations in a loop\n", - "\n", "## The `while` Loop\n", "\n", - "A `while` loop is similar to a `for` loop [LINK] with the main difference being it will continuosly loop while a condition is `True`. As as example see the cell below which prints integers from 1 to 5." + "A `while` loop is similar to a [`for` loop](./For_Loop_Lesson.ipynb), with the main difference being it will continuosly loop while a condition is `True`. As as example see the cell below which prints integers from 1 to 5." ] }, { @@ -67,8 +67,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Exercise 1?\n", - "1. create a `while` loop to print even integers from zero to 10" + "## Exercise 1\n", + "Create a `while` loop to print even integers from zero to 10." ] }, { @@ -82,9 +82,44 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## MORE WIP NOTES \n", - "- wait for input\n", - "- `break` or `continue` \n" + "## Break Clauses\n", + "\n", + "Sometimes we might want to add a second condition under which the code should stop looping. For example, we might be trying to reduce the error in a calculation below some threshold, but we also want to stop the loop if we get to a certain number of iterations stop the calculation running for too long. We can do this using `break`.\n", + "\n", + "For example, the code below\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "327.9185050801573\n", + "2951.2665457214152\n", + "100\n" + ] + } + ], + "source": [ + "x_new = 0.1\n", + "delta_x = 100\n", + "counter = 0\n", + "\n", + "while abs(delta_x) > 1e-3:\n", + " counter += 1\n", + " x_old = x_new\n", + " delta_x = (x_old-1/x_old**9)/10\n", + " x_new = x_old - delta_x\n", + " if counter == 100:\n", + " break\n", + "\n", + "print(delta_x)\n", + "print(x_new)\n", + "print(counter)" ] }, { diff --git a/lessons/loops_functions/StockCake-Overwhelmed with paperwork_1744290627.jpg b/lessons/loops_functions/StockCake-Overwhelmed with paperwork_1744290627.jpg new file mode 100644 index 0000000000000000000000000000000000000000..845308553256869005ea7eb0dea6c3bc814065ce GIT binary patch literal 260240 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Þ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⪼u2&WIF@^#HeyPk#HbI|Np9^|X+;DRVf5tC1 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�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 Wm_gMpAPZqe0+ejFrAz0?XaCvYElC*w literal 0 HcmV?d00001 diff --git a/lessons/loops_functions/methyl_benzoate.png b/lessons/loops_functions/methyl_benzoate.png new file mode 100644 index 0000000000000000000000000000000000000000..0fffd08df01f26e3d2fd96399862e7ac24c838ca GIT binary patch literal 19742 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 Date: Wed, 18 Jun 2025 16:49:43 +0100 Subject: [PATCH 5/7] Add default extensions --- _config.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/_config.yml b/_config.yml index 2a7da1e..5eca94e 100644 --- a/_config.yml +++ b/_config.yml @@ -19,7 +19,16 @@ launch_buttons: parse: myst_enable_extensions: + - colon_fence + # - deflist + - dollarmath + # - html_admonition - html_image + - linkify + # - replacements + # - smartquotes + - substitution + - tasklist # Define the name of the latex output file for PDF builds latex: From 46da318e110ee3cc34a731ff45949d399282587b Mon Sep 17 00:00:00 2001 From: "Alan M. Lewis" Date: Wed, 18 Jun 2025 17:40:11 +0100 Subject: [PATCH 6/7] Cleaned up organising code section (for loops still needs work) --- lessons/loops_functions/For_Loop_Lesson.ipynb | 15 +- .../PyinC_while_loops_WIP.ipynb | 195 +++++++++++--- .../loops_functions/functions_and_scope.ipynb | 241 +++++++++++++----- lessons/variables/Conditions.ipynb | 144 ++++++----- 4 files changed, 420 insertions(+), 175 deletions(-) diff --git a/lessons/loops_functions/For_Loop_Lesson.ipynb b/lessons/loops_functions/For_Loop_Lesson.ipynb index 1c2997c..62c5a92 100644 --- a/lessons/loops_functions/For_Loop_Lesson.ipynb +++ b/lessons/loops_functions/For_Loop_Lesson.ipynb @@ -347,13 +347,14 @@ "source": [ "
    Click here to see a possible solution to Task 5 \n", "\n", - ">```Python\n", - ">molecule_smiles = ['C[C@@H]1CCO[C@@H]2N1C(=O)C3=C(C(=O)C(=CN3C2)C(=O)NCC4=C(C=C(C=C4)F)F)O',\n", - ">'C1CC(CCC1C2=CC=C(C=C2)Cl)C3=C(C4=CC=CC=C4C(=O)C3=O)O',\n", - ">'CC1=C2[C@H](C(=O)[C@@]3([C@H](C[C@@H]4[C@]([C@H]3[C@@H]([C@@](C2(C)C)(C[C@@H]1OC(=O)[C@@H]([C@H]>>>(C5=CC=CC=C5)NC(=O)C6=CC=CC=C6)O)O)OC(=O)C7=CC=CC=C7)(CO4)OC(=O)C)O)C)OC(=O)C']\n", - ">\n", - ">for smiles in molecule_smiles:\n", - "> display_molecule(smiles)\n", + "\n", + "```Python\n", + "molecule_smiles = ['C[C@@H]1CCO[C@@H]2N1C(=O)C3=C(C(=O)C(=CN3C2)C(=O)NCC4=C(C=C(C=C4)F)F)O',\n", + "'C1CC(CCC1C2=CC=C(C=C2)Cl)C3=C(C4=CC=CC=C4C(=O)C3=O)O',\n", + "'CC1=C2[C@H](C(=O)[C@@]3([C@H](C[C@@H]4[C@]([C@H]3[C@@H]([C@@](C2(C)C)(C[C@@H]1OC(=O)[C@@H]([C@H]>>>(C5=CC=CC=C5)NC(=O)C6=CC=CC=C6)O)O)OC(=O)C7=CC=CC=C7)(CO4)OC(=O)C)O)C)OC(=O)C']\n", + "\n", + "for smiles in molecule_smiles:\n", + " display_molecule(smiles)\n", "```" ] }, diff --git a/lessons/loops_functions/PyinC_while_loops_WIP.ipynb b/lessons/loops_functions/PyinC_while_loops_WIP.ipynb index 5af8d31..49db644 100644 --- a/lessons/loops_functions/PyinC_while_loops_WIP.ipynb +++ b/lessons/loops_functions/PyinC_while_loops_WIP.ipynb @@ -67,7 +67,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Exercise 1\n", + "### Exercise\n", "Create a `while` loop to print even integers from zero to 10." ] }, @@ -82,44 +82,37 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Break Clauses\n", - "\n", - "Sometimes we might want to add a second condition under which the code should stop looping. For example, we might be trying to reduce the error in a calculation below some threshold, but we also want to stop the loop if we get to a certain number of iterations stop the calculation running for too long. We can do this using `break`.\n", - "\n", - "For example, the code below\n" + "### Answer" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "327.9185050801573\n", - "2951.2665457214152\n", - "100\n" + "0\n", + "1\n", + "2\n", + "3\n", + "4\n", + "5\n", + "6\n", + "7\n", + "8\n", + "9\n", + "10\n" ] } ], "source": [ - "x_new = 0.1\n", - "delta_x = 100\n", - "counter = 0\n", - "\n", - "while abs(delta_x) > 1e-3:\n", - " counter += 1\n", - " x_old = x_new\n", - " delta_x = (x_old-1/x_old**9)/10\n", - " x_new = x_old - delta_x\n", - " if counter == 100:\n", - " break\n", - "\n", - "print(delta_x)\n", - "print(x_new)\n", - "print(counter)" + "count = 0\n", + "while count < 11:\n", + " print(count)\n", + " count += 1" ] }, { @@ -136,25 +129,109 @@ " print(count)\n", " count -= 2\n", "```\n", - "Bug fix? or explain that condition is never met?" + "\n", + "In this example, `count` is never exactly equal to 0: it counts down from 5, to 3, 1, -1, and continues down. As a result, the condition `count != 0` is never `False`, and the loop will run forever." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Break Clauses\n", + "\n", + "In order to avoid infinite loops, we might want to add a second condition under which the code should stop looping. We can do this using the keyword `break`.\n", + "\n", + "For example, the code below is the same as the code above, but with an additional `break` added, which will be executed once `count < 9`.\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5\n", + "3\n", + "1\n", + "-1\n", + "-3\n", + "-5\n", + "-7\n", + "-9\n" + ] + } + ], "source": [ - "WIP EXAMPLE -- search through file until wanted line is found" + "count = 5\n", + "while count != 0:\n", + " print(count)\n", + " count -= 2\n", + " if count < -9:\n", + " break" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Password Example\n", + "\n", + "The code below pulls together everything we've seen in this lesson. It continuially asks the user for a password, while counting the number of attempts the user has made. If the user either enters the password correctly, or reaches the maximum permitted number of attempts, we use `break` to exit the loop." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Password: test\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Incorrect password. 2 attempts left.\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Password: quit\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Incorrect password. 1 attempts left.\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Password: oh no!\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Too many failed attempts.\n" + ] + } + ], "source": [ - "# Password example??\n", + "# Password example\n", "\n", "MAX_ATTEMPTS = 3\n", "\n", @@ -180,17 +257,59 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## TO DO\n", - "- Useful chemical applications/exercises?\n", - "- `break`, `continue`\n", - "- loop while its condition remains True\n", - "- applications? -> program inputs, chemical?" + "### Exercise\n", + "\n", + "The code above uses two `break` statements, and begins `while True:`. Rewrite the code so that only one `break` statement is used." ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": {}, + "outputs": [], "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Answer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "MAX_ATTEMPTS = 3\n", + "\n", + "correct_password = \"secret123\"\n", + "attempts = 0\n", + "\n", + "while attempts < MAX_ATTEMPTS:\n", + " password = input(\"Password: \").strip()\n", + " attempts += 1\n", + "\n", + " if password == correct_password:\n", + " print(\"Login successful! Welcome!\")\n", + " break\n", + " else:\n", + " if attempts < MAX_ATTEMPTS:\n", + " print(f\"Incorrect password. {MAX_ATTEMPTS - attempts} attempts left.\")\n", + " else:\n", + " print(\"Too many failed attempts.\")\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## TO DO\n", + "- Useful chemical applications/exercises?\n", + "- applications? -> program inputs, chemical?" + ] } ], "metadata": { diff --git a/lessons/loops_functions/functions_and_scope.ipynb b/lessons/loops_functions/functions_and_scope.ipynb index b3be580..b5edeb2 100644 --- a/lessons/loops_functions/functions_and_scope.ipynb +++ b/lessons/loops_functions/functions_and_scope.ipynb @@ -7,7 +7,7 @@ "source": [ "# Functions and Scope\n", "\n", - "## Prerequisites:\n", + "## Prerequisites\n", "\n", "- Variables and Data Types\n", "- Mathematical Operators\n", @@ -15,7 +15,7 @@ "- Loops\n", "- Lists, Dictionaries and Tuples\n", "\n", - "## Learning Objectives:\n", + "## Learning Objectives\n", "\n", "- To learn how to re-run code which will be used often\n", "- To understand the purpose of a function\n", @@ -30,15 +30,25 @@ "id": "1c23b1aa-bffb-4400-867c-042a065273f8", "metadata": {}, "source": [ + "## Functions\n", + "\n", "When running Python scripts, we often use statements to change or read the values of variables. Take the following code, for instance, which looks to add up the values of numbers in a list. Here we can use it to generate the molecular mass of a molecule from a list of atomic masses. The script iterates through the list, and adds each element in it to a running total variable, which at the end of the function contains the total:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "9c60cd53-dab9-4810-9ec2-6bc1914af9a9", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "28\n" + ] + } + ], "source": [ "m1 = [12,12,1,1,1,1]\n", "\n", @@ -63,14 +73,14 @@ "id": "c4c048a9-fa8c-43d2-ae91-48939a2d02c2", "metadata": {}, "source": [ - "## Defining functions:\n", + "## Defining functions\n", "\n", "Functions offer a way for us to package up frequently-run code into an easily callable package, which we can call repeatedly. Let's now wrap the code used to add up the list elements in a function, called `add_up`" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "d03d38ba-1447-4f03-86b0-6c09c09297af", "metadata": {}, "outputs": [], @@ -79,8 +89,7 @@ " total = 0\n", " for atom in list_of_atoms:\n", " total += atom\n", - " return total\n", - "\n" + " return total" ] }, { @@ -97,10 +106,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "4a30ee2e-a69a-4495-b681-cb58d2437655", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "28\n" + ] + } + ], "source": [ "x = add_up(m1)\n", "\n", @@ -112,15 +129,29 @@ "id": "d417fb60-282e-4457-a911-c0f94b50afb4", "metadata": {}, "source": [ - "Here you may be asking why we need the `return total` statement in our code, as we should be able to reference just the variable `total` which is used as our running total during the function's loop. However, if we try that, we will get an error:" + "## Scope\n", + "\n", + "You may be asking why we need the `return total` statement in our code, as we should be able to reference just the variable `total` which is used as our running total during the function's loop. However, if we try that, we will get an error:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "f8a25e4c-cd67-4ae3-a784-a8f7b1078cd2", "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'total' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_47361/4090930406.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0madd_up\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mm1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtotal\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mNameError\u001b[0m: name 'total' is not defined" + ] + } + ], "source": [ "x = add_up(m1)\n", "\n", @@ -132,24 +163,41 @@ "id": "fc7bffb4-2db8-4ab2-9570-49a13975ec9b", "metadata": {}, "source": [ - "Here, Python is telling us that the variable named `total` is not defined. This highlights an important feature of functions in Python. Functions only return what is included on the return line, and any other variables which we define in them which are not returned are lost once the function has finished executing. However, this is not true the other way around. Functions *do* have access to variables which have not been given to them explicitly as arguments. See below that we can initialise a variable `foo` which contains the string `\"bar\"`. We can then also initialise the function `readfoo()` which takes no arguments, but prints the value of the variable `foo`. If we call this function, we can see that the string `bar` is printed to the console. This shows us that even though we did not explicitly pass the variable `foo` to our function, it was able to find the value of the variable `foo` and output it to the console anyway. This is because `foo`, having been declared in our main script, is a *global* variable, in contrast to function variables, which are *local* variables. Remember that if you see an error like this in your code output, it is likely because you have referenced a value which only exists inside the function from outside of it. " + "Here, Python is telling us that the variable named `total` is not defined. This highlights an important feature of functions in Python. Functions only return what is included on the return line, and any other variables which we define in them which are not returned are lost once the function has finished executing. However, this is not true the other way around. Functions *do* have access to variables which have not been given to them explicitly as arguments.\n", + "\n", + "In the code below we can initialise a variable `string` which contains the string `\"benzene\"`. We can then also initialise the function `read_string()` which takes no arguments, but prints the value of the variable `string`. If we call this function, we can see that the string `benzene` is printed to the console." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "b8cdf670-d3e8-4504-8240-4628fd65ec6a", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "benzene\n" + ] + } + ], "source": [ - "foo = \"bar\"\n", - "\n", + "string = \"benzene\"\n", "\n", - "def readfoo():\n", - " print(foo)\n", + "def read_string():\n", + " print(string)\n", " return\n", "\n", - "readfoo() # Note here that even though readfoo takes no arguments, we still need to supply some empty brackets after it when calling it.\n" + "read_string() # Note here that even though readfoo takes no arguments, we still need to supply some empty brackets after it when calling it.\n" + ] + }, + { + "cell_type": "markdown", + "id": "ba898076-1abc-45bc-9198-2d22fc0bbdb3", + "metadata": {}, + "source": [ + "This shows us that even though we did not explicitly pass the variable `string` to our function, it was able to find the value of the variable `string` and output it to the console anyway. This is because `string`, having been declared in our main script, is a *global* variable, in contrast to function variables, which are *local* variables. Remember that if you see an error like this in your code output, it is likely because you have referenced a value which only exists inside the function from outside of it. " ] }, { @@ -157,17 +205,25 @@ "id": "10374f42-0a0f-4457-b3b7-b0f8443d3fd9", "metadata": {}, "source": [ - "## Calling functions:\n", + "## Calling functions\n", "\n", "Now that we've written our `add_up` function, we can use it to add up lots of lists very quickly. Here, we can define a list of lists, then iterate through that to provide a list of their totals. To call the function, all we need to do is write the name of the function, and enclose the list on which we would like it to operate in the brackets:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "6f554c80-ff5a-4db0-b432-ef087b1d5252", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[28, 58, 72]\n" + ] + } + ], "source": [ "many_sets_of_atoms = [\n", " [12,12,1,1,1,1],\n", @@ -287,10 +343,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "47374f25-3d38-4b46-9442-acdff2dddd26", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "def say_hello():\n", " print(\"Hello World\")\n", @@ -306,7 +373,7 @@ "id": "4b8b293d-cc79-40e9-a83c-b8f75454aec2", "metadata": {}, "source": [ - "# Exercises:\n", + "# Exercises\n", "\n", "1. Write a function that takes one argument, `num`, and returns `True` if it is even and `False` if it is odd. \n", "\n", @@ -347,13 +414,14 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "id": "991aba54-f8ab-4431-aba2-36fd3843401a", "metadata": {}, "outputs": [], "source": [ - "# Write a function to look up the atomic mass of an atom based on its chemical symbol. Use the dictionary below to reference the masses. \n", - "# Don't worry about other elements for the time being, you can assume that these are the only elements that matter (pretend you're an organic chemist)\n", + "# The dictionary below can be used to look up an atom's mass from its symbol. \n", + "# Don't worry about other elements for the time being, you can assume that these are the only elements that matter.\n", + "# (pretend you're an organic chemist)\n", "\n", "atom_masses = {\n", " \"C\" : 12,\n", @@ -362,30 +430,10 @@ " \"N\" : 14\n", "}\n", "\n", - "\n", - "\n", - "\n", - "# Now write a function to take a list of atomic numbers, and apply your function above to each element in turn to provide a list of masses\n", - "\n", - "\n", - "\n", - "# Finally, define a function which calls the two above in combination, accepting a list of elemental symbols and returning a mass value\n", - "\n", - "\n", - "\n", - " \n", - "\n", + "# Write a function to take a list of atomic symbols, and return a list of masses.\n", "\n" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "1aa7bd24-0487-4ff2-b961-b2ba35850f11", - "metadata": {}, - "outputs": [], - "source": [] - }, { "cell_type": "markdown", "id": "203732e1-509b-436a-a2b3-fcde5b3d8ab6", @@ -396,19 +444,49 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "id": "e14aea88-2dd4-486a-8a11-ba69db8256c5", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n" + ] + } + ], "source": [ - "# Problem 1:\n", + "# Exercise 1:\n", "\n", "def is_even(num):\n", - " if num%0 == 0:\n", + " if num%2 == 0:\n", " return True\n", " else:\n", " return False\n", - "# Problem 2:\n", + "\n", + "print(is_even(9))\n", + "print(is_even(42))\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "df8b0816-99f6-4f09-8636-96c14fa153e7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2, 4, 6, 8, 10]\n" + ] + } + ], + "source": [ + "# Exercise 2:\n", "\n", "def keep_evens(num_list):\n", " evens = []\n", @@ -417,7 +495,49 @@ " evens.append(num)\n", "\n", " return evens\n", - " " + "\n", + "print(keep_evens([1,2,3,4,5,6,7,8,9,10]))" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "22ba62ed-7af1-42f9-90dd-93cf68f828ca", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[12, 1, 1, 1, 12, 1, 16]\n" + ] + } + ], + "source": [ + "# Exercise 3:\n", + "\n", + "# The dictionary below can be used to look up an atom's mass from its symbol. \n", + "# Don't worry about other elements for the time being, you can assume that these are the only elements that matter.\n", + "# (pretend you're an organic chemist)\n", + "\n", + "atom_masses = {\n", + " \"C\" : 12,\n", + " \"H\" : 1,\n", + " \"O\" : 16,\n", + " \"N\" : 14\n", + "}\n", + "\n", + "# Write a function to take a list of atomic symbols, and return a list of masses.\n", + "\n", + "def get_masses(atoms):\n", + " mass_list = []\n", + " for atom in atoms:\n", + " mass_list.append(atom_masses[atom])\n", + " return mass_list\n", + "\n", + "print(get_masses([\"C\",\"H\",\"H\",\"H\",\"C\",\"H\",\"O\"]))\n", + "\n", + "\n" ] }, { @@ -425,14 +545,11 @@ "id": "26af8885-0ec8-4421-8947-89f371cf350f", "metadata": {}, "source": [ - "TODO:\n", + "## TODO:\n", "\n", "- More relation to chemistry in some of the later examples?\n", "- Discussion of use of *args etc to supply multiple arguments to a function\n", - "- Answer to Q3\n", "- More debugging exercises\n", - "- Discussion of recursion?\n", - "- Defining functions within functions - further discussion of scope\n", "- Default arguments\n", "\n", "Please email theo.tanner@chem.ox.ac.uk with any questions" @@ -463,7 +580,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.5" + "version": "3.10.12" } }, "nbformat": 4, diff --git a/lessons/variables/Conditions.ipynb b/lessons/variables/Conditions.ipynb index e699d6a..3e23c16 100644 --- a/lessons/variables/Conditions.ipynb +++ b/lessons/variables/Conditions.ipynb @@ -64,7 +64,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 5, "id": "de0e669c-1c14-47ad-b12d-5b25c0fdaf35", "metadata": {}, "outputs": [ @@ -74,7 +74,7 @@ "True" ] }, - "execution_count": 27, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -85,7 +85,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 6, "id": "e5d946d4-36d2-4114-bb2f-326975ee0ee5", "metadata": {}, "outputs": [ @@ -95,7 +95,7 @@ "False" ] }, - "execution_count": 28, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -106,7 +106,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 7, "id": "dd5f7b7d-b9c7-411c-bef6-af9154332c9f", "metadata": {}, "outputs": [ @@ -116,7 +116,7 @@ "True" ] }, - "execution_count": 29, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -137,7 +137,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 8, "id": "962ed8f3-bb4e-4826-a348-4d42fb38025e", "metadata": {}, "outputs": [ @@ -147,7 +147,7 @@ "True" ] }, - "execution_count": 30, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -158,7 +158,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 9, "id": "39103a6d-8149-4a1e-9be8-f59f8231d729", "metadata": {}, "outputs": [ @@ -168,7 +168,7 @@ "False" ] }, - "execution_count": 31, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -179,7 +179,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 10, "id": "ff5c56d6-1170-4464-8ce3-23395e43a744", "metadata": {}, "outputs": [ @@ -189,7 +189,7 @@ "True" ] }, - "execution_count": 32, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -210,7 +210,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 11, "id": "2331f446-16b9-4b2a-82ca-c7c90aeaa15c", "metadata": {}, "outputs": [ @@ -220,7 +220,7 @@ "True" ] }, - "execution_count": 33, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -231,7 +231,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 12, "id": "3c29dc42-ae21-4a7f-beff-8c115fb3a7c8", "metadata": {}, "outputs": [ @@ -241,7 +241,7 @@ "False" ] }, - "execution_count": 34, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -252,7 +252,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 13, "id": "be03a6a0-eff3-4135-9258-97c46a00221d", "metadata": {}, "outputs": [ @@ -262,7 +262,7 @@ "False" ] }, - "execution_count": 35, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -273,7 +273,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 14, "id": "a6d6ecf7-38ca-4fc8-998f-9987dbd5a024", "metadata": {}, "outputs": [ @@ -283,7 +283,7 @@ "True" ] }, - "execution_count": 36, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -302,7 +302,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 15, "id": "6ebfdf09-34fa-4919-a6f1-ba1b6fc12e1f", "metadata": {}, "outputs": [ @@ -312,7 +312,7 @@ "False" ] }, - "execution_count": 37, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -325,7 +325,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 16, "id": "462ee079-297b-4e00-bd37-6ff3df21a4af", "metadata": {}, "outputs": [ @@ -335,7 +335,7 @@ "True" ] }, - "execution_count": 38, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -373,7 +373,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 17, "id": "302f094f-766c-47fb-95ae-a89eed39ffac", "metadata": {}, "outputs": [ @@ -383,7 +383,7 @@ "True" ] }, - "execution_count": 39, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -395,7 +395,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 18, "id": "b15d57e0-6260-42a5-94d8-f1e45743a40b", "metadata": {}, "outputs": [ @@ -405,7 +405,7 @@ "False" ] }, - "execution_count": 40, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -426,7 +426,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 19, "id": "f016ee5a-25b4-4547-857f-b10f5c1d48d3", "metadata": {}, "outputs": [ @@ -436,7 +436,7 @@ "True" ] }, - "execution_count": 41, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -447,7 +447,7 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 20, "id": "e97f2cdf-8e79-4eba-b5dc-2cbca8710b8e", "metadata": {}, "outputs": [ @@ -457,7 +457,7 @@ "True" ] }, - "execution_count": 42, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -468,7 +468,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 21, "id": "d14bcff8-6b5f-4055-88bb-e18e3a0cafd0", "metadata": {}, "outputs": [ @@ -478,7 +478,7 @@ "False" ] }, - "execution_count": 43, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -499,7 +499,7 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 22, "id": "87ab9e7d-dc0d-44d5-9f0e-94b79f728f5f", "metadata": {}, "outputs": [ @@ -509,7 +509,7 @@ "True" ] }, - "execution_count": 44, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -530,7 +530,7 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 23, "id": "f30a769e-184f-4d13-aab3-ccd2a91f6470", "metadata": {}, "outputs": [ @@ -540,7 +540,7 @@ "False" ] }, - "execution_count": 45, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -552,7 +552,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 24, "id": "40c9c586-0376-48c5-97cb-279d31c26067", "metadata": {}, "outputs": [ @@ -562,7 +562,7 @@ "True" ] }, - "execution_count": 46, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -599,7 +599,7 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 25, "id": "3761936a-7163-41de-813b-580ce83a8857", "metadata": {}, "outputs": [ @@ -621,7 +621,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 26, "id": "34f11095-cd62-40a6-ad7a-9df4dd7eae14", "metadata": {}, "outputs": [ @@ -652,7 +652,7 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 27, "id": "b66d509c-f888-45a0-ab94-7c8115852979", "metadata": {}, "outputs": [ @@ -676,7 +676,7 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 28, "id": "64bfd426-81a8-44f3-a54e-cd2f9e99687e", "metadata": {}, "outputs": [ @@ -711,7 +711,7 @@ "id": "0a5899ad-5b4a-439b-bd47-df83a6d37136", "metadata": {}, "source": [ - "## **Tasks**" + "### Exercise" ] }, { @@ -719,12 +719,12 @@ "id": "116cf3f9-74fa-46fe-a06c-ee5cec0a4b9b", "metadata": {}, "source": [ - "1. The following commented code needs the correct operator to replace the **BLANK** in the code to output True - what replaces the **BLANK**?" + "The following commented code needs the correct operator to replace the **BLANK** in the code to output True - what replaces the **BLANK**?" ] }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 29, "id": "a827cfbe-7726-4a42-bb38-0468a752b998", "metadata": {}, "outputs": [], @@ -735,7 +735,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 30, "id": "81dd9a93-9296-4da8-be41-3f4fc6989d56", "metadata": {}, "outputs": [ @@ -744,7 +744,7 @@ "evalue": "invalid syntax (420637187.py, line 1)", "output_type": "error", "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"/tmp/ipykernel_23398/420637187.py\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m atomic_no_of_nitrogen BLANK atomic_no_of_fluorine\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + "\u001b[0;36m File \u001b[0;32m\"/tmp/ipykernel_44779/420637187.py\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m atomic_no_of_nitrogen BLANK atomic_no_of_fluorine\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" ] } ], @@ -752,9 +752,17 @@ "atomic_no_of_nitrogen BLANK atomic_no_of_fluorine" ] }, + { + "cell_type": "markdown", + "id": "bcdbba50-4cb5-4556-bc5c-39a16db6113f", + "metadata": {}, + "source": [ + "### Answer" + ] + }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 31, "id": "b3f749e9-674c-428c-8eeb-df549473ebae", "metadata": {}, "outputs": [ @@ -764,7 +772,7 @@ "True" ] }, - "execution_count": 53, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } @@ -774,28 +782,12 @@ "atomic_no_of_nitrogen < atomic_no_of_fluorine" ] }, - { - "cell_type": "markdown", - "id": "5ccf3004-bb13-465f-90b9-a6c871c09f72", - "metadata": {}, - "source": [ - "2. The following code gives an output that doesn't match chemical intuition, can you fix it so that it will output a correct statement?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "768b30a4-d3f7-4abd-97ae-6a27bcfcb9b7", - "metadata": {}, - "outputs": [], - "source": [] - }, { "cell_type": "markdown", "id": "120f98bf-03ef-49b8-8338-6081411d2b10", "metadata": {}, "source": [ - "## **Learning Outcomes**" + "## Learning Outcomes" ] }, { @@ -836,6 +828,22 @@ "metadata": {}, "outputs": [], "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32454202-0869-460c-b3e6-ed6fec5bf114", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "73a9fb7c-8930-4091-89a3-283eda6f41c1", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { From 22481e4234106a6f28cd5fa38f50b49451875312 Mon Sep 17 00:00:00 2001 From: "Alan M. Lewis" Date: Thu, 19 Jun 2025 10:07:52 +0100 Subject: [PATCH 7/7] Clear all outputs --- lessons/loops_functions/For_Loop_Lesson.ipynb | 30 +- .../PyinC_while_loops_WIP.ipynb | 88 +--- .../loops_functions/functions_and_scope.ipynb | 120 +----- lessons/variables/Conditions.ipynb | 378 +++--------------- lessons/variables/Variable_data_types.ipynb | 41 +- 5 files changed, 90 insertions(+), 567 deletions(-) diff --git a/lessons/loops_functions/For_Loop_Lesson.ipynb b/lessons/loops_functions/For_Loop_Lesson.ipynb index 62c5a92..0306d38 100644 --- a/lessons/loops_functions/For_Loop_Lesson.ipynb +++ b/lessons/loops_functions/For_Loop_Lesson.ipynb @@ -36,21 +36,11 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": { "id": "VSiGQd0PKsxD" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "H2\n", - "H2O\n", - "CH4\n" - ] - } - ], + "outputs": [], "source": [ "molecules = [\"H2\", \"H2O\", \"CH4\"]\n", "\n", @@ -135,21 +125,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name '_______' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m/tmp/ipykernel_18599/3197947029.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mproduct_mass_list\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m2.5\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2.7\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3.1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1.6\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mstarting_mass\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m3\u001b[0m \u001b[0;31m# grams\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mtheoretical_yield\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0m_______\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0m_______\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0;36m136\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mproduct_mass\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mproduct_mass_list\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mpercent_yield\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0m_________\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0m___________\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0;36m100\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mNameError\u001b[0m: name '_______' is not defined" - ] - } - ], + "outputs": [], "source": [ "product_mass_list = [2.5,2.7,3.1,1.6,4]\n", "starting_mass = 3 # grams\n", diff --git a/lessons/loops_functions/PyinC_while_loops_WIP.ipynb b/lessons/loops_functions/PyinC_while_loops_WIP.ipynb index 49db644..40512e6 100644 --- a/lessons/loops_functions/PyinC_while_loops_WIP.ipynb +++ b/lessons/loops_functions/PyinC_while_loops_WIP.ipynb @@ -87,27 +87,9 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0\n", - "1\n", - "2\n", - "3\n", - "4\n", - "5\n", - "6\n", - "7\n", - "8\n", - "9\n", - "10\n" - ] - } - ], + "outputs": [], "source": [ "count = 0\n", "while count < 11:\n", @@ -146,24 +128,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "5\n", - "3\n", - "1\n", - "-1\n", - "-3\n", - "-5\n", - "-7\n", - "-9\n" - ] - } - ], + "outputs": [], "source": [ "count = 5\n", "while count != 0:\n", @@ -184,52 +151,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdin", - "output_type": "stream", - "text": [ - "Password: test\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Incorrect password. 2 attempts left.\n" - ] - }, - { - "name": "stdin", - "output_type": "stream", - "text": [ - "Password: quit\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Incorrect password. 1 attempts left.\n" - ] - }, - { - "name": "stdin", - "output_type": "stream", - "text": [ - "Password: oh no!\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Too many failed attempts.\n" - ] - } - ], + "outputs": [], "source": [ "# Password example\n", "\n", diff --git a/lessons/loops_functions/functions_and_scope.ipynb b/lessons/loops_functions/functions_and_scope.ipynb index b5edeb2..ad79c3f 100644 --- a/lessons/loops_functions/functions_and_scope.ipynb +++ b/lessons/loops_functions/functions_and_scope.ipynb @@ -37,18 +37,10 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "9c60cd53-dab9-4810-9ec2-6bc1914af9a9", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "28\n" - ] - } - ], + "outputs": [], "source": [ "m1 = [12,12,1,1,1,1]\n", "\n", @@ -80,7 +72,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "d03d38ba-1447-4f03-86b0-6c09c09297af", "metadata": {}, "outputs": [], @@ -106,18 +98,10 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "4a30ee2e-a69a-4495-b681-cb58d2437655", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "28\n" - ] - } - ], + "outputs": [], "source": [ "x = add_up(m1)\n", "\n", @@ -136,22 +120,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "f8a25e4c-cd67-4ae3-a784-a8f7b1078cd2", "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'total' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m/tmp/ipykernel_47361/4090930406.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0madd_up\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mm1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtotal\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;31mNameError\u001b[0m: name 'total' is not defined" - ] - } - ], + "outputs": [], "source": [ "x = add_up(m1)\n", "\n", @@ -170,18 +142,10 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "b8cdf670-d3e8-4504-8240-4628fd65ec6a", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "benzene\n" - ] - } - ], + "outputs": [], "source": [ "string = \"benzene\"\n", "\n", @@ -212,18 +176,10 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "6f554c80-ff5a-4db0-b432-ef087b1d5252", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[28, 58, 72]\n" - ] - } - ], + "outputs": [], "source": [ "many_sets_of_atoms = [\n", " [12,12,1,1,1,1],\n", @@ -343,21 +299,10 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "47374f25-3d38-4b46-9442-acdff2dddd26", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "def say_hello():\n", " print(\"Hello World\")\n", @@ -414,7 +359,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "id": "991aba54-f8ab-4431-aba2-36fd3843401a", "metadata": {}, "outputs": [], @@ -444,19 +389,10 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "e14aea88-2dd4-486a-8a11-ba69db8256c5", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "False\n", - "True\n" - ] - } - ], + "outputs": [], "source": [ "# Exercise 1:\n", "\n", @@ -473,18 +409,10 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "df8b0816-99f6-4f09-8636-96c14fa153e7", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[2, 4, 6, 8, 10]\n" - ] - } - ], + "outputs": [], "source": [ "# Exercise 2:\n", "\n", @@ -501,18 +429,10 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "id": "22ba62ed-7af1-42f9-90dd-93cf68f828ca", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[12, 1, 1, 1, 12, 1, 16]\n" - ] - } - ], + "outputs": [], "source": [ "# Exercise 3:\n", "\n", diff --git a/lessons/variables/Conditions.ipynb b/lessons/variables/Conditions.ipynb index 3e23c16..748ae87 100644 --- a/lessons/variables/Conditions.ipynb +++ b/lessons/variables/Conditions.ipynb @@ -64,63 +64,30 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "de0e669c-1c14-47ad-b12d-5b25c0fdaf35", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "4 > 2" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "e5d946d4-36d2-4114-bb2f-326975ee0ee5", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "5.1 < 3.6" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "dd5f7b7d-b9c7-411c-bef6-af9154332c9f", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "4 >= 4" ] @@ -137,63 +104,30 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "962ed8f3-bb4e-4826-a348-4d42fb38025e", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "4 == 4" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "39103a6d-8149-4a1e-9be8-f59f8231d729", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "4 != 4" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "ff5c56d6-1170-4464-8ce3-23395e43a744", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "3.1 != 3" ] @@ -210,84 +144,40 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "2331f446-16b9-4b2a-82ca-c7c90aeaa15c", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "\"CH4\" == \"CH4\"" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "3c29dc42-ae21-4a7f-beff-8c115fb3a7c8", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "\"NH3\" == \"H3N\"" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "be03a6a0-eff3-4135-9258-97c46a00221d", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "[2, 3, 5] == [2, 3, 4]" ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "a6d6ecf7-38ca-4fc8-998f-9987dbd5a024", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "[\"helium\", \"neon\", \"argon\"] == [\"helium\", \"neon\", \"argon\"]" ] @@ -302,21 +192,10 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "id": "6ebfdf09-34fa-4919-a6f1-ba1b6fc12e1f", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "x = [\"N\", \"H\", 3] \n", "y = [\"N\", \"H\", 3]\n", @@ -325,21 +204,10 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "id": "462ee079-297b-4e00-bd37-6ff3df21a4af", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "x = y\n", "x is y" @@ -373,21 +241,10 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "id": "302f094f-766c-47fb-95ae-a89eed39ffac", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "z = 2\n", "z < 3 and z > 0.1 " @@ -395,21 +252,10 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "id": "b15d57e0-6260-42a5-94d8-f1e45743a40b", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "z < 3 and z != 2" ] @@ -426,63 +272,30 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "id": "f016ee5a-25b4-4547-857f-b10f5c1d48d3", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "z < 3 or z > 0.1" ] }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "id": "e97f2cdf-8e79-4eba-b5dc-2cbca8710b8e", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "z < 3 or z !=2" ] }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "id": "d14bcff8-6b5f-4055-88bb-e18e3a0cafd0", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "z > 3 or z != 2" ] @@ -499,21 +312,10 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "id": "87ab9e7d-dc0d-44d5-9f0e-94b79f728f5f", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "w = \"tungsten\"\n", "w == \"neon\" or w == \"iron\" or w == \"bismuth\" or w == \"tungsten\"" @@ -530,21 +332,10 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "id": "f30a769e-184f-4d13-aab3-ccd2a91f6470", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "z = 2\n", "not z <= 2" @@ -552,21 +343,10 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "id": "40c9c586-0376-48c5-97cb-279d31c26067", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "not z > 3 or z != 2" ] @@ -599,18 +379,10 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": null, "id": "3761936a-7163-41de-813b-580ce83a8857", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Yes, these are the same formula\n" - ] - } - ], + "outputs": [], "source": [ "x = \"CH4\"\n", "y = \"CH4\"\n", @@ -621,18 +393,10 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": null, "id": "34f11095-cd62-40a6-ad7a-9df4dd7eae14", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The indentation has ended, this code line is always run\n" - ] - } - ], + "outputs": [], "source": [ "x = \"CH4\"\n", "y = \"NH3\"\n", @@ -652,18 +416,10 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": null, "id": "b66d509c-f888-45a0-ab94-7c8115852979", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "This compound is methane\n" - ] - } - ], + "outputs": [], "source": [ "x = \"CH4\"\n", "if x == \"CH4\":\n", @@ -676,18 +432,10 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": null, "id": "64bfd426-81a8-44f3-a54e-cd2f9e99687e", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "This compound is not ammonia\n" - ] - } - ], + "outputs": [], "source": [ "x = \"H2O\"\n", "if x == \"CH4\":\n", @@ -724,7 +472,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": null, "id": "a827cfbe-7726-4a42-bb38-0468a752b998", "metadata": {}, "outputs": [], @@ -735,19 +483,10 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": null, "id": "81dd9a93-9296-4da8-be41-3f4fc6989d56", "metadata": {}, - "outputs": [ - { - "ename": "SyntaxError", - "evalue": "invalid syntax (420637187.py, line 1)", - "output_type": "error", - "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"/tmp/ipykernel_44779/420637187.py\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m atomic_no_of_nitrogen BLANK atomic_no_of_fluorine\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" - ] - } - ], + "outputs": [], "source": [ "atomic_no_of_nitrogen BLANK atomic_no_of_fluorine" ] @@ -762,21 +501,10 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": null, "id": "b3f749e9-674c-428c-8eeb-df549473ebae", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "### ANSWER: <, <= or != all work\n", "atomic_no_of_nitrogen < atomic_no_of_fluorine" diff --git a/lessons/variables/Variable_data_types.ipynb b/lessons/variables/Variable_data_types.ipynb index 2b642de..1c14824 100644 --- a/lessons/variables/Variable_data_types.ipynb +++ b/lessons/variables/Variable_data_types.ipynb @@ -326,20 +326,11 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": { "id": "3C66kNgC4sQf" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['H', 'He', 'Li']\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "elements = ['H', 'He', 'Li']\n", "print(elements)\n", @@ -355,18 +346,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "H\n", - "Li\n" - ] - } - ], + "outputs": [], "source": [ "print(elements[0])\n", "print(elements[2])" @@ -385,20 +367,11 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": { "id": "lAOQrm4LE24D" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'Hydrogen': 1.008, 'Helium': 4.002602, 'Lithium': 6.941}\n", - "1.008\n" - ] - } - ], + "outputs": [], "source": [ "ram = {\n", " \"Hydrogen\": 1.008,\n", @@ -419,7 +392,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": { "id": "EbJjHF7fD0Ea" },