From 921b358c5ca534cd6323082a81c2a44ea28ea287 Mon Sep 17 00:00:00 2001 From: Liam J Berrisford Date: Tue, 12 Aug 2025 13:47:13 +0100 Subject: [PATCH 1/8] fix: Non-consecutive headings --- individual_modules/improve_your_r_code/microbenchmark.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/individual_modules/improve_your_r_code/microbenchmark.ipynb b/individual_modules/improve_your_r_code/microbenchmark.ipynb index 31d3c127..c9aa3833 100644 --- a/individual_modules/improve_your_r_code/microbenchmark.ipynb +++ b/individual_modules/improve_your_r_code/microbenchmark.ipynb @@ -172,7 +172,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Exercise\n", + "## Exercise\n", "Try microbenchmarking one of your own functions." ] } From 0df200cef64bbf3295c96606245177f0a51302b1 Mon Sep 17 00:00:00 2001 From: Liam J Berrisford Date: Tue, 12 Aug 2025 14:06:00 +0100 Subject: [PATCH 2/8] fix: incorrect strikethrough --- .../markdown_with_python/3-Markdown-Fundamentals.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/individual_modules/markdown_with_python/3-Markdown-Fundamentals.md b/individual_modules/markdown_with_python/3-Markdown-Fundamentals.md index 711f6d97..8d8473d7 100644 --- a/individual_modules/markdown_with_python/3-Markdown-Fundamentals.md +++ b/individual_modules/markdown_with_python/3-Markdown-Fundamentals.md @@ -122,7 +122,7 @@ Here are the main text styles: - ***Bold and italic text***: `***Bold and italic text***` - - ~~Strikethrough~~: `~~Strikethrough text~~` + - **Strikethrough**: `~~Strikethrough text~~` These styles help make your writing easier to read. Use them to highlight important points, but keep it simple so your document stays clean and easy to follow. From 458ce997723d8613c3d762db71dfdee1386dcd52 Mon Sep 17 00:00:00 2001 From: Liam J Berrisford Date: Wed, 13 Aug 2025 09:51:40 +0100 Subject: [PATCH 3/8] Fix misc build warnings --- _config.yml | 2 +- _static/multiple_regression_hyperplane.html | 2 +- _static/multiple_regression_hyperplane_2.html | 2 +- ..._advanced_regression_analysis_with_r_.html | 4 +- ..._prereqs_intermediate_version_control.html | 4 +- _static/workshops_network_hpc.html | 2 +- _static/workshops_network_python_ds.html | 2 +- _static/workshops_network_r_ds.html | 2 +- _toc.yml | 14 +- ...the-Document.md => Export-the-Document.md} | 0 ...ther-Knowledge.md => Further-Knowledge.md} | 0 ...> How-to-embed-Python-Code-in-Markdown.md} | 0 ...ndamentals.md => Markdown-Fundamentals.md} | 0 ...-Markdown-Task-1.md => Markdown-Task-1.md} | 0 ...-Markdown-Task-2.md => Markdown-Task-2.md} | 0 ...ground.md => Motivation-and-Background.md} | 0 .../markdown_with_python/ch2_liveOutput.ipynb | 1983 ----------------- .../markdown_with_python/liveOutput.ipynb | 206 ++ .../{ch0_outline.md => outline.md} | 0 19 files changed, 223 insertions(+), 2000 deletions(-) rename individual_modules/markdown_with_python/{6-Export-the-Document.md => Export-the-Document.md} (100%) rename individual_modules/markdown_with_python/{8-Further-Knowledge.md => Further-Knowledge.md} (100%) rename individual_modules/markdown_with_python/{5-How-to-embed-Python-Code-in-Markdown.md => How-to-embed-Python-Code-in-Markdown.md} (100%) rename individual_modules/markdown_with_python/{3-Markdown-Fundamentals.md => Markdown-Fundamentals.md} (100%) rename individual_modules/markdown_with_python/{4-Markdown-Task-1.md => Markdown-Task-1.md} (100%) rename individual_modules/markdown_with_python/{7-Markdown-Task-2.md => Markdown-Task-2.md} (100%) rename individual_modules/markdown_with_python/{2-Motivation-and-Background.md => Motivation-and-Background.md} (100%) delete mode 100644 individual_modules/markdown_with_python/ch2_liveOutput.ipynb create mode 100644 individual_modules/markdown_with_python/liveOutput.ipynb rename individual_modules/markdown_with_python/{ch0_outline.md => outline.md} (100%) diff --git a/_config.yml b/_config.yml index d2e3536d..4207f40f 100644 --- a/_config.yml +++ b/_config.yml @@ -116,4 +116,4 @@ execute: - 'short_courses/r_unit_testing.ipynb' - 'short_courses/r_functions.ipynb' - 'short_courses/r_functions.ipynb' - - 'individual_modules/markdown_with_python/ch2_liveOutput.ipynb' + - 'individual_modules/markdown_with_python/liveOutput.ipynb' diff --git a/_static/multiple_regression_hyperplane.html b/_static/multiple_regression_hyperplane.html index f80e3ff0..f77af395 100644 --- a/_static/multiple_regression_hyperplane.html +++ b/_static/multiple_regression_hyperplane.html @@ -2,6 +2,6 @@
-
+
\ No newline at end of file diff --git a/_static/multiple_regression_hyperplane_2.html b/_static/multiple_regression_hyperplane_2.html index 27f5a15e..fe9bf32e 100644 --- a/_static/multiple_regression_hyperplane_2.html +++ b/_static/multiple_regression_hyperplane_2.html @@ -2,6 +2,6 @@
-
+
\ No newline at end of file diff --git a/_static/workshop_prereqs_advanced_regression_analysis_with_r_.html b/_static/workshop_prereqs_advanced_regression_analysis_with_r_.html index 0d276aff..90610b4e 100644 --- a/_static/workshop_prereqs_advanced_regression_analysis_with_r_.html +++ b/_static/workshop_prereqs_advanced_regression_analysis_with_r_.html @@ -282,8 +282,8 @@

// parsing and collecting nodes and edges from the python - nodes = new vis.DataSet([{"color": "#B0B0B0", "id": "Regression Analysis with R Adapting to Varied Data Types", "label": "Regression Analysis with R Adapting to Varied Data Types", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Regression Analysis with R Adapting to Varied Data Types\nCourse Pre-reqs: Introduction to Regression with R\nSubsequent Courses: Advanced Regression Analysis With R "}, {"color": "#B0B0B0", "id": "Advanced Regression Analysis With R ", "label": "Advanced Regression Analysis With R ", "level": 4, "shape": "dot", "size": 10, "title": "Course Name: Advanced Regression Analysis With R \nCourse Pre-reqs: Regression Analysis with R Adapting to Varied Data Types\nSubsequent Courses: None"}, {"color": "#B0B0B0", "id": "Introduction to R", "label": "Introduction to R", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to R\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to Regression with R"}, {"color": "#B0B0B0", "id": "Introduction to Regression with R", "label": "Introduction to Regression with R", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Regression with R\nCourse Pre-reqs: Introduction to R\nSubsequent Courses: Regression Analysis with R Adapting to Varied Data Types"}]); - edges = new vis.DataSet([{"arrows": "to", "from": "Regression Analysis with R Adapting to Varied Data Types", "to": "Advanced Regression Analysis With R ", "width": 1}, {"arrows": "to", "from": "Introduction to R", "to": "Introduction to Regression with R", "width": 1}, {"arrows": "to", "from": "Introduction to Regression with R", "to": "Regression Analysis with R Adapting to Varied Data Types", "width": 1}]); + nodes = new vis.DataSet([{"color": "#B0B0B0", "id": "Introduction to R", "label": "Introduction to R", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to R\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to Regression with R"}, {"color": "#B0B0B0", "id": "Introduction to Regression with R", "label": "Introduction to Regression with R", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Regression with R\nCourse Pre-reqs: Introduction to R\nSubsequent Courses: Regression Analysis with R Adapting to Varied Data Types"}, {"color": "#B0B0B0", "id": "Regression Analysis with R Adapting to Varied Data Types", "label": "Regression Analysis with R Adapting to Varied Data Types", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Regression Analysis with R Adapting to Varied Data Types\nCourse Pre-reqs: Introduction to Regression with R\nSubsequent Courses: Advanced Regression Analysis With R "}, {"color": "#B0B0B0", "id": "Advanced Regression Analysis With R ", "label": "Advanced Regression Analysis With R ", "level": 4, "shape": "dot", "size": 10, "title": "Course Name: Advanced Regression Analysis With R \nCourse Pre-reqs: Regression Analysis with R Adapting to Varied Data Types\nSubsequent Courses: None"}]); + edges = new vis.DataSet([{"arrows": "to", "from": "Introduction to R", "to": "Introduction to Regression with R", "width": 1}, {"arrows": "to", "from": "Regression Analysis with R Adapting to Varied Data Types", "to": "Advanced Regression Analysis With R ", "width": 1}, {"arrows": "to", "from": "Introduction to Regression with R", "to": "Regression Analysis with R Adapting to Varied Data Types", "width": 1}]); nodeColors = {}; allNodes = nodes.get({ returnType: "Object" }); diff --git a/_static/workshop_prereqs_intermediate_version_control.html b/_static/workshop_prereqs_intermediate_version_control.html index 76de6db0..4f50c7e5 100644 --- a/_static/workshop_prereqs_intermediate_version_control.html +++ b/_static/workshop_prereqs_intermediate_version_control.html @@ -282,8 +282,8 @@

// parsing and collecting nodes and edges from the python - nodes = new vis.DataSet([{"color": "#B0B0B0", "id": "Introduction to Version Control with Git and GitHub", "label": "Introduction to Version Control with Git and GitHub", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Version Control with Git and GitHub\nCourse Pre-reqs: Introduction to Unix\nSubsequent Courses: Intermediate Version Control"}, {"color": "#B0B0B0", "id": "Intermediate Version Control", "label": "Intermediate Version Control", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Intermediate Version Control\nCourse Pre-reqs: Introduction to Version Control with Git and GitHub\nSubsequent Courses: None"}, {"color": "#B0B0B0", "id": "Introduction to Unix", "label": "Introduction to Unix", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Unix\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to Version Control with Git and GitHub"}]); - edges = new vis.DataSet([{"arrows": "to", "from": "Introduction to Version Control with Git and GitHub", "to": "Intermediate Version Control", "width": 1}, {"arrows": "to", "from": "Introduction to Unix", "to": "Introduction to Version Control with Git and GitHub", "width": 1}]); + nodes = new vis.DataSet([{"color": "#B0B0B0", "id": "Introduction to Unix", "label": "Introduction to Unix", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Unix\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to Version Control with Git and GitHub"}, {"color": "#B0B0B0", "id": "Introduction to Version Control with Git and GitHub", "label": "Introduction to Version Control with Git and GitHub", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Version Control with Git and GitHub\nCourse Pre-reqs: Introduction to Unix\nSubsequent Courses: Intermediate Version Control"}, {"color": "#B0B0B0", "id": "Intermediate Version Control", "label": "Intermediate Version Control", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Intermediate Version Control\nCourse Pre-reqs: Introduction to Version Control with Git and GitHub\nSubsequent Courses: None"}]); + edges = new vis.DataSet([{"arrows": "to", "from": "Introduction to Unix", "to": "Introduction to Version Control with Git and GitHub", "width": 1}, {"arrows": "to", "from": "Introduction to Version Control with Git and GitHub", "to": "Intermediate Version Control", "width": 1}]); nodeColors = {}; allNodes = nodes.get({ returnType: "Object" }); diff --git a/_static/workshops_network_hpc.html b/_static/workshops_network_hpc.html index a8d85a26..a33a5c53 100644 --- a/_static/workshops_network_hpc.html +++ b/_static/workshops_network_hpc.html @@ -282,7 +282,7 @@

// parsing and collecting nodes and edges from the python - nodes = new vis.DataSet([{"color": "#4682B4", "id": "Introduction to HPC", "label": "Introduction to HPC", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to HPC\nCourse Pre-reqs: Introduction to Unix\nSubsequent Courses: Parallel Computing"}, {"color": "#4682B4", "id": "Parallel Computing", "label": "Parallel Computing", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Parallel Computing\nCourse Pre-reqs: Introduction to HPC\nSubsequent Courses: None"}, {"color": "#4682B4", "id": "Introduction to Unix", "label": "Introduction to Unix", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Unix\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to HPC, Introduction to Version Control with Git and GitHub"}, {"color": "#4682B4", "id": "Introduction to Version Control with Git and GitHub", "label": "Introduction to Version Control with Git and GitHub", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Version Control with Git and GitHub\nCourse Pre-reqs: Introduction to Unix\nSubsequent Courses: Intermediate Version Control"}, {"color": "#4682B4", "id": "Intermediate Version Control", "label": "Intermediate Version Control", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Intermediate Version Control\nCourse Pre-reqs: Introduction to Version Control with Git and GitHub\nSubsequent Courses: None"}, {"color": "#4682B4", "id": "Introduction to Python", "label": "Introduction to Python", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Python\nCourse Pre-reqs: None\nSubsequent Courses: None"}]); + nodes = new vis.DataSet([{"color": "#FF6347", "id": "Introduction to HPC", "label": "Introduction to HPC", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to HPC\nCourse Pre-reqs: Introduction to Unix\nSubsequent Courses: Parallel Computing"}, {"color": "#FF6347", "id": "Parallel Computing", "label": "Parallel Computing", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Parallel Computing\nCourse Pre-reqs: Introduction to HPC\nSubsequent Courses: None"}, {"color": "#FF6347", "id": "Introduction to Unix", "label": "Introduction to Unix", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Unix\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to HPC, Introduction to Version Control with Git and GitHub"}, {"color": "#FF6347", "id": "Introduction to Version Control with Git and GitHub", "label": "Introduction to Version Control with Git and GitHub", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Version Control with Git and GitHub\nCourse Pre-reqs: Introduction to Unix\nSubsequent Courses: Intermediate Version Control"}, {"color": "#FF6347", "id": "Intermediate Version Control", "label": "Intermediate Version Control", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Intermediate Version Control\nCourse Pre-reqs: Introduction to Version Control with Git and GitHub\nSubsequent Courses: None"}, {"color": "#FF6347", "id": "Introduction to Python", "label": "Introduction to Python", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Python\nCourse Pre-reqs: None\nSubsequent Courses: None"}]); edges = new vis.DataSet([{"arrows": "to", "from": "Introduction to HPC", "to": "Parallel Computing", "width": 1}, {"arrows": "to", "from": "Introduction to Unix", "to": "Introduction to HPC", "width": 1}, {"arrows": "to", "from": "Introduction to Unix", "to": "Introduction to Version Control with Git and GitHub", "width": 1}, {"arrows": "to", "from": "Introduction to Version Control with Git and GitHub", "to": "Intermediate Version Control", "width": 1}]); nodeColors = {}; diff --git a/_static/workshops_network_python_ds.html b/_static/workshops_network_python_ds.html index fb1a00d9..d430b69f 100644 --- a/_static/workshops_network_python_ds.html +++ b/_static/workshops_network_python_ds.html @@ -282,7 +282,7 @@

// parsing and collecting nodes and edges from the python - nodes = new vis.DataSet([{"color": "#FF6347", "id": "Introduction to Version Control with Git and GitHub", "label": "Introduction to Version Control with Git and GitHub", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Version Control with Git and GitHub\nCourse Pre-reqs: Introduction to Unix\nSubsequent Courses: Intermediate Version Control"}, {"color": "#FF6347", "id": "Intermediate Version Control", "label": "Intermediate Version Control", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Intermediate Version Control\nCourse Pre-reqs: Introduction to Version Control with Git and GitHub\nSubsequent Courses: None"}, {"color": "#FF6347", "id": "Introduction to Unix", "label": "Introduction to Unix", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Unix\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to Version Control with Git and GitHub"}, {"color": "#FF6347", "id": "Introduction to Python", "label": "Introduction to Python", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Python\nCourse Pre-reqs: None\nSubsequent Courses: Python for Data Analysis, Using Markdown for Python"}, {"color": "#FF6347", "id": "Python for Data Analysis", "label": "Python for Data Analysis", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Python for Data Analysis\nCourse Pre-reqs: Introduction to Python\nSubsequent Courses: Introduction to Machine Learning"}, {"color": "#FF6347", "id": "Using Markdown for Python", "label": "Using Markdown for Python", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Using Markdown for Python\nCourse Pre-reqs: Introduction to Python\nSubsequent Courses: None"}, {"color": "#FF6347", "id": "Introduction to Machine Learning", "label": "Introduction to Machine Learning", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Machine Learning\nCourse Pre-reqs: Python for Data Analysis\nSubsequent Courses: None"}]); + nodes = new vis.DataSet([{"color": "#FFD700", "id": "Introduction to Version Control with Git and GitHub", "label": "Introduction to Version Control with Git and GitHub", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Version Control with Git and GitHub\nCourse Pre-reqs: Introduction to Unix\nSubsequent Courses: Intermediate Version Control"}, {"color": "#FFD700", "id": "Intermediate Version Control", "label": "Intermediate Version Control", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Intermediate Version Control\nCourse Pre-reqs: Introduction to Version Control with Git and GitHub\nSubsequent Courses: None"}, {"color": "#FFD700", "id": "Introduction to Unix", "label": "Introduction to Unix", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Unix\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to Version Control with Git and GitHub"}, {"color": "#FFD700", "id": "Introduction to Python", "label": "Introduction to Python", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Python\nCourse Pre-reqs: None\nSubsequent Courses: Python for Data Analysis, Using Markdown for Python"}, {"color": "#FFD700", "id": "Python for Data Analysis", "label": "Python for Data Analysis", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Python for Data Analysis\nCourse Pre-reqs: Introduction to Python\nSubsequent Courses: Introduction to Machine Learning"}, {"color": "#FFD700", "id": "Using Markdown for Python", "label": "Using Markdown for Python", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Using Markdown for Python\nCourse Pre-reqs: Introduction to Python\nSubsequent Courses: None"}, {"color": "#FFD700", "id": "Introduction to Machine Learning", "label": "Introduction to Machine Learning", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Machine Learning\nCourse Pre-reqs: Python for Data Analysis\nSubsequent Courses: None"}]); edges = new vis.DataSet([{"arrows": "to", "from": "Introduction to Version Control with Git and GitHub", "to": "Intermediate Version Control", "width": 1}, {"arrows": "to", "from": "Introduction to Unix", "to": "Introduction to Version Control with Git and GitHub", "width": 1}, {"arrows": "to", "from": "Introduction to Python", "to": "Python for Data Analysis", "width": 1}, {"arrows": "to", "from": "Introduction to Python", "to": "Using Markdown for Python", "width": 1}, {"arrows": "to", "from": "Python for Data Analysis", "to": "Introduction to Machine Learning", "width": 1}]); nodeColors = {}; diff --git a/_static/workshops_network_r_ds.html b/_static/workshops_network_r_ds.html index 73fcc6fe..fc6ca45f 100644 --- a/_static/workshops_network_r_ds.html +++ b/_static/workshops_network_r_ds.html @@ -282,7 +282,7 @@

// parsing and collecting nodes and edges from the python - nodes = new vis.DataSet([{"color": "#FFD700", "id": "Introduction to R", "label": "Introduction to R", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to R\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to Regression with R, Working With Data In R, Improve Your R Code, Introduction to Markdown in R"}, {"color": "#FFD700", "id": "Introduction to Regression with R", "label": "Introduction to Regression with R", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Regression with R\nCourse Pre-reqs: Introduction to R\nSubsequent Courses: Regression Analysis with R Adapting to Varied Data Types"}, {"color": "#FFD700", "id": "Working With Data In R", "label": "Working With Data In R", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Working With Data In R\nCourse Pre-reqs: Introduction to R\nSubsequent Courses: None"}, {"color": "#FFD700", "id": "Improve Your R Code", "label": "Improve Your R Code", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Improve Your R Code\nCourse Pre-reqs: Introduction to R\nSubsequent Courses: None"}, {"color": "#FFD700", "id": "Introduction to Markdown in R", "label": "Introduction to Markdown in R", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Markdown in R\nCourse Pre-reqs: Introduction to R\nSubsequent Courses: None"}, {"color": "#FFD700", "id": "Regression Analysis with R Adapting to Varied Data Types", "label": "Regression Analysis with R Adapting to Varied Data Types", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Regression Analysis with R Adapting to Varied Data Types\nCourse Pre-reqs: Introduction to Regression with R\nSubsequent Courses: Advanced Regression Analysis With R "}, {"color": "#FFD700", "id": "Advanced Regression Analysis With R ", "label": "Advanced Regression Analysis With R ", "level": 4, "shape": "dot", "size": 10, "title": "Course Name: Advanced Regression Analysis With R \nCourse Pre-reqs: Regression Analysis with R Adapting to Varied Data Types\nSubsequent Courses: None"}, {"color": "#FFD700", "id": "Introduction to Version Control with Git and GitHub", "label": "Introduction to Version Control with Git and GitHub", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Version Control with Git and GitHub\nCourse Pre-reqs: Introduction to Unix\nSubsequent Courses: Intermediate Version Control"}, {"color": "#FFD700", "id": "Intermediate Version Control", "label": "Intermediate Version Control", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Intermediate Version Control\nCourse Pre-reqs: Introduction to Version Control with Git and GitHub\nSubsequent Courses: None"}, {"color": "#FFD700", "id": "Introduction to Unix", "label": "Introduction to Unix", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Unix\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to Version Control with Git and GitHub"}]); + nodes = new vis.DataSet([{"color": "#4682B4", "id": "Introduction to R", "label": "Introduction to R", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to R\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to Regression with R, Working With Data In R, Improve Your R Code, Introduction to Markdown in R"}, {"color": "#4682B4", "id": "Introduction to Regression with R", "label": "Introduction to Regression with R", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Regression with R\nCourse Pre-reqs: Introduction to R\nSubsequent Courses: Regression Analysis with R Adapting to Varied Data Types"}, {"color": "#4682B4", "id": "Working With Data In R", "label": "Working With Data In R", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Working With Data In R\nCourse Pre-reqs: Introduction to R\nSubsequent Courses: None"}, {"color": "#4682B4", "id": "Improve Your R Code", "label": "Improve Your R Code", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Improve Your R Code\nCourse Pre-reqs: Introduction to R\nSubsequent Courses: None"}, {"color": "#4682B4", "id": "Introduction to Markdown in R", "label": "Introduction to Markdown in R", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Markdown in R\nCourse Pre-reqs: Introduction to R\nSubsequent Courses: None"}, {"color": "#4682B4", "id": "Regression Analysis with R Adapting to Varied Data Types", "label": "Regression Analysis with R Adapting to Varied Data Types", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Regression Analysis with R Adapting to Varied Data Types\nCourse Pre-reqs: Introduction to Regression with R\nSubsequent Courses: Advanced Regression Analysis With R "}, {"color": "#4682B4", "id": "Advanced Regression Analysis With R ", "label": "Advanced Regression Analysis With R ", "level": 4, "shape": "dot", "size": 10, "title": "Course Name: Advanced Regression Analysis With R \nCourse Pre-reqs: Regression Analysis with R Adapting to Varied Data Types\nSubsequent Courses: None"}, {"color": "#4682B4", "id": "Introduction to Version Control with Git and GitHub", "label": "Introduction to Version Control with Git and GitHub", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Version Control with Git and GitHub\nCourse Pre-reqs: Introduction to Unix\nSubsequent Courses: Intermediate Version Control"}, {"color": "#4682B4", "id": "Intermediate Version Control", "label": "Intermediate Version Control", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Intermediate Version Control\nCourse Pre-reqs: Introduction to Version Control with Git and GitHub\nSubsequent Courses: None"}, {"color": "#4682B4", "id": "Introduction to Unix", "label": "Introduction to Unix", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Unix\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to Version Control with Git and GitHub"}]); edges = new vis.DataSet([{"arrows": "to", "from": "Introduction to R", "to": "Introduction to Regression with R", "width": 1}, {"arrows": "to", "from": "Introduction to R", "to": "Working With Data In R", "width": 1}, {"arrows": "to", "from": "Introduction to R", "to": "Improve Your R Code", "width": 1}, {"arrows": "to", "from": "Introduction to R", "to": "Introduction to Markdown in R", "width": 1}, {"arrows": "to", "from": "Introduction to Regression with R", "to": "Regression Analysis with R Adapting to Varied Data Types", "width": 1}, {"arrows": "to", "from": "Regression Analysis with R Adapting to Varied Data Types", "to": "Advanced Regression Analysis With R ", "width": 1}, {"arrows": "to", "from": "Introduction to Version Control with Git and GitHub", "to": "Intermediate Version Control", "width": 1}, {"arrows": "to", "from": "Introduction to Unix", "to": "Introduction to Version Control with Git and GitHub", "width": 1}]); nodeColors = {}; diff --git a/_toc.yml b/_toc.yml index 8568c9ce..f6d639a0 100644 --- a/_toc.yml +++ b/_toc.yml @@ -161,13 +161,13 @@ parts: - file: individual_modules/introduction_to_machine_learning/resources - file: individual_modules/section_landing_pages/markdown_with_python sections: - - file: individual_modules/markdown_with_python/2-Motivation-and-Background - - file: individual_modules/markdown_with_python/3-Markdown-Fundamentals - - file: individual_modules/markdown_with_python/4-Markdown-Task-1 - - file: individual_modules/markdown_with_python/5-How-to-embed-Python-Code-in-Markdown - - file: individual_modules/markdown_with_python/6-Export-the-Document - - file: individual_modules/markdown_with_python/7-Markdown-Task-2 - - file: individual_modules/markdown_with_python/8-Further-Knowledge + - file: individual_modules/markdown_with_python/Motivation-and-Background + - file: individual_modules/markdown_with_python/Markdown-Fundamentals + - file: individual_modules/markdown_with_python/Markdown-Task-1 + - file: individual_modules/markdown_with_python/How-to-embed-Python-Code-in-Markdown + - file: individual_modules/markdown_with_python/Export-the-Document + - file: individual_modules/markdown_with_python/Markdown-Task-2 + - file: individual_modules/markdown_with_python/Further-Knowledge - file: individual_modules/markdown_with_python/resources - file: course_homepages/R sections: diff --git a/individual_modules/markdown_with_python/6-Export-the-Document.md b/individual_modules/markdown_with_python/Export-the-Document.md similarity index 100% rename from individual_modules/markdown_with_python/6-Export-the-Document.md rename to individual_modules/markdown_with_python/Export-the-Document.md diff --git a/individual_modules/markdown_with_python/8-Further-Knowledge.md b/individual_modules/markdown_with_python/Further-Knowledge.md similarity index 100% rename from individual_modules/markdown_with_python/8-Further-Knowledge.md rename to individual_modules/markdown_with_python/Further-Knowledge.md diff --git a/individual_modules/markdown_with_python/5-How-to-embed-Python-Code-in-Markdown.md b/individual_modules/markdown_with_python/How-to-embed-Python-Code-in-Markdown.md similarity index 100% rename from individual_modules/markdown_with_python/5-How-to-embed-Python-Code-in-Markdown.md rename to individual_modules/markdown_with_python/How-to-embed-Python-Code-in-Markdown.md diff --git a/individual_modules/markdown_with_python/3-Markdown-Fundamentals.md b/individual_modules/markdown_with_python/Markdown-Fundamentals.md similarity index 100% rename from individual_modules/markdown_with_python/3-Markdown-Fundamentals.md rename to individual_modules/markdown_with_python/Markdown-Fundamentals.md diff --git a/individual_modules/markdown_with_python/4-Markdown-Task-1.md b/individual_modules/markdown_with_python/Markdown-Task-1.md similarity index 100% rename from individual_modules/markdown_with_python/4-Markdown-Task-1.md rename to individual_modules/markdown_with_python/Markdown-Task-1.md diff --git a/individual_modules/markdown_with_python/7-Markdown-Task-2.md b/individual_modules/markdown_with_python/Markdown-Task-2.md similarity index 100% rename from individual_modules/markdown_with_python/7-Markdown-Task-2.md rename to individual_modules/markdown_with_python/Markdown-Task-2.md diff --git a/individual_modules/markdown_with_python/2-Motivation-and-Background.md b/individual_modules/markdown_with_python/Motivation-and-Background.md similarity index 100% rename from individual_modules/markdown_with_python/2-Motivation-and-Background.md rename to individual_modules/markdown_with_python/Motivation-and-Background.md diff --git a/individual_modules/markdown_with_python/ch2_liveOutput.ipynb b/individual_modules/markdown_with_python/ch2_liveOutput.ipynb deleted file mode 100644 index 2e5638bf..00000000 --- a/individual_modules/markdown_with_python/ch2_liveOutput.ipynb +++ /dev/null @@ -1,1983 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "240dfb4a-2234-489b-89ed-1d60c07dfe5c", - "metadata": {}, - "source": [ - "# Introduction" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "df768551-afd7-436a-9c60-457f60ffcc9e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "This is my Research Report!\n" - ] - } - ], - "source": [ - "print(\"This is my Research Report!\")" - ] - }, - { - "cell_type": "markdown", - "id": "e3e439fd-c956-4afd-ae0b-a037d3f42297", - "metadata": {}, - "source": [ - "# Methods" - ] - }, - { - "cell_type": "markdown", - "id": "be441b6f-e7de-437d-8e75-e607f7267eaf", - "metadata": {}, - "source": [ - "1. Open JupyterLab\n", - "2. Creade a Jupyter Notebook\n", - "3. Start typing" - ] - }, - { - "cell_type": "markdown", - "id": "5bf438c9-aa9e-4c88-8663-dcc45c79a7d3", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "16fdfc09-84e6-4a5a-9bea-ec24e7378bc7", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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g4waNQrTp0+Xn1OEmePHj5fjkRJReWGQISJFHDhwAHPnzsXGjRvx1FNPYdiwYXJ9y8cff4yoqKg7D+HgwYNyUXCXLl3k68VMi9jdJFpDd8vJycGxY8dgYWGBuLi4h379119/HefPn7/T2mrSpImcxSEibWGQIaIKJwLHK6+8grfeeku2e77//nscPnwYX331Fdzd3VG3bt07j6LQ4+PjI8OLCBxipkUs1r3fuHHjYG5uji1btsi1Mrt27XpoHWK7t5gBWrt2rfxYsYuKiLSFQYaIKtyECRPk7ItoAQm1atWSrSCxcPfChQv/er0ILqKNJNbEnDt3ToYUsVD4bps2bZKtqqVLl6J9+/YYP348hg4dKtfEPIhYR7Nt2zbZ1hLrc/7880+5XoeItIWLfYmoQu3Zswdt27aVi29btWp1z5+J7dOFhYXYsWOH3Il0NxFyRFDJy8tD165d8fTTT2PKlClyO/W1a9fkgmGxW0mEJEFszW7evDl8fX3l+pr7F/uKXVNi5kaszXF2dkanTp1kq6ty5coV+v0goifDIENERESaxdYSERERaRaDDBEREWkWgwwRERFpFoMMERERaRaDDBEREWkWgwwRERFpFoMMERERaRaDDBEREWkWgwwRERFpFoMMERERaRaDDBEREWkWgwwRERFBq/4vsQ3g12ndukIAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "# might have to run: pip install matplotlib in the terminal\n", - "\n", - "# Sample data\n", - "x = [1, 2, 3, 4, 5]\n", - "y = [2, 4, 6, 8, 10]\n", - "\n", - "# Create a line plot\n", - "plt.plot(x, y)\n", - "\n", - "# Add labels and title\n", - "plt.xlabel('X-axis')\n", - "plt.ylabel('Y-axis')\n", - "plt.title('Basic Line Plot')\n", - "\n", - "# Show the plot\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "322eb9dc-5f35-454d-9e71-19ad249f859a", - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.plotly.v1+json": { - "config": { - "plotlyServerURL": "https://plot.ly" - }, - "data": [ - { - "hovertemplate": "Year=%{x}
Sales=%{y}", - "legendgroup": "", - "line": { - "color": "#636efa", - "dash": "solid" - }, - "marker": { - "symbol": "circle" - }, - "mode": "lines+markers", - "name": "", - "orientation": "v", - "showlegend": false, - "type": "scatter", - "x": { - "bdata": "4gfjB+QH5QfmBw==", - "dtype": "i2" - }, - "xaxis": "x", - "y": { - "bdata": "ZACWAMgAtADcAA==", - "dtype": "i2" - }, - "yaxis": "y" - } - ], - "layout": { - "legend": { - "tracegroupgap": 0 - }, - "template": { - "data": { - "bar": [ - { - "error_x": { - "color": "#2a3f5f" - }, - "error_y": { - "color": "#2a3f5f" - }, - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "baxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "type": "carpet" - } - ], - "choropleth": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "choropleth" - } - ], - "contour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "contour" - } - ], - "contourcarpet": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "contourcarpet" - } - ], - "heatmap": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "heatmap" - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "histogram2d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2d" - } - ], - "histogram2dcontour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2dcontour" - } - ], - "mesh3d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "mesh3d" - } - ], - "parcoords": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "parcoords" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ], - "scatter": [ - { - "fillpattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - }, - "type": "scatter" - } - ], - "scatter3d": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter3d" - } - ], - "scattercarpet": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattercarpet" - } - ], - "scattergeo": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergeo" - } - ], - "scattergl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergl" - } - ], - "scattermap": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermap" - } - ], - "scattermapbox": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermapbox" - } - ], - "scatterpolar": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolar" - } - ], - "scatterpolargl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolargl" - } - ], - "scatterternary": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterternary" - } - ], - "surface": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "surface" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#EBF0F8" - }, - "line": { - "color": "white" - } - }, - "header": { - "fill": { - "color": "#C8D4E3" - }, - "line": { - "color": "white" - } - }, - "type": "table" - } - ] - }, - "layout": { - "annotationdefaults": { - "arrowcolor": "#2a3f5f", - "arrowhead": 0, - "arrowwidth": 1 - }, - "autotypenumbers": "strict", - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ], - "sequential": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ] - }, - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#2a3f5f" - }, - "geo": { - "bgcolor": "white", - "lakecolor": "white", - "landcolor": "#E5ECF6", - "showlakes": true, - "showland": true, - "subunitcolor": "white" - }, - "hoverlabel": { - "align": "left" - }, - "hovermode": "closest", - "mapbox": { - "style": "light" - }, - "paper_bgcolor": "white", - "plot_bgcolor": "#E5ECF6", - "polar": { - "angularaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "radialaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "scene": { - "xaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "yaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "zaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - } - }, - "shapedefaults": { - "line": { - "color": "#2a3f5f" - } - }, - "ternary": { - "aaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "baxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "caxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "title": { - "x": 0.05 - }, - "xaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - }, - "yaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - } - } - }, - "title": { - "text": "Sales Over Time" - }, - "xaxis": { - "anchor": "y", - "domain": [ - 0, - 1 - ], - "title": { - "text": "Year" - } - }, - "yaxis": { - "anchor": "x", - "domain": [ - 0, - 1 - ], - "title": { - "text": "Sales" - } - } - } - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAACMgAAAFoCAYAAACo8FWBAAAAAXNSR0IArs4c6QAAIABJREFUeF7s3QeUZFWd+PHfq849XV0dBhDFwLIuBkBxTbCLkkTJQUCCqCRhQTIKgggIuAIKCJJMgKgIoiigiAFR/wICgijioosoSxChY/V07qr/+d33qsPMdFf1va9uhfetczjT01P33fc+t1g529+5N8jn83nhhQACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIBAnQoEBDJ1urI8FgIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggIARIJDhg4AAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBQ1wIEMnW9vDwcAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAIEMnwEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQACBuhYgkKnr5eXhEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBAhk+AwggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAII1LUAgUxdLy8PhwACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIEAgw2cAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAoK4FCGTqenl5OAQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAECGT4DCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAnUtQCBT18vLwyGAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggQyPAZQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEKhrAQKZul5eHg4BBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEECAQIbPAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEBdCxDI1PXy8nAIIIAAAggggAACCCCAAAIIIIAAAggggAAC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" - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import plotly.express as px\n", - "import pandas as pd\n", - "\n", - "# Sample data\n", - "df = pd.DataFrame({\n", - " \"Year\": [2018, 2019, 2020, 2021, 2022],\n", - " \"Sales\": [100, 150, 200, 180, 220]\n", - "})\n", - "\n", - "# Create interactive line plot\n", - "fig = px.line(df, x=\"Year\", y=\"Sales\", title=\"Sales Over Time\", markers=True)\n", - "fig.show()\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "0489633f-4d95-4cf9-9ffc-0846672df1ac", - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "6de39751-c3a8-497f-9e5d-1999c53f1b77", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Requirement already satisfied: plotly in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (6.2.0)\n", - "Requirement already satisfied: pandas in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (2.3.1)\n", - "Requirement already satisfied: narwhals>=1.15.1 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from plotly) (2.0.1)\n", - "Requirement already satisfied: packaging in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from plotly) (25.0)\n", - "Requirement already satisfied: numpy>=1.23.2 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from pandas) (1.26.4)\n", - "Requirement already satisfied: python-dateutil>=2.8.2 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from pandas) (2.9.0.post0)\n", - "Requirement already satisfied: pytz>=2020.1 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from pandas) (2025.2)\n", - "Requirement already satisfied: tzdata>=2022.7 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from pandas) (2025.2)\n", - "Requirement already satisfied: six>=1.5 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from python-dateutil>=2.8.2->pandas) (1.17.0)\n" - ] - } - ], - "source": [ - "!pip install plotly pandas" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "ae1068cb-1ceb-44f9-89fc-5e64a7b38cf5", - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.plotly.v1+json": { - "config": { - "plotlyServerURL": "https://plot.ly" - }, - "data": [ - { - "hovertemplate": "Year=%{x}
Sales=%{y}", - "legendgroup": "", - "line": { - "color": "#636efa", - "dash": "solid" - }, - "marker": { - "symbol": "circle" - }, - "mode": "lines+markers", - "name": "", - "orientation": "v", - "showlegend": false, - "type": "scatter", - "x": { - "bdata": "4gfjB+QH5QfmBw==", - "dtype": "i2" - }, - "xaxis": "x", - "y": { - "bdata": "ZACWAMgAtADcAA==", - "dtype": "i2" - }, - "yaxis": "y" - } - ], - "layout": { - "legend": { - "tracegroupgap": 0 - }, - "template": { - "data": { - "bar": [ - { - "error_x": { - "color": "#2a3f5f" - }, - "error_y": { - "color": "#2a3f5f" - }, - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "baxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "type": "carpet" - } - ], - "choropleth": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "choropleth" - } - ], - "contour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "contour" - } - ], - "contourcarpet": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "contourcarpet" - } - ], - "heatmap": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "heatmap" - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "histogram2d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2d" - } - ], - "histogram2dcontour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2dcontour" - } - ], - "mesh3d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "mesh3d" - } - ], - "parcoords": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "parcoords" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ], - "scatter": [ - { - "fillpattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - }, - "type": "scatter" - } - ], - "scatter3d": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter3d" - } - ], - "scattercarpet": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattercarpet" - } - ], - "scattergeo": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergeo" - } - ], - "scattergl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergl" - } - ], - "scattermap": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermap" - } - ], - "scattermapbox": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermapbox" - } - ], - "scatterpolar": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolar" - } - ], - "scatterpolargl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolargl" - } - ], - "scatterternary": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterternary" - } - ], - "surface": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "surface" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#EBF0F8" - }, - "line": { - "color": "white" - } - }, - "header": { - "fill": { - "color": "#C8D4E3" - }, - "line": { - "color": "white" - } - }, - "type": "table" - } - ] - }, - "layout": { - "annotationdefaults": { - "arrowcolor": "#2a3f5f", - "arrowhead": 0, - "arrowwidth": 1 - }, - "autotypenumbers": "strict", - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ], - "sequential": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ] - }, - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#2a3f5f" - }, - "geo": { - "bgcolor": "white", - "lakecolor": "white", - "landcolor": "#E5ECF6", - "showlakes": true, - "showland": true, - "subunitcolor": "white" - }, - "hoverlabel": { - "align": "left" - }, - "hovermode": "closest", - "mapbox": { - "style": "light" - }, - "paper_bgcolor": "white", - "plot_bgcolor": "#E5ECF6", - "polar": { - "angularaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "radialaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "scene": { - "xaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "yaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "zaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - } - }, - "shapedefaults": { - "line": { - "color": "#2a3f5f" - } - }, - "ternary": { - "aaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "baxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "caxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "title": { - "x": 0.05 - }, - "xaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - }, - "yaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - } - } - }, - "title": { - "text": "Sales Over Time" - }, - "xaxis": { - "anchor": "y", - "domain": [ - 0, - 1 - ], - "title": { - "text": "Year" - } - }, - "yaxis": { - "anchor": "x", - "domain": [ - 0, - 1 - ], - "title": { - "text": "Sales" - } - } - } - } - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import plotly.express as px\n", - "import pandas as pd\n", - "\n", - "# Sample data\n", - "df = pd.DataFrame({\n", - " \"Year\": [2018, 2019, 2020, 2021, 2022],\n", - " \"Sales\": [100, 150, 200, 180, 220]\n", - "})\n", - "\n", - "# Create interactive line plot\n", - "fig = px.line(df, x=\"Year\", y=\"Sales\", title=\"Sales Over Time\", markers=True)\n", - "fig.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "a95fea8f-a39c-4a10-8302-a08beeb31181", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Requirement already satisfied: ipywidgets in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (8.1.7)\n", - "Requirement already satisfied: comm>=0.1.3 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from ipywidgets) (0.2.3)\n", - "Requirement already satisfied: ipython>=6.1.0 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from ipywidgets) (9.4.0)\n", - "Requirement already satisfied: traitlets>=4.3.1 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from ipywidgets) (5.14.3)\n", - "Requirement already satisfied: widgetsnbextension~=4.0.14 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from ipywidgets) (4.0.14)\n", - "Requirement already satisfied: jupyterlab_widgets~=3.0.15 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from ipywidgets) (3.0.15)\n", - "Requirement already satisfied: decorator in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from ipython>=6.1.0->ipywidgets) (5.2.1)\n", - "Requirement already satisfied: ipython-pygments-lexers in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from ipython>=6.1.0->ipywidgets) (1.1.1)\n", - "Requirement already satisfied: jedi>=0.16 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from ipython>=6.1.0->ipywidgets) (0.19.2)\n", - "Requirement already satisfied: matplotlib-inline in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from ipython>=6.1.0->ipywidgets) (0.1.7)\n", - "Requirement already satisfied: pexpect>4.3 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from ipython>=6.1.0->ipywidgets) (4.9.0)\n", - "Requirement already satisfied: prompt_toolkit<3.1.0,>=3.0.41 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from ipython>=6.1.0->ipywidgets) (3.0.51)\n", - "Requirement already satisfied: pygments>=2.4.0 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from ipython>=6.1.0->ipywidgets) (2.19.2)\n", - "Requirement already satisfied: stack_data in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from ipython>=6.1.0->ipywidgets) (0.6.3)\n", - "Requirement already satisfied: typing_extensions>=4.6 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from ipython>=6.1.0->ipywidgets) (4.14.1)\n", - "Requirement already satisfied: wcwidth in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from prompt_toolkit<3.1.0,>=3.0.41->ipython>=6.1.0->ipywidgets) (0.2.13)\n", - "Requirement already satisfied: parso<0.9.0,>=0.8.4 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from jedi>=0.16->ipython>=6.1.0->ipywidgets) (0.8.4)\n", - "Requirement already satisfied: ptyprocess>=0.5 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from pexpect>4.3->ipython>=6.1.0->ipywidgets) (0.7.0)\n", - "Requirement already satisfied: executing>=1.2.0 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from stack_data->ipython>=6.1.0->ipywidgets) (2.2.0)\n", - "Requirement already satisfied: asttokens>=2.1.0 in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from stack_data->ipython>=6.1.0->ipywidgets) (3.0.0)\n", - "Requirement already satisfied: pure-eval in /Users/lb788/miniconda3/envs/CfRR-py311/lib/python3.11/site-packages (from stack_data->ipython>=6.1.0->ipywidgets) (0.2.3)\n" - ] - } - ], - "source": [ - "!pip install ipywidgets" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "0769a722-1a50-449d-9126-c7293af1a62a", - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "9120cef866864dc792e9c93f38a184c4", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "interactive(children=(IntSlider(value=10, description='x_max', max=20, min=1), Output()), _dom_classes=('widge…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import ipywidgets as widgets\n", - "from ipywidgets import interact\n", - "\n", - "# Function to plot data\n", - "def plot_graph(x_max):\n", - " # Generate x values and compute y values\n", - " x = np.linspace(0, x_max, 100)\n", - " y = np.sin(x)\n", - "\n", - " # Create the plot\n", - " plt.plot(x, y, label=f\"sin(x), x_max = {x_max}\")\n", - " plt.xlabel('X')\n", - " plt.ylabel('Y')\n", - " plt.title('Interactive Plot of sin(x)')\n", - " plt.legend()\n", - " plt.grid(True)\n", - " plt.show()\n", - "\n", - "# Create an interactive slider widget for adjusting the x_max value\n", - "interact(plot_graph, x_max=widgets.IntSlider(min=1, max=20, step=1, value=10))\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b30d8410-4569-422a-9f11-597331f6d6dd", - "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.11.13" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/individual_modules/markdown_with_python/liveOutput.ipynb b/individual_modules/markdown_with_python/liveOutput.ipynb new file mode 100644 index 00000000..c28dd177 --- /dev/null +++ b/individual_modules/markdown_with_python/liveOutput.ipynb @@ -0,0 +1,206 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "240dfb4a-2234-489b-89ed-1d60c07dfe5c", + "metadata": {}, + "source": [ + "# Introduction" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "df768551-afd7-436a-9c60-457f60ffcc9e", + "metadata": {}, + "outputs": [], + "source": [ + "print(\"This is my Research Report!\")" + ] + }, + { + "cell_type": "markdown", + "id": "e3e439fd-c956-4afd-ae0b-a037d3f42297", + "metadata": {}, + "source": [ + "# Methods" + ] + }, + { + "cell_type": "markdown", + "id": "be441b6f-e7de-437d-8e75-e607f7267eaf", + "metadata": {}, + "source": [ + "1. Open JupyterLab\n", + "2. Creade a Jupyter Notebook\n", + "3. Start typing" + ] + }, + { + "cell_type": "markdown", + "id": "5bf438c9-aa9e-4c88-8663-dcc45c79a7d3", + "metadata": {}, + "source": [ + "# Results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16fdfc09-84e6-4a5a-9bea-ec24e7378bc7", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "# might have to run: pip install matplotlib in the terminal\n", + "\n", + "# Sample data\n", + "x = [1, 2, 3, 4, 5]\n", + "y = [2, 4, 6, 8, 10]\n", + "\n", + "# Create a line plot\n", + "plt.plot(x, y)\n", + "\n", + "# Add labels and title\n", + "plt.xlabel('X-axis')\n", + "plt.ylabel('Y-axis')\n", + "plt.title('Basic Line Plot')\n", + "\n", + "# Show the plot\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "322eb9dc-5f35-454d-9e71-19ad249f859a", + "metadata": {}, + "outputs": [], + "source": [ + "import plotly.express as px\n", + "import pandas as pd\n", + "\n", + "# Sample data\n", + "df = pd.DataFrame({\n", + " \"Year\": [2018, 2019, 2020, 2021, 2022],\n", + " \"Sales\": [100, 150, 200, 180, 220]\n", + "})\n", + "\n", + "# Create interactive line plot\n", + "fig = px.line(df, x=\"Year\", y=\"Sales\", title=\"Sales Over Time\", markers=True)\n", + "fig.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0489633f-4d95-4cf9-9ffc-0846672df1ac", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6de39751-c3a8-497f-9e5d-1999c53f1b77", + "metadata": {}, + "outputs": [], + "source": [ + "!pip install plotly pandas" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ae1068cb-1ceb-44f9-89fc-5e64a7b38cf5", + "metadata": {}, + "outputs": [], + "source": [ + "import plotly.express as px\n", + "import pandas as pd\n", + "\n", + "# Sample data\n", + "df = pd.DataFrame({\n", + " \"Year\": [2018, 2019, 2020, 2021, 2022],\n", + " \"Sales\": [100, 150, 200, 180, 220]\n", + "})\n", + "\n", + "# Create interactive line plot\n", + "fig = px.line(df, x=\"Year\", y=\"Sales\", title=\"Sales Over Time\", markers=True)\n", + "fig.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a95fea8f-a39c-4a10-8302-a08beeb31181", + "metadata": {}, + "outputs": [], + "source": [ + "!pip install ipywidgets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0769a722-1a50-449d-9126-c7293af1a62a", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import ipywidgets as widgets\n", + "from ipywidgets import interact\n", + "\n", + "# Function to plot data\n", + "def plot_graph(x_max):\n", + " # Generate x values and compute y values\n", + " x = np.linspace(0, x_max, 100)\n", + " y = np.sin(x)\n", + "\n", + " # Create the plot\n", + " plt.plot(x, y, label=f\"sin(x), x_max = {x_max}\")\n", + " plt.xlabel('X')\n", + " plt.ylabel('Y')\n", + " plt.title('Interactive Plot of sin(x)')\n", + " plt.legend()\n", + " plt.grid(True)\n", + " plt.show()\n", + "\n", + "# Create an interactive slider widget for adjusting the x_max value\n", + "interact(plot_graph, x_max=widgets.IntSlider(min=1, max=20, step=1, value=10))\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b30d8410-4569-422a-9f11-597331f6d6dd", + "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.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/individual_modules/markdown_with_python/ch0_outline.md b/individual_modules/markdown_with_python/outline.md similarity index 100% rename from individual_modules/markdown_with_python/ch0_outline.md rename to individual_modules/markdown_with_python/outline.md From 1fefc0d9fb82ce24098ccfca5e1383353d21da87 Mon Sep 17 00:00:00 2001 From: Liam J Berrisford Date: Wed, 13 Aug 2025 10:50:55 +0100 Subject: [PATCH 4/8] Remove incorrect punctionation failing YAML within alt text --- .../markdown_with_python/liveOutput.ipynb | 206 ------------------ .../markdown_with_python/outline.md | 55 ----- short_courses/python_environments.ipynb | 37 ++-- 3 files changed, 23 insertions(+), 275 deletions(-) delete mode 100644 individual_modules/markdown_with_python/liveOutput.ipynb delete mode 100644 individual_modules/markdown_with_python/outline.md diff --git a/individual_modules/markdown_with_python/liveOutput.ipynb b/individual_modules/markdown_with_python/liveOutput.ipynb deleted file mode 100644 index c28dd177..00000000 --- a/individual_modules/markdown_with_python/liveOutput.ipynb +++ /dev/null @@ -1,206 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "240dfb4a-2234-489b-89ed-1d60c07dfe5c", - "metadata": {}, - "source": [ - "# Introduction" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "df768551-afd7-436a-9c60-457f60ffcc9e", - "metadata": {}, - "outputs": [], - "source": [ - "print(\"This is my Research Report!\")" - ] - }, - { - "cell_type": "markdown", - "id": "e3e439fd-c956-4afd-ae0b-a037d3f42297", - "metadata": {}, - "source": [ - "# Methods" - ] - }, - { - "cell_type": "markdown", - "id": "be441b6f-e7de-437d-8e75-e607f7267eaf", - "metadata": {}, - "source": [ - "1. Open JupyterLab\n", - "2. Creade a Jupyter Notebook\n", - "3. Start typing" - ] - }, - { - "cell_type": "markdown", - "id": "5bf438c9-aa9e-4c88-8663-dcc45c79a7d3", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "16fdfc09-84e6-4a5a-9bea-ec24e7378bc7", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "# might have to run: pip install matplotlib in the terminal\n", - "\n", - "# Sample data\n", - "x = [1, 2, 3, 4, 5]\n", - "y = [2, 4, 6, 8, 10]\n", - "\n", - "# Create a line plot\n", - "plt.plot(x, y)\n", - "\n", - "# Add labels and title\n", - "plt.xlabel('X-axis')\n", - "plt.ylabel('Y-axis')\n", - "plt.title('Basic Line Plot')\n", - "\n", - "# Show the plot\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "322eb9dc-5f35-454d-9e71-19ad249f859a", - "metadata": {}, - "outputs": [], - "source": [ - "import plotly.express as px\n", - "import pandas as pd\n", - "\n", - "# Sample data\n", - "df = pd.DataFrame({\n", - " \"Year\": [2018, 2019, 2020, 2021, 2022],\n", - " \"Sales\": [100, 150, 200, 180, 220]\n", - "})\n", - "\n", - "# Create interactive line plot\n", - "fig = px.line(df, x=\"Year\", y=\"Sales\", title=\"Sales Over Time\", markers=True)\n", - "fig.show()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0489633f-4d95-4cf9-9ffc-0846672df1ac", - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6de39751-c3a8-497f-9e5d-1999c53f1b77", - "metadata": {}, - "outputs": [], - "source": [ - "!pip install plotly pandas" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ae1068cb-1ceb-44f9-89fc-5e64a7b38cf5", - "metadata": {}, - "outputs": [], - "source": [ - "import plotly.express as px\n", - "import pandas as pd\n", - "\n", - "# Sample data\n", - "df = pd.DataFrame({\n", - " \"Year\": [2018, 2019, 2020, 2021, 2022],\n", - " \"Sales\": [100, 150, 200, 180, 220]\n", - "})\n", - "\n", - "# Create interactive line plot\n", - "fig = px.line(df, x=\"Year\", y=\"Sales\", title=\"Sales Over Time\", markers=True)\n", - "fig.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a95fea8f-a39c-4a10-8302-a08beeb31181", - "metadata": {}, - "outputs": [], - "source": [ - "!pip install ipywidgets" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0769a722-1a50-449d-9126-c7293af1a62a", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import ipywidgets as widgets\n", - "from ipywidgets import interact\n", - "\n", - "# Function to plot data\n", - "def plot_graph(x_max):\n", - " # Generate x values and compute y values\n", - " x = np.linspace(0, x_max, 100)\n", - " y = np.sin(x)\n", - "\n", - " # Create the plot\n", - " plt.plot(x, y, label=f\"sin(x), x_max = {x_max}\")\n", - " plt.xlabel('X')\n", - " plt.ylabel('Y')\n", - " plt.title('Interactive Plot of sin(x)')\n", - " plt.legend()\n", - " plt.grid(True)\n", - " plt.show()\n", - "\n", - "# Create an interactive slider widget for adjusting the x_max value\n", - "interact(plot_graph, x_max=widgets.IntSlider(min=1, max=20, step=1, value=10))\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b30d8410-4569-422a-9f11-597331f6d6dd", - "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.9.19" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/individual_modules/markdown_with_python/outline.md b/individual_modules/markdown_with_python/outline.md deleted file mode 100644 index afec3034..00000000 --- a/individual_modules/markdown_with_python/outline.md +++ /dev/null @@ -1,55 +0,0 @@ -# Course Outline: Introduction to Markdown with Python - -## 1. Formatting in Markdown - -### 1. Headings - -### 2. Paragraphs & Line Breaks - -### 3. Text Styling - -### 4. Lists -- Unordered Lists (Bullets) -- Ordered Lists (Numbered) - -### 5. Task Lists - -### 6. Blockquotes - -### 7. Code Formatting -- Inline Code -- Code Blocks - -### 8. Tables -- Links -- Images - -### 9. Horizontal Lines - -### 10. Links and Images - -### Summary of Formatting Features - -## Exercise 1 - -## 2. Embedding Python Code in Markdown -- Inline code snippets -- Executable Python code blocks in Jupyter Notebook -- Running Python within Markdown cells - -## Exercise 2 -- Create a structured Markdown document -- Add formatted text and lists -- Embed and execute Python code in Markdown -- Save and export your document - -## 3. Exporting Dynamic Documents -- Exporting documents to different formats (HTML, PDF, etc.) - -## 4. Q&A -- Key takeaways -- Additional resources and documentation -- Ask away! - - - \ No newline at end of file diff --git a/short_courses/python_environments.ipynb b/short_courses/python_environments.ipynb index eee9336e..b36b1fff 100644 --- a/short_courses/python_environments.ipynb +++ b/short_courses/python_environments.ipynb @@ -70,17 +70,19 @@ "\n", "\n", "```{image} figures/virtual_environments/terminal_icon.png\n", - ":alt: A simple, square icon representing a terminal. The icon is dark gray with a light gray border, and features a white \">_\" symbol in the upper left corner, commonly used to denote a command-line interface.\n", + ":alt: Terminal icon dark grey square with white greater underscore symbol\n", ":width: 300px\n", ":align: center\n", "```\n", + "\n", "This should then open a window such as: \n", "\n", "```{image} figures/virtual_environments/macos_terminal.png\n", - ":alt: A screenshot of a macOS Terminal window. The window title is \"lb788 — -zsh — 80x24.\" The terminal displays the last login time and date: \"Last login: Tue Jan 7 09:26:58 on ttys001.\" Below that, the command prompt is shown as \"(base) lb788@F6XP2KY6WJ~ %\".\n", + ":alt: MacOS terminal window showing command prompt\n", ":width: 1000px\n", ":align: center\n", "```\n", + "\n", "Commands can then be typed directly into the terminal and executed by pressing Return. \n", "\n", "#### Verifying Python Installation\n", @@ -103,17 +105,21 @@ "```bash\n", "python example_script.py\n", "```\n", + "\n", "Calling Python from command line with no other arguments will open the [interpreter](https://docs.python.org/3/tutorial/interpreter.html) (indicated by the `>>>` prompt), where python commands can be executed in an interactive manner. This is rarely used as the code written is cleared when the interpreter is exited, which can be done by executing the `exit()` command: \n", "\n", "```bash\n", ">>> exit()\n", "```\n", + "\n", "#### Checking what is currently installed\n", "Python comes with some default packages installed already, and installation of packages is typically managed through PIP (a recursive acronym for \"pip install package\"). We can see what is currently installed system-wide using:\n", + "\n", "```bash\n", "pip list \n", + "```\n", "\n", - "we _could_ install more packages system-wide using pip, but it is better to do so in a virtual environment.\n", + "we could install more packages system-wide using pip, but it is better to do so in a virtual environment.\n", "\n", "#### Creating an environment \n", "\n", @@ -132,7 +138,7 @@ "Your command line should now have a hint that highlights which environment you are currently in. This is key as it will make it easy at a glance to understand which environment you are in. Your command line should now look something like: \n", "\n", "```{image} figures/virtual_environments/venv_terminal_hint.png\n", - ":alt: A screenshot of a macOS Terminal window showing the activation of a virtual environment. The command source virtual_environment_1/bin/activate is executed. After activation, the prompt changes to (virtual_environment_1) lb788@F6XP2KY6WJ~ %, indicating that the virtual environment named \"virtual_environment_1\" is now active.\n", + ":alt: MacOS terminal with virtual environment active showing environment name in prompt\n", ":width: 1000px\n", ":align: center\n", "```\n", @@ -177,7 +183,7 @@ "\n", "### Windows \n", "\n", - "#### Openign the Command Prompt (CMD) or PowerShell \n", + "#### Opening the Command Prompt (CMD) or PowerShell \n", "\n", "On windows, you can open the **Command Prompt** by:\n", "1. Clicking on the **Start** menu (Windows icon).\n", @@ -185,23 +191,23 @@ "3. Clicking on the **Command Prompt** icon.\n", "\n", "```{image} figures/virtual_environments/Command_Prompt.png\n", - ":alt: A screenshot of a Windows Command Prompt terminal. The window displays \"Microsoft Windows [Version 10.0.19045.4651]\" and a copyright notice. The prompt C:\\Users\\lb1132> is visible, indicating the current user and directory. The background is black with white text.\n", - ":width: 500px\n", + ":alt: Windows command prompt window with black background and white text\n", + ":width: 1000px\n", ":align: center\n", "```\n", "\n", "Alternatively, you may use **PowerShell** by typing **PowerShell** in the Start menu and selecting it.\n", "\n", "```{image} figures/virtual_environments/Powershell.png\n", - ":alt: A screenshot of the Windows search results for \"Windows PowerShell\" under the \"System\" category. The result shows a blue icon with a white \">_\" symbol, and the text \"Windows PowerShell\" in white, with \"System\" in gray below it.\n", - ":width: 500px\n", + ":alt: Windows start menu search showing PowerShell icon and text\n", + ":width: 1000px\n", ":align: center\n", "```\n", "\n", "When the Command Prompt is opened, you will see a window such as:\n", "\n", "```{image} figures/virtual_environments/Command_Prompt_Terminal.png\n", - ":alt: A screenshot of the top right section of a GitHub page, showing a dropdown menu open from an icon that resembles a rocket or a spark. The dropdown menu presents two options: \"Repository\" (with a GitHub octocat icon) and \"Open issue\" (with a lightbulb icon).\n", + ":alt: GitHub page showing dropdown menu with repository and open issue options\n", ":width: 1000px\n", ":align: center\n", "```\n", @@ -210,7 +216,7 @@ "\n", "\n", "```{image} figures/virtual_environments/Powershell_terminal.png\n", - ":alt: A screenshot of a Windows PowerShell terminal. The terminal has a dark blue background with white text. It displays \"Windows PowerShell,\" followed by the copyright notice and a prompt to \"Try the new cross-platform PowerShell.\" The command prompt PS C:\\Users\\lb1132> is shown at the bottom.\n", + ":alt: Windows PowerShell terminal with dark blue background and white text\n", ":width: 1000px\n", ":align: center\n", "```\n", @@ -242,8 +248,10 @@ "```\n", "#### Checking what is currently installed\n", "Python comes with some default packages installed already, and installation of packages is typically managed through PIP (a recursive acronym for \"pip install package\"). We can see what is currently installed system-wide using:\n", + "\n", "```bash\n", "pip list \n", + "```\n", "\n", "we _could_ install more packages system-wide using pip, but it is better to do so in a virtual environment.\n", "\n", @@ -292,6 +300,7 @@ "```shell\n", "deactivate\n", ".\\virtual_environment_1\\Scripts\\activate\n", + "```\n", "\n", "#### Installing a Package \n", "\n", @@ -318,7 +327,6 @@ "There are a number of different options available for environmental and dependency management tools. Below are some of the most widely used tools for this task within Python. The following sections act as a set of signposts to the more comprehensive guides to their use on their official websites. \n", "\n", "### venv\n", - "(covered above)\n", "\n", "[venv Tutorial](https://docs.python.org/3/tutorial/venv.html)\n", "\n", @@ -326,8 +334,9 @@ "\n", "```sh\n", "python -m venv .venv\n", - "```\n", "source .venv/bin/activate\n", + "```\n", + "\n", "\n", "### Virtualenv\n", "\n", @@ -427,7 +436,7 @@ "To update the current environment from a `.yml` file (such as if you have changed the dependencies or versions listed):\n", "\n", "```sh\n", - "conva env update --file environment.yml --prune\n", + "conda env update --file environment.yml --prune\n", "```\n", "\n", "To delete the environment:\n", From b74370ce5d02d3aebe3ea14f82e664431a3bea42 Mon Sep 17 00:00:00 2001 From: Liam J Berrisford Date: Wed, 13 Aug 2025 10:55:03 +0100 Subject: [PATCH 5/8] Reshuffle additional python for data analysis content into short courses --- _toc.yml | 2 + .../Python_Virtual_environments.ipynb | 1305 ----------------- .../python_language_features.ipynb | 17 +- .../python_testing.ipynb | 21 +- 4 files changed, 36 insertions(+), 1309 deletions(-) delete mode 100644 individual_modules/python_for_data_analysis/Python_Virtual_environments.ipynb rename individual_modules/python_for_data_analysis/Python_Language_features.ipynb => short_courses/python_language_features.ipynb (99%) rename individual_modules/python_for_data_analysis/Python_Testing.ipynb => short_courses/python_testing.ipynb (99%) diff --git a/_toc.yml b/_toc.yml index f6d639a0..2c759b51 100644 --- a/_toc.yml +++ b/_toc.yml @@ -335,6 +335,8 @@ parts: - file: short_courses/python sections: - file: short_courses/python_environments + - file: short_courses/python_language_features + - file: short_courses/python_testing - file: short_courses/r sections: - file: short_courses/r_environments diff --git a/individual_modules/python_for_data_analysis/Python_Virtual_environments.ipynb b/individual_modules/python_for_data_analysis/Python_Virtual_environments.ipynb deleted file mode 100644 index fc216e62..00000000 --- a/individual_modules/python_for_data_analysis/Python_Virtual_environments.ipynb +++ /dev/null @@ -1,1305 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "source": [ - "# Virtual environments\n", - "\n", - "## Learning Objectives\n", - "- Understand the importance of using virtual environments in Python development\n", - "- Differentiate between various tools for managing virtual environments: `venv`, `Conda`, `Pipenv`, and `Poetry`\n", - "- Create and activate a virtual environment using `venv`\n", - "- Use `Conda` to manage environments and packages.\n", - "- Utilize `Pipenv` and `Poetry` for dependency management and virtual environments\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Why do we need virtual environments?\n", - "\n", - "### Control\n", - "\n", - "Virtual environments give you control over the version of Python and the versions of installed libraries (modules).\n", - "Typically this means you will be using the latest versions of Python and libraries for your latest project.\n", - "\n", - "### Freedom to update\n", - "\n", - "By using virtual environments you are free to update to new versions of libraries for your latest project, without breaking earlier projects.\n", - "\n", - "### Reliable deployment\n", - "\n", - "It is far easier to create reproducible and portable software with virtual environments.\n", - "\n", - "### System Python!\n", - "\n", - "Use of Python is so widespread that some operating systems include Python, for a long time this was Python 2.7 though more recently Python 3 (3.8,3.9) has become a popular default. It is never a good idea to change this configuration, except with the usual system upgrade tools. \n", - "\n", - "## Why not use virtual machines or containers?\n", - "\n", - "These have their own place in development and deployment of software. We are not going to cover them here, except to note the following. \n", - "\n", - "If you find yourself having to do complicated or unusual things with virtual environments, or virtual environments do not provide the facilities or security your software requires, then consider alternatives such as Docker.\n", - "\n", - "Yes, *but*\n", - "\n", - "**I have admin rights so I can install libraries and a new Python version for all users.**\n", - "\n", - "**Just don't!**\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "source": [ - "## venv\n", - "\n", - "Tutorial https://docs.python.org/3/tutorial/venv.html\n", - "\n", - "```sh\n", - "python -m venv .venv\n", - "\n", - "source .venv/bin/activate\n", - "```\n", - "\n", - "Though in practice your IDE, e.g. VS Code will typically activate environments for you.\n", - "\n", - "## Virtualenv\n", - "\n", - "Tutorial: \n", - "\n", - "Virtualenv is a tool that can be used to set up a virtual environment. If it is not already on your machine, you'll need to install it such as by:\n", - "\n", - "```sh\n", - "pip install virtualenv\n", - "```\n", - "\n", - "To create a new environment:\n", - "\n", - "```sh\n", - "virtualenv env_name\n", - "```\n", - "\n", - "To activate and deactivate the environment:\n", - "\n", - "```sh\n", - "source env_name/bin/activate\n", - "deactivate\n", - "```\n", - "\n", - "To install packages into the environment, a great method is to store all dependencies listed in a `requirements.txt` (rather than directly installing them with `pip install package_name`). This is because you can save and share this file alongside your repository, and it allows others to easily see and make a copy of the environment you used for your analysis - and for yourself to reproduce that environment, when you return to your code years later!\n", - "\n", - "An example `requirements.txt` file:\n", - "\n", - "```sh\n", - "jupyter==1.0.0\n", - "pandas==2.2.2\n", - "```\n", - "\n", - "To install the packages from `requirements.txt` into your environment:\n", - "\n", - "```sh\n", - "pip install -r requirements.txt\n", - "```\n", - "\n", - "To update your environment (such as if you to have add a new package to the requirements file):\n", - "\n", - "```sh\n", - "pip install -r requirements.txt --upgrade\n", - "```\n", - "\n", - "To delete your environment, use the command below - but be careful! Do not name your environment with the same name as a folder in your current location. If so, you could accidentally permanently delete that folder rather than your environment...\n", - "\n", - "```sh\n", - "rm -r env_name\n", - "```\n", - "\n", - "## Conda\n", - "\n", - "Tutorial: \n", - "\n", - "Conda is another popular tool for environment management in Python. If not already on your machine, follow these [installation instructions](https://conda.io/projects/conda/en/latest/user-guide/install/index.html) to install conda.\n", - "\n", - "You can save the dependencies needed for your Python environment using an `environment.yml` file. Other people can then build an environment with the same dependencies based on that file. Within this file, you can just list the packages needed, or you can include specific versions (if you want people to use the same environment as you).\n", - "\n", - "Example file:\n", - "\n", - "```sh\n", - "name: shoaib2022\n", - "channels:\n", - " - defaults\n", - "dependencies:\n", - " - matplotlib=3.3.4\n", - " - pytest=7.4.4\n", - " - pip:\n", - " - pytest-xdist==3.6.1\n", - "```\n", - "\n", - "To create environment from the file:\n", - "\n", - "```sh\n", - "conda env create --name env_name --file environment.yml\n", - "```\n", - "\n", - "To activate the environment:\n", - "\n", - "```sh\n", - "conda activate env_name\n", - "```\n", - "\n", - "To see packages in the current environment:\n", - "\n", - "```sh\n", - "conda list\n", - "```\n", - "\n", - "To see the conda environments on your machine:\n", - "\n", - "```sh\n", - "conda env list\n", - "```\n", - "\n", - "To update the current environment from a `.yml` file (such as if you have changed the dependencies or versions listed):\n", - "\n", - "```sh\n", - "conva env update --file environment.yml --prune\n", - "```\n", - "\n", - "To delete the environment:\n", - "\n", - "```sh\n", - "conda remove -n env_name --all\n", - "```\n", - "\n", - "## Pipenv\n", - "\n", - "```sh\n", - "mkdir .venv\n", - "pipenv install numpy\n", - "pipenv shell\n", - "```\n", - "\n", - "## Poetry\n", - "\n", - "https://python-poetry.org/docs/\n", - "\n", - "```sh\n", - "pipx install poetry\n", - "```\n", - "\n", - "https://python-poetry.org/docs/basic-usage/" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [ - "remove-input" - ] - }, - "outputs": [ - { - "data": { - "text/html": [ - "
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": [ - "var questionsqukeMLYgLRMA=[\n", - " {\n", - " \"question\": \"What is one of the main benefits of using virtual environments in Python?\",\n", - " \"type\": \"many_choice\",\n", - " \"answers\": [\n", - " {\n", - " \"answer\": \"Improved performance of the Python interpreter\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"Control over the version of Python and installed libraries\",\n", - " \"correct\": true,\n", - " \"feedback\": \"Correct\"\n", - " },\n", - " {\n", - " \"answer\": \"Automatic code optimization\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"Built-in version control for the code\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " }\n", - " ]\n", - " },\n", - " {\n", - " \"question\": \"Why is it recommended not to modify the sytsem Python installation directly?\",\n", - " \"type\": \"many_choice\",\n", - " \"answers\": [\n", - " {\n", - " \"answer\": \"It is protected by the operating system and cannot be changed\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"Modifying system Python can break system tools that depends on it\",\n", - " \"correct\": true,\n", - " \"feedback\": \"Correct\"\n", - " },\n", - " {\n", - " \"answer\": \"System Python is always the latest version and does not need changes\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"It is automatically updated and does not require manual changes\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " }\n", - " ]\n", - " },\n", - " {\n", - " \"question\": \"Which of the following commands is used to create a virtual environment using venv?\",\n", - " \"type\": \"many_choice\",\n", - " \"answers\": [\n", - " {\n", - " \"answer\": \"python -m venv env\",\n", - " \"correct\": true,\n", - " \"feedback\": \"Correct\"\n", - " },\n", - " {\n", - " \"answer\": \"conda create --name env\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"pipenv install\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"poetry new\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " }\n", - " ]\n", - " }\n", - "];\n", - " // Make a random ID\n", - "function makeid(length) {\n", - " var result = [];\n", - " var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';\n", - " var charactersLength = characters.length;\n", - " for (var i = 0; i < length; i++) {\n", - " result.push(characters.charAt(Math.floor(Math.random() * charactersLength)));\n", - " }\n", - " return result.join('');\n", - "}\n", - "\n", - "// Choose a random subset of an array. Can also be used to shuffle the array\n", - "function getRandomSubarray(arr, size) {\n", - " var shuffled = arr.slice(0), i = arr.length, temp, index;\n", - " while (i--) {\n", - " index = Math.floor((i + 1) * Math.random());\n", - " temp = shuffled[index];\n", - " shuffled[index] = shuffled[i];\n", - " shuffled[i] = temp;\n", - " }\n", - " return shuffled.slice(0, size);\n", - "}\n", - "\n", - "function printResponses(responsesContainer) {\n", - " var responses=JSON.parse(responsesContainer.dataset.responses);\n", - " var stringResponses='IMPORTANT!To preserve this answer sequence for submission, when you have finalized your answers:
  1. Copy the text in this cell below \"Answer String\"
  2. Double click on the cell directly below the Answer String, labeled \"Replace Me\"
  3. Select the whole \"Replace Me\" text
  4. Paste in your answer string and press shift-Enter.
  5. Save the notebook using the save icon or File->Save Notebook menu item



  6. Answer String:
    ';\n", - " console.log(responses);\n", - " responses.forEach((response, index) => {\n", - " if (response) {\n", - " console.log(index + ': ' + response);\n", - " stringResponses+= index + ': ' + response +\"
    \";\n", - " }\n", - " });\n", - " responsesContainer.innerHTML=stringResponses;\n", - "}\n", - "function check_mc() {\n", - " var id = this.id.split('-')[0];\n", - " //var response = this.id.split('-')[1];\n", - " //console.log(response);\n", - " //console.log(\"In check_mc(), id=\"+id);\n", - " //console.log(event.srcElement.id) \n", - " //console.log(event.srcElement.dataset.correct) \n", - " //console.log(event.srcElement.dataset.feedback)\n", - "\n", - " var label = event.srcElement;\n", - " //console.log(label, label.nodeName);\n", - " var depth = 0;\n", - " while ((label.nodeName != \"LABEL\") && (depth < 20)) {\n", - " label = label.parentElement;\n", - " console.log(depth, label);\n", - " depth++;\n", - " }\n", - "\n", - "\n", - "\n", - " var answers = label.parentElement.children;\n", - "\n", - " //console.log(answers);\n", - "\n", - "\n", - " // Split behavior based on multiple choice vs many choice:\n", - " var fb = document.getElementById(\"fb\" + id);\n", - "\n", - "\n", - "\n", - "\n", - " if (fb.dataset.numcorrect == 1) {\n", - " // What follows is for the saved responses stuff\n", - " var outerContainer = fb.parentElement.parentElement;\n", - " var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n", - " if (responsesContainer) {\n", - " //console.log(responsesContainer);\n", - " var response = label.firstChild.innerText;\n", - " if (label.querySelector(\".QuizCode\")){\n", - " response+= label.querySelector(\".QuizCode\").firstChild.innerText;\n", - " }\n", - " console.log(response);\n", - " //console.log(document.getElementById(\"quizWrap\"+id));\n", - " var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n", - " console.log(\"Question \" + qnum);\n", - " //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n", - " var responses=JSON.parse(responsesContainer.dataset.responses);\n", - " console.log(responses);\n", - " responses[qnum]= response;\n", - " responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n", - " printResponses(responsesContainer);\n", - " }\n", - " // End code to preserve responses\n", - " \n", - " for (var i = 0; i < answers.length; i++) {\n", - " var child = answers[i];\n", - " //console.log(child);\n", - " child.className = \"MCButton\";\n", - " }\n", - "\n", - "\n", - "\n", - " if (label.dataset.correct == \"true\") {\n", - " // console.log(\"Correct action\");\n", - " if (\"feedback\" in label.dataset) {\n", - " fb.textContent = jaxify(label.dataset.feedback);\n", - " } else {\n", - " fb.textContent = \"Correct!\";\n", - " }\n", - " label.classList.add(\"correctButton\");\n", - "\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"correct\");\n", - "\n", - " } else {\n", - " if (\"feedback\" in label.dataset) {\n", - " fb.textContent = jaxify(label.dataset.feedback);\n", - " } else {\n", - " fb.textContent = \"Incorrect -- try again.\";\n", - " }\n", - " //console.log(\"Error action\");\n", - " label.classList.add(\"incorrectButton\");\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"incorrect\");\n", - " }\n", - " }\n", - " else {\n", - " var reset = false;\n", - " var feedback;\n", - " if (label.dataset.correct == \"true\") {\n", - " if (\"feedback\" in label.dataset) {\n", - " feedback = jaxify(label.dataset.feedback);\n", - " } else {\n", - " feedback = \"Correct!\";\n", - " }\n", - " if (label.dataset.answered <= 0) {\n", - " if (fb.dataset.answeredcorrect < 0) {\n", - " fb.dataset.answeredcorrect = 1;\n", - " reset = true;\n", - " } else {\n", - " fb.dataset.answeredcorrect++;\n", - " }\n", - " if (reset) {\n", - " for (var i = 0; i < answers.length; i++) {\n", - " var child = answers[i];\n", - " child.className = \"MCButton\";\n", - " child.dataset.answered = 0;\n", - " }\n", - " }\n", - " label.classList.add(\"correctButton\");\n", - " label.dataset.answered = 1;\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"correct\");\n", - "\n", - " }\n", - " } else {\n", - " if (\"feedback\" in label.dataset) {\n", - " feedback = jaxify(label.dataset.feedback);\n", - " } else {\n", - " feedback = \"Incorrect -- try again.\";\n", - " }\n", - " if (fb.dataset.answeredcorrect > 0) {\n", - " fb.dataset.answeredcorrect = -1;\n", - " reset = true;\n", - " } else {\n", - " fb.dataset.answeredcorrect--;\n", - " }\n", - "\n", - " if (reset) {\n", - " for (var i = 0; i < answers.length; i++) {\n", - " var child = answers[i];\n", - " child.className = \"MCButton\";\n", - " child.dataset.answered = 0;\n", - " }\n", - " }\n", - " label.classList.add(\"incorrectButton\");\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"incorrect\");\n", - " }\n", - " // What follows is for the saved responses stuff\n", - " var outerContainer = fb.parentElement.parentElement;\n", - " var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n", - " if (responsesContainer) {\n", - " //console.log(responsesContainer);\n", - " var response = label.firstChild.innerText;\n", - " if (label.querySelector(\".QuizCode\")){\n", - " response+= label.querySelector(\".QuizCode\").firstChild.innerText;\n", - " }\n", - " console.log(response);\n", - " //console.log(document.getElementById(\"quizWrap\"+id));\n", - " var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n", - " console.log(\"Question \" + qnum);\n", - " //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n", - " var responses=JSON.parse(responsesContainer.dataset.responses);\n", - " if (label.dataset.correct == \"true\") {\n", - " if (typeof(responses[qnum]) == \"object\"){\n", - " if (!responses[qnum].includes(response))\n", - " responses[qnum].push(response);\n", - " } else{\n", - " responses[qnum]= [ response ];\n", - " }\n", - " } else {\n", - " responses[qnum]= response;\n", - " }\n", - " console.log(responses);\n", - " responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n", - " printResponses(responsesContainer);\n", - " }\n", - " // End save responses stuff\n", - "\n", - "\n", - "\n", - " var numcorrect = fb.dataset.numcorrect;\n", - " var answeredcorrect = fb.dataset.answeredcorrect;\n", - " if (answeredcorrect >= 0) {\n", - " fb.textContent = feedback + \" [\" + answeredcorrect + \"/\" + numcorrect + \"]\";\n", - " } else {\n", - " fb.textContent = feedback + \" [\" + 0 + \"/\" + numcorrect + \"]\";\n", - " }\n", - "\n", - "\n", - " }\n", - "\n", - " if (typeof MathJax != 'undefined') {\n", - " var version = MathJax.version;\n", - " console.log('MathJax version', version);\n", - " if (version[0] == \"2\") {\n", - " MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n", - " } else if (version[0] == \"3\") {\n", - " MathJax.typeset([fb]);\n", - " }\n", - " } else {\n", - " console.log('MathJax not detected');\n", - " }\n", - "\n", - "}\n", - "\n", - "function make_mc(qa, shuffle_answers, outerqDiv, qDiv, aDiv, id) {\n", - " var shuffled;\n", - " if (shuffle_answers == \"True\") {\n", - " //console.log(shuffle_answers+\" read as true\");\n", - " shuffled = getRandomSubarray(qa.answers, qa.answers.length);\n", - " } else {\n", - " //console.log(shuffle_answers+\" read as false\");\n", - " shuffled = qa.answers;\n", - " }\n", - "\n", - "\n", - " var num_correct = 0;\n", - "\n", - "\n", - "\n", - " shuffled.forEach((item, index, ans_array) => {\n", - " //console.log(answer);\n", - "\n", - " // Make input element\n", - " var inp = document.createElement(\"input\");\n", - " inp.type = \"radio\";\n", - " inp.id = \"quizo\" + id + index;\n", - " inp.style = \"display:none;\";\n", - " aDiv.append(inp);\n", - "\n", - " //Make label for input element\n", - " var lab = document.createElement(\"label\");\n", - " lab.className = \"MCButton\";\n", - " lab.id = id + '-' + index;\n", - " lab.onclick = check_mc;\n", - " var aSpan = document.createElement('span');\n", - " aSpan.classsName = \"\";\n", - " //qDiv.id=\"quizQn\"+id+index;\n", - " if (\"answer\" in item) {\n", - " aSpan.innerHTML = jaxify(item.answer);\n", - " //aSpan.innerHTML=item.answer;\n", - " }\n", - " lab.append(aSpan);\n", - "\n", - " // Create div for code inside question\n", - " var codeSpan;\n", - " if (\"code\" in item) {\n", - " codeSpan = document.createElement('span');\n", - " codeSpan.id = \"code\" + id + index;\n", - " codeSpan.className = \"QuizCode\";\n", - " var codePre = document.createElement('pre');\n", - " codeSpan.append(codePre);\n", - " var codeCode = document.createElement('code');\n", - " codePre.append(codeCode);\n", - " codeCode.innerHTML = item.code;\n", - " lab.append(codeSpan);\n", - " //console.log(codeSpan);\n", - " }\n", - "\n", - " //lab.textContent=item.answer;\n", - "\n", - " // Set the data attributes for the answer\n", - " lab.setAttribute('data-correct', item.correct);\n", - " if (item.correct) {\n", - " num_correct++;\n", - " }\n", - " if (\"feedback\" in item) {\n", - " lab.setAttribute('data-feedback', item.feedback);\n", - " }\n", - " lab.setAttribute('data-answered', 0);\n", - "\n", - " aDiv.append(lab);\n", - "\n", - " });\n", - "\n", - " if (num_correct > 1) {\n", - " outerqDiv.className = \"ManyChoiceQn\";\n", - " } else {\n", - " outerqDiv.className = \"MultipleChoiceQn\";\n", - " }\n", - "\n", - " return num_correct;\n", - "\n", - "}\n", - "function check_numeric(ths, event) {\n", - "\n", - " if (event.keyCode === 13) {\n", - " ths.blur();\n", - "\n", - " var id = ths.id.split('-')[0];\n", - "\n", - " var submission = ths.value;\n", - " if (submission.indexOf('/') != -1) {\n", - " var sub_parts = submission.split('/');\n", - " //console.log(sub_parts);\n", - " submission = sub_parts[0] / sub_parts[1];\n", - " }\n", - " //console.log(\"Reader entered\", submission);\n", - "\n", - " if (\"precision\" in ths.dataset) {\n", - " var precision = ths.dataset.precision;\n", - " // console.log(\"1:\", submission)\n", - " submission = Math.round((1 * submission + Number.EPSILON) * 10 ** precision) / 10 ** precision;\n", - " // console.log(\"Rounded to \", submission, \" precision=\", precision );\n", - " }\n", - "\n", - "\n", - " //console.log(\"In check_numeric(), id=\"+id);\n", - " //console.log(event.srcElement.id) \n", - " //console.log(event.srcElement.dataset.feedback)\n", - "\n", - " var fb = document.getElementById(\"fb\" + id);\n", - " fb.style.display = \"none\";\n", - " fb.textContent = \"Incorrect -- try again.\";\n", - "\n", - " var answers = JSON.parse(ths.dataset.answers);\n", - " //console.log(answers);\n", - "\n", - " var defaultFB = \"\";\n", - " var correct;\n", - " var done = false;\n", - " answers.every(answer => {\n", - " //console.log(answer.type);\n", - "\n", - " correct = false;\n", - " // if (answer.type==\"value\"){\n", - " if ('value' in answer) {\n", - " if (submission == answer.value) {\n", - " if (\"feedback\" in answer) {\n", - " fb.textContent = jaxify(answer.feedback);\n", - " } else {\n", - " fb.textContent = jaxify(\"Correct\");\n", - " }\n", - " correct = answer.correct;\n", - " //console.log(answer.correct);\n", - " done = true;\n", - " }\n", - " // } else if (answer.type==\"range\") {\n", - " } else if ('range' in answer) {\n", - " //console.log(answer.range);\n", - " if ((submission >= answer.range[0]) && (submission < answer.range[1])) {\n", - " fb.textContent = jaxify(answer.feedback);\n", - " correct = answer.correct;\n", - " //console.log(answer.correct);\n", - " done = true;\n", - " }\n", - " } else if (answer.type == \"default\") {\n", - " defaultFB = answer.feedback;\n", - " }\n", - " if (done) {\n", - " return false; // Break out of loop if this has been marked correct\n", - " } else {\n", - " return true; // Keep looking for case that includes this as a correct answer\n", - " }\n", - " });\n", - "\n", - " if ((!done) && (defaultFB != \"\")) {\n", - " fb.innerHTML = jaxify(defaultFB);\n", - " //console.log(\"Default feedback\", defaultFB);\n", - " }\n", - "\n", - " fb.style.display = \"block\";\n", - " if (correct) {\n", - " ths.className = \"Input-text\";\n", - " ths.classList.add(\"correctButton\");\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"correct\");\n", - " } else {\n", - " ths.className = \"Input-text\";\n", - " ths.classList.add(\"incorrectButton\");\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"incorrect\");\n", - " }\n", - "\n", - " // What follows is for the saved responses stuff\n", - " var outerContainer = fb.parentElement.parentElement;\n", - " var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n", - " if (responsesContainer) {\n", - " console.log(submission);\n", - " var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n", - " //console.log(\"Question \" + qnum);\n", - " //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n", - " var responses=JSON.parse(responsesContainer.dataset.responses);\n", - " console.log(responses);\n", - " if (submission == ths.value){\n", - " responses[qnum]= submission;\n", - " } else {\n", - " responses[qnum]= ths.value + \"(\" + submission +\")\";\n", - " }\n", - " responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n", - " printResponses(responsesContainer);\n", - " }\n", - " // End code to preserve responses\n", - "\n", - " if (typeof MathJax != 'undefined') {\n", - " var version = MathJax.version;\n", - " console.log('MathJax version', version);\n", - " if (version[0] == \"2\") {\n", - " MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n", - " } else if (version[0] == \"3\") {\n", - " MathJax.typeset([fb]);\n", - " }\n", - " } else {\n", - " console.log('MathJax not detected');\n", - " }\n", - " return false;\n", - " }\n", - "\n", - "}\n", - "\n", - "function isValid(el, charC) {\n", - " //console.log(\"Input char: \", charC);\n", - " if (charC == 46) {\n", - " if (el.value.indexOf('.') === -1) {\n", - " return true;\n", - " } else if (el.value.indexOf('/') != -1) {\n", - " var parts = el.value.split('/');\n", - " if (parts[1].indexOf('.') === -1) {\n", - " return true;\n", - " }\n", - " }\n", - " else {\n", - " return false;\n", - " }\n", - " } else if (charC == 47) {\n", - " if (el.value.indexOf('/') === -1) {\n", - " if ((el.value != \"\") && (el.value != \".\")) {\n", - " return true;\n", - " } else {\n", - " return false;\n", - " }\n", - " } else {\n", - " return false;\n", - " }\n", - " } else if (charC == 45) {\n", - " var edex = el.value.indexOf('e');\n", - " if (edex == -1) {\n", - " edex = el.value.indexOf('E');\n", - " }\n", - "\n", - " if (el.value == \"\") {\n", - " return true;\n", - " } else if (edex == (el.value.length - 1)) { // If just after e or E\n", - " return true;\n", - " } else {\n", - " return false;\n", - " }\n", - " } else if (charC == 101) { // \"e\"\n", - " if ((el.value.indexOf('e') === -1) && (el.value.indexOf('E') === -1) && (el.value.indexOf('/') == -1)) {\n", - " // Prev symbol must be digit or decimal point:\n", - " if (el.value.slice(-1).search(/\\d/) >= 0) {\n", - " return true;\n", - " } else if (el.value.slice(-1).search(/\\./) >= 0) {\n", - " return true;\n", - " } else {\n", - " return false;\n", - " }\n", - " } else {\n", - " return false;\n", - " }\n", - " } else {\n", - " if (charC > 31 && (charC < 48 || charC > 57))\n", - " return false;\n", - " }\n", - " return true;\n", - "}\n", - "\n", - "function numeric_keypress(evnt) {\n", - " var charC = (evnt.which) ? evnt.which : evnt.keyCode;\n", - "\n", - " if (charC == 13) {\n", - " check_numeric(this, evnt);\n", - " } else {\n", - " return isValid(this, charC);\n", - " }\n", - "}\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "function make_numeric(qa, outerqDiv, qDiv, aDiv, id) {\n", - "\n", - "\n", - "\n", - " //console.log(answer);\n", - "\n", - "\n", - " outerqDiv.className = \"NumericQn\";\n", - " aDiv.style.display = 'block';\n", - "\n", - " var lab = document.createElement(\"label\");\n", - " lab.className = \"InpLabel\";\n", - " lab.textContent = \"Type numeric answer here:\";\n", - " aDiv.append(lab);\n", - "\n", - " var inp = document.createElement(\"input\");\n", - " inp.type = \"text\";\n", - " //inp.id=\"input-\"+id;\n", - " inp.id = id + \"-0\";\n", - " inp.className = \"Input-text\";\n", - " inp.setAttribute('data-answers', JSON.stringify(qa.answers));\n", - " if (\"precision\" in qa) {\n", - " inp.setAttribute('data-precision', qa.precision);\n", - " }\n", - " aDiv.append(inp);\n", - " //console.log(inp);\n", - "\n", - " //inp.addEventListener(\"keypress\", check_numeric);\n", - " //inp.addEventListener(\"keypress\", numeric_keypress);\n", - " /*\n", - " inp.addEventListener(\"keypress\", function(event) {\n", - " return numeric_keypress(this, event);\n", - " }\n", - " );\n", - " */\n", - " //inp.onkeypress=\"return numeric_keypress(this, event)\";\n", - " inp.onkeypress = numeric_keypress;\n", - " inp.onpaste = event => false;\n", - "\n", - " inp.addEventListener(\"focus\", function (event) {\n", - " this.value = \"\";\n", - " return false;\n", - " }\n", - " );\n", - "\n", - "\n", - "}\n", - "function jaxify(string) {\n", - " var mystring = string;\n", - "\n", - " var count = 0;\n", - " var loc = mystring.search(/([^\\\\]|^)(\\$)/);\n", - "\n", - " var count2 = 0;\n", - " var loc2 = mystring.search(/([^\\\\]|^)(\\$\\$)/);\n", - "\n", - " //console.log(loc);\n", - "\n", - " while ((loc >= 0) || (loc2 >= 0)) {\n", - "\n", - " /* Have to replace all the double $$ first with current implementation */\n", - " if (loc2 >= 0) {\n", - " if (count2 % 2 == 0) {\n", - " mystring = mystring.replace(/([^\\\\]|^)(\\$\\$)/, \"$1\\\\[\");\n", - " } else {\n", - " mystring = mystring.replace(/([^\\\\]|^)(\\$\\$)/, \"$1\\\\]\");\n", - " }\n", - " count2++;\n", - " } else {\n", - " if (count % 2 == 0) {\n", - " mystring = mystring.replace(/([^\\\\]|^)(\\$)/, \"$1\\\\(\");\n", - " } else {\n", - " mystring = mystring.replace(/([^\\\\]|^)(\\$)/, \"$1\\\\)\");\n", - " }\n", - " count++;\n", - " }\n", - " loc = mystring.search(/([^\\\\]|^)(\\$)/);\n", - " loc2 = mystring.search(/([^\\\\]|^)(\\$\\$)/);\n", - " //console.log(mystring,\", loc:\",loc,\", loc2:\",loc2);\n", - " }\n", - "\n", - " //console.log(mystring);\n", - " return mystring;\n", - "}\n", - "\n", - "\n", - "function show_questions(json, mydiv) {\n", - " console.log('show_questions');\n", - " //var mydiv=document.getElementById(myid);\n", - " var shuffle_questions = mydiv.dataset.shufflequestions;\n", - " var num_questions = mydiv.dataset.numquestions;\n", - " var shuffle_answers = mydiv.dataset.shuffleanswers;\n", - " var max_width = mydiv.dataset.maxwidth;\n", - "\n", - " if (num_questions > json.length) {\n", - " num_questions = json.length;\n", - " }\n", - "\n", - " var questions;\n", - " if ((num_questions < json.length) || (shuffle_questions == \"True\")) {\n", - " //console.log(num_questions+\",\"+json.length);\n", - " questions = getRandomSubarray(json, num_questions);\n", - " } else {\n", - " questions = json;\n", - " }\n", - "\n", - " //console.log(\"SQ: \"+shuffle_questions+\", NQ: \" + num_questions + \", SA: \", shuffle_answers);\n", - "\n", - " // Iterate over questions\n", - " questions.forEach((qa, index, array) => {\n", - " //console.log(qa.question); \n", - "\n", - " var id = makeid(8);\n", - " //console.log(id);\n", - "\n", - "\n", - " // Create Div to contain question and answers\n", - " var iDiv = document.createElement('div');\n", - " //iDiv.id = 'quizWrap' + id + index;\n", - " iDiv.id = 'quizWrap' + id;\n", - " iDiv.className = 'Quiz';\n", - " iDiv.setAttribute('data-qnum', index);\n", - " iDiv.style.maxWidth =max_width+\"px\";\n", - " mydiv.appendChild(iDiv);\n", - " // iDiv.innerHTML=qa.question;\n", - " \n", - " var outerqDiv = document.createElement('div');\n", - " outerqDiv.id = \"OuterquizQn\" + id + index;\n", - " // Create div to contain question part\n", - " var qDiv = document.createElement('div');\n", - " qDiv.id = \"quizQn\" + id + index;\n", - " \n", - " if (qa.question) {\n", - " iDiv.append(outerqDiv);\n", - "\n", - " //qDiv.textContent=qa.question;\n", - " qDiv.innerHTML = jaxify(qa.question);\n", - " outerqDiv.append(qDiv);\n", - " }\n", - "\n", - " // Create div for code inside question\n", - " var codeDiv;\n", - " if (\"code\" in qa) {\n", - " codeDiv = document.createElement('div');\n", - " codeDiv.id = \"code\" + id + index;\n", - " codeDiv.className = \"QuizCode\";\n", - " var codePre = document.createElement('pre');\n", - " codeDiv.append(codePre);\n", - " var codeCode = document.createElement('code');\n", - " codePre.append(codeCode);\n", - " codeCode.innerHTML = qa.code;\n", - " outerqDiv.append(codeDiv);\n", - " //console.log(codeDiv);\n", - " }\n", - "\n", - "\n", - " // Create div to contain answer part\n", - " var aDiv = document.createElement('div');\n", - " aDiv.id = \"quizAns\" + id + index;\n", - " aDiv.className = 'Answer';\n", - " iDiv.append(aDiv);\n", - "\n", - " //console.log(qa.type);\n", - "\n", - " var num_correct;\n", - " if ((qa.type == \"multiple_choice\") || (qa.type == \"many_choice\") ) {\n", - " num_correct = make_mc(qa, shuffle_answers, outerqDiv, qDiv, aDiv, id);\n", - " if (\"answer_cols\" in qa) {\n", - " //aDiv.style.gridTemplateColumns = 'auto '.repeat(qa.answer_cols);\n", - " aDiv.style.gridTemplateColumns = 'repeat(' + qa.answer_cols + ', 1fr)';\n", - " }\n", - " } else if (qa.type == \"numeric\") {\n", - " //console.log(\"numeric\");\n", - " make_numeric(qa, outerqDiv, qDiv, aDiv, id);\n", - " }\n", - "\n", - "\n", - " //Make div for feedback\n", - " var fb = document.createElement(\"div\");\n", - " fb.id = \"fb\" + id;\n", - " //fb.style=\"font-size: 20px;text-align:center;\";\n", - " fb.className = \"Feedback\";\n", - " fb.setAttribute(\"data-answeredcorrect\", 0);\n", - " fb.setAttribute(\"data-numcorrect\", num_correct);\n", - " iDiv.append(fb);\n", - "\n", - "\n", - " });\n", - " var preserveResponses = mydiv.dataset.preserveresponses;\n", - " console.log(preserveResponses);\n", - " console.log(preserveResponses == \"true\");\n", - " if (preserveResponses == \"true\") {\n", - " console.log(preserveResponses);\n", - " // Create Div to contain record of answers\n", - " var iDiv = document.createElement('div');\n", - " iDiv.id = 'responses' + mydiv.id;\n", - " iDiv.className = 'JCResponses';\n", - " // Create a place to store responses as an empty array\n", - " iDiv.setAttribute('data-responses', '[]');\n", - "\n", - " // Dummy Text\n", - " iDiv.innerHTML=\"Select your answers and then follow the directions that will appear here.\"\n", - " //iDiv.className = 'Quiz';\n", - " mydiv.appendChild(iDiv);\n", - " }\n", - "//console.log(\"At end of show_questions\");\n", - " if (typeof MathJax != 'undefined') {\n", - " console.log(\"MathJax version\", MathJax.version);\n", - " var version = MathJax.version;\n", - " setTimeout(function(){\n", - " var version = MathJax.version;\n", - " console.log('After sleep, MathJax version', version);\n", - " if (version[0] == \"2\") {\n", - " MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n", - " } else if (version[0] == \"3\") {\n", - " MathJax.typeset([mydiv]);\n", - " }\n", - " }, 500);\n", - "if (typeof version == 'undefined') {\n", - " } else\n", - " {\n", - " if (version[0] == \"2\") {\n", - " MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n", - " } else if (version[0] == \"3\") {\n", - " MathJax.typeset([mydiv]);\n", - " } else {\n", - " console.log(\"MathJax not found\");\n", - " }\n", - " }\n", - " }\n", - " return false;\n", - "}\n", - "/* This is to handle asynchrony issues in loading Jupyter notebooks\n", - " where the quiz has been previously run. The Javascript was generally\n", - " being run before the div was added to the DOM. I tried to do this\n", - " more elegantly using Mutation Observer, but I didn't get it to work.\n", - "\n", - " Someone more knowledgeable could make this better ;-) */\n", - "\n", - " function try_show() {\n", - " if(document.getElementById(\"qukeMLYgLRMA\")) {\n", - " show_questions(questionsqukeMLYgLRMA, qukeMLYgLRMA); \n", - " } else {\n", - " setTimeout(try_show, 200);\n", - " }\n", - " };\n", - " \n", - " {\n", - " // console.log(element);\n", - "\n", - " //console.log(\"qukeMLYgLRMA\");\n", - " // console.log(document.getElementById(\"qukeMLYgLRMA\"));\n", - "\n", - " try_show();\n", - " }\n", - " " - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from jupyterquiz import display_quiz\n", - "display_quiz(\"questions/summary_virtual_environments.json\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "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.9.19" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/individual_modules/python_for_data_analysis/Python_Language_features.ipynb b/short_courses/python_language_features.ipynb similarity index 99% rename from individual_modules/python_for_data_analysis/Python_Language_features.ipynb rename to short_courses/python_language_features.ipynb index 0a5ab7f0..b4b5acdc 100644 --- a/individual_modules/python_for_data_analysis/Python_Language_features.ipynb +++ b/short_courses/python_language_features.ipynb @@ -11,8 +11,21 @@ "tags": [] }, "source": [ - "# Advanced Language Features \n", - "## Learning Objectives\n", + "# Python Advanced Language Features \n", + "\n", + "```{card}\n", + "\n", + "
    \n", + "\n", + "**Author:** Michael Saunby (GitHub: [msaunby](https://github.com/msaunby))\n", + "\n", + "**License:** Creative Commons Attribution-ShareAlike 4.0 International license ([CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)).\n", + "\n", + "
    \n", + "\n", + "```\n", + "\n", + "## Course Objectives\n", "- Understand the use and significance of docstrings and type hints in Python for better code documentation and type-checking\n", "- Utilize introspection to inspect objects, functions, and modules\n", "- Apply decorators to modify the behaviour of functions and methods\n", diff --git a/individual_modules/python_for_data_analysis/Python_Testing.ipynb b/short_courses/python_testing.ipynb similarity index 99% rename from individual_modules/python_for_data_analysis/Python_Testing.ipynb rename to short_courses/python_testing.ipynb index 4585a682..85eec964 100644 --- a/individual_modules/python_for_data_analysis/Python_Testing.ipynb +++ b/short_courses/python_testing.ipynb @@ -10,8 +10,25 @@ "tags": [] }, "source": [ - "# Checking and Testing Code\n", - "## Learning Objectives\n", + "# Python Checking and Testing Code\n", + "\n", + "\n", + "```{card}\n", + "\n", + "
    \n", + "\n", + "**Author:** Michael Saunby (GitHub: [msaunby](https://github.com/msaunby))\n", + "\n", + "**License:** Creative Commons Attribution-ShareAlike 4.0 International license ([CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)).\n", + "\n", + "
    \n", + "\n", + "```\n", + "\n", + "\n", + "\n", + "\n", + "## Course Objectives\n", "- Understand the importance and limitations of software testing\n", "- Recognize different types of testing such as system-level and defect testing\n", "- Learn how to implement and interpret assert statement in Python code\n", From 90e91f106a560edf8e3955fd05c7a607625f852a Mon Sep 17 00:00:00 2001 From: Liam J Berrisford Date: Wed, 13 Aug 2025 11:14:37 +0100 Subject: [PATCH 6/8] Fix broken link and lexer issues --- _config.yml | 2 + _static/multiple_regression_hyperplane.html | 2 +- _static/multiple_regression_hyperplane_2.html | 2 +- ..._advanced_regression_analysis_with_r_.html | 4 +- .../workshop_prereqs_parallel_computing.html | 4 +- ..._with_r_adapting_to_varied_data_types.html | 4 +- .../improve_your_r_code/style.ipynb | 2 +- .../introduction_to_julia/functions.ipynb | 134 ++++++++++-------- .../introduction_to_julia/variables.ipynb | 44 +++--- .../figures/python_testing}/type-checking.png | Bin short_courses/python_language_features.ipynb | 83 ++++++----- short_courses/python_testing.ipynb | 117 ++++----------- 12 files changed, 187 insertions(+), 211 deletions(-) rename {individual_modules/python_for_data_analysis/images => short_courses/figures/python_testing}/type-checking.png (100%) diff --git a/_config.yml b/_config.yml index 4207f40f..1e1a45eb 100644 --- a/_config.yml +++ b/_config.yml @@ -116,4 +116,6 @@ execute: - 'short_courses/r_unit_testing.ipynb' - 'short_courses/r_functions.ipynb' - 'short_courses/r_functions.ipynb' + - 'short_courses/python_language_features.ipynb' + - 'short_courses/python_testing.ipynb' - 'individual_modules/markdown_with_python/liveOutput.ipynb' diff --git a/_static/multiple_regression_hyperplane.html b/_static/multiple_regression_hyperplane.html index f77af395..500aeca6 100644 --- a/_static/multiple_regression_hyperplane.html +++ b/_static/multiple_regression_hyperplane.html @@ -2,6 +2,6 @@
    -
    +
\ No newline at end of file diff --git a/_static/multiple_regression_hyperplane_2.html b/_static/multiple_regression_hyperplane_2.html index fe9bf32e..58899908 100644 --- a/_static/multiple_regression_hyperplane_2.html +++ b/_static/multiple_regression_hyperplane_2.html @@ -2,6 +2,6 @@
-
+
\ No newline at end of file diff --git a/_static/workshop_prereqs_advanced_regression_analysis_with_r_.html b/_static/workshop_prereqs_advanced_regression_analysis_with_r_.html index 90610b4e..1c628a68 100644 --- a/_static/workshop_prereqs_advanced_regression_analysis_with_r_.html +++ b/_static/workshop_prereqs_advanced_regression_analysis_with_r_.html @@ -282,8 +282,8 @@

// parsing and collecting nodes and edges from the python - nodes = new vis.DataSet([{"color": "#B0B0B0", "id": "Introduction to R", "label": "Introduction to R", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to R\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to Regression with R"}, {"color": "#B0B0B0", "id": "Introduction to Regression with R", "label": "Introduction to Regression with R", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Regression with R\nCourse Pre-reqs: Introduction to R\nSubsequent Courses: Regression Analysis with R Adapting to Varied Data Types"}, {"color": "#B0B0B0", "id": "Regression Analysis with R Adapting to Varied Data Types", "label": "Regression Analysis with R Adapting to Varied Data Types", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Regression Analysis with R Adapting to Varied Data Types\nCourse Pre-reqs: Introduction to Regression with R\nSubsequent Courses: Advanced Regression Analysis With R "}, {"color": "#B0B0B0", "id": "Advanced Regression Analysis With R ", "label": "Advanced Regression Analysis With R ", "level": 4, "shape": "dot", "size": 10, "title": "Course Name: Advanced Regression Analysis With R \nCourse Pre-reqs: Regression Analysis with R Adapting to Varied Data Types\nSubsequent Courses: None"}]); - edges = new vis.DataSet([{"arrows": "to", "from": "Introduction to R", "to": "Introduction to Regression with R", "width": 1}, {"arrows": "to", "from": "Regression Analysis with R Adapting to Varied Data Types", "to": "Advanced Regression Analysis With R ", "width": 1}, {"arrows": "to", "from": "Introduction to Regression with R", "to": "Regression Analysis with R Adapting to Varied Data Types", "width": 1}]); + nodes = new vis.DataSet([{"color": "#B0B0B0", "id": "Regression Analysis with R Adapting to Varied Data Types", "label": "Regression Analysis with R Adapting to Varied Data Types", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Regression Analysis with R Adapting to Varied Data Types\nCourse Pre-reqs: Introduction to Regression with R\nSubsequent Courses: Advanced Regression Analysis With R "}, {"color": "#B0B0B0", "id": "Advanced Regression Analysis With R ", "label": "Advanced Regression Analysis With R ", "level": 4, "shape": "dot", "size": 10, "title": "Course Name: Advanced Regression Analysis With R \nCourse Pre-reqs: Regression Analysis with R Adapting to Varied Data Types\nSubsequent Courses: None"}, {"color": "#B0B0B0", "id": "Introduction to Regression with R", "label": "Introduction to Regression with R", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Regression with R\nCourse Pre-reqs: Introduction to R\nSubsequent Courses: Regression Analysis with R Adapting to Varied Data Types"}, {"color": "#B0B0B0", "id": "Introduction to R", "label": "Introduction to R", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to R\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to Regression with R"}]); + edges = new vis.DataSet([{"arrows": "to", "from": "Regression Analysis with R Adapting to Varied Data Types", "to": "Advanced Regression Analysis With R ", "width": 1}, {"arrows": "to", "from": "Introduction to Regression with R", "to": "Regression Analysis with R Adapting to Varied Data Types", "width": 1}, {"arrows": "to", "from": "Introduction to R", "to": "Introduction to Regression with R", "width": 1}]); nodeColors = {}; allNodes = nodes.get({ returnType: "Object" }); diff --git a/_static/workshop_prereqs_parallel_computing.html b/_static/workshop_prereqs_parallel_computing.html index fe8a9c41..54885b27 100644 --- a/_static/workshop_prereqs_parallel_computing.html +++ b/_static/workshop_prereqs_parallel_computing.html @@ -282,8 +282,8 @@

// parsing and collecting nodes and edges from the python - nodes = new vis.DataSet([{"color": "#B0B0B0", "id": "Introduction to HPC", "label": "Introduction to HPC", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to HPC\nCourse Pre-reqs: Introduction to Unix\nSubsequent Courses: Parallel Computing"}, {"color": "#B0B0B0", "id": "Parallel Computing", "label": "Parallel Computing", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Parallel Computing\nCourse Pre-reqs: Introduction to HPC\nSubsequent Courses: None"}, {"color": "#B0B0B0", "id": "Introduction to Unix", "label": "Introduction to Unix", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Unix\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to HPC"}]); - edges = new vis.DataSet([{"arrows": "to", "from": "Introduction to HPC", "to": "Parallel Computing", "width": 1}, {"arrows": "to", "from": "Introduction to Unix", "to": "Introduction to HPC", "width": 1}]); + nodes = new vis.DataSet([{"color": "#B0B0B0", "id": "Introduction to Unix", "label": "Introduction to Unix", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Unix\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to HPC"}, {"color": "#B0B0B0", "id": "Introduction to HPC", "label": "Introduction to HPC", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to HPC\nCourse Pre-reqs: Introduction to Unix\nSubsequent Courses: Parallel Computing"}, {"color": "#B0B0B0", "id": "Parallel Computing", "label": "Parallel Computing", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Parallel Computing\nCourse Pre-reqs: Introduction to HPC\nSubsequent Courses: None"}]); + edges = new vis.DataSet([{"arrows": "to", "from": "Introduction to Unix", "to": "Introduction to HPC", "width": 1}, {"arrows": "to", "from": "Introduction to HPC", "to": "Parallel Computing", "width": 1}]); nodeColors = {}; allNodes = nodes.get({ returnType: "Object" }); diff --git a/_static/workshop_prereqs_regression_analysis_with_r_adapting_to_varied_data_types.html b/_static/workshop_prereqs_regression_analysis_with_r_adapting_to_varied_data_types.html index ebaa7777..c2443843 100644 --- a/_static/workshop_prereqs_regression_analysis_with_r_adapting_to_varied_data_types.html +++ b/_static/workshop_prereqs_regression_analysis_with_r_adapting_to_varied_data_types.html @@ -282,8 +282,8 @@

// parsing and collecting nodes and edges from the python - nodes = new vis.DataSet([{"color": "#B0B0B0", "id": "Introduction to R", "label": "Introduction to R", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to R\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to Regression with R"}, {"color": "#B0B0B0", "id": "Introduction to Regression with R", "label": "Introduction to Regression with R", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Regression with R\nCourse Pre-reqs: Introduction to R\nSubsequent Courses: Regression Analysis with R Adapting to Varied Data Types"}, {"color": "#B0B0B0", "id": "Regression Analysis with R Adapting to Varied Data Types", "label": "Regression Analysis with R Adapting to Varied Data Types", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Regression Analysis with R Adapting to Varied Data Types\nCourse Pre-reqs: Introduction to Regression with R\nSubsequent Courses: None"}]); - edges = new vis.DataSet([{"arrows": "to", "from": "Introduction to R", "to": "Introduction to Regression with R", "width": 1}, {"arrows": "to", "from": "Introduction to Regression with R", "to": "Regression Analysis with R Adapting to Varied Data Types", "width": 1}]); + nodes = new vis.DataSet([{"color": "#B0B0B0", "id": "Introduction to Regression with R", "label": "Introduction to Regression with R", "level": 2, "shape": "dot", "size": 10, "title": "Course Name: Introduction to Regression with R\nCourse Pre-reqs: Introduction to R\nSubsequent Courses: Regression Analysis with R Adapting to Varied Data Types"}, {"color": "#B0B0B0", "id": "Regression Analysis with R Adapting to Varied Data Types", "label": "Regression Analysis with R Adapting to Varied Data Types", "level": 3, "shape": "dot", "size": 10, "title": "Course Name: Regression Analysis with R Adapting to Varied Data Types\nCourse Pre-reqs: Introduction to Regression with R\nSubsequent Courses: None"}, {"color": "#B0B0B0", "id": "Introduction to R", "label": "Introduction to R", "level": 1, "shape": "dot", "size": 10, "title": "Course Name: Introduction to R\nCourse Pre-reqs: None\nSubsequent Courses: Introduction to Regression with R"}]); + edges = new vis.DataSet([{"arrows": "to", "from": "Introduction to Regression with R", "to": "Regression Analysis with R Adapting to Varied Data Types", "width": 1}, {"arrows": "to", "from": "Introduction to R", "to": "Introduction to Regression with R", "width": 1}]); nodeColors = {}; allNodes = nodes.get({ returnType: "Object" }); diff --git a/individual_modules/improve_your_r_code/style.ipynb b/individual_modules/improve_your_r_code/style.ipynb index fed25287..9b005838 100644 --- a/individual_modules/improve_your_r_code/style.ipynb +++ b/individual_modules/improve_your_r_code/style.ipynb @@ -492,7 +492,7 @@ "\n", "## The Styler and lintr packages\n", "The `styler` and `lintr` packages are two useful packages for formatting your code according to the Tidyverse style guide. You can install them from CRAN in the usual way:\n", - "```{r eval=FALSE, include=TRUE}\n", + "```r\n", "install.packages(\"styler\")\n", "install.packages(\"lintr\")\n", "```\n", diff --git a/individual_modules/introduction_to_julia/functions.ipynb b/individual_modules/introduction_to_julia/functions.ipynb index d5bbae51..35437c29 100644 --- a/individual_modules/introduction_to_julia/functions.ipynb +++ b/individual_modules/introduction_to_julia/functions.ipynb @@ -369,51 +369,61 @@ ] }, { - "cell_type": "code", - "execution_count": 6, - "id": "ba047e98-2bcf-4e07-a71b-48868ae04f69", + "cell_type": "markdown", + "id": "7d0c0b2a-8214-42a7-8ab8-29525cdfb025", "metadata": {}, - "outputs": [ - { - "ename": "LoadError", - "evalue": "MethodError: no method matching add(::Int64, ::String)\nThe function `add` exists, but no method is defined for this combination of argument types.\n\n\u001b[0mClosest candidates are:\n\u001b[0m add(\u001b[91m::String\u001b[39m, ::String)\n\u001b[0m\u001b[90m @\u001b[39m \u001b[35mMain\u001b[39m \u001b[90m\u001b[4mIn[5]:7\u001b[24m\u001b[39m\n\u001b[0m add(::Int64, \u001b[91m::Int64\u001b[39m)\n\u001b[0m\u001b[90m @\u001b[39m \u001b[35mMain\u001b[39m \u001b[90m\u001b[4mIn[5]:2\u001b[24m\u001b[39m\n", - "output_type": "error", - "traceback": [ - "MethodError: no method matching add(::Int64, ::String)\nThe function `add` exists, but no method is defined for this combination of argument types.\n\n\u001b[0mClosest candidates are:\n\u001b[0m add(\u001b[91m::String\u001b[39m, ::String)\n\u001b[0m\u001b[90m @\u001b[39m \u001b[35mMain\u001b[39m \u001b[90m\u001b[4mIn[5]:7\u001b[24m\u001b[39m\n\u001b[0m add(::Int64, \u001b[91m::Int64\u001b[39m)\n\u001b[0m\u001b[90m @\u001b[39m \u001b[35mMain\u001b[39m \u001b[90m\u001b[4mIn[5]:2\u001b[24m\u001b[39m\n", - "", - "Stacktrace:", - " [1] top-level scope", - "\u001b[90m @\u001b[39m \u001b[90m\u001b[4mIn[6]:2\u001b[24m\u001b[39m" - ] - } - ], "source": [ + "```\n", "# Error: not defined for Int, String\n", - "add(1, \"hello\")" + "add(1, \"hello\")\n", + "```\n", + "\n", + "produces: \n", + "\n", + "```\n", + "MethodError: no method matching add(::Int64, ::String)\n", + "The function `add` exists, but no method is defined for this combination of argument types.\n", + "\n", + "Closest candidates are:\n", + " add(::String, ::String)\n", + " @ Main In[5]:7\n", + " add(::Int64, ::Int64)\n", + " @ Main In[5]:2\n", + "\n", + "\n", + "Stacktrace:\n", + " [1] top-level scope\n", + " @ In[6]:2\n", + "```" ] }, { - "cell_type": "code", - "execution_count": 7, - "id": "203e17c6-f031-4458-9f68-0a9d0682ccab", + "cell_type": "markdown", + "id": "2ddb2f55-54f6-44a7-b619-fef08840a779", "metadata": {}, - "outputs": [ - { - "ename": "LoadError", - "evalue": "MethodError: no method matching add(::Int64, ::Int64, ::Int64)\nThe function `add` exists, but no method is defined for this combination of argument types.\n\n\u001b[0mClosest candidates are:\n\u001b[0m add(::Int64, ::Int64)\n\u001b[0m\u001b[90m @\u001b[39m \u001b[35mMain\u001b[39m \u001b[90m\u001b[4mIn[5]:2\u001b[24m\u001b[39m\n\u001b[0m add(\u001b[91m::String\u001b[39m, \u001b[91m::String\u001b[39m)\n\u001b[0m\u001b[90m @\u001b[39m \u001b[35mMain\u001b[39m \u001b[90m\u001b[4mIn[5]:7\u001b[24m\u001b[39m\n", - "output_type": "error", - "traceback": [ - "MethodError: no method matching add(::Int64, ::Int64, ::Int64)\nThe function `add` exists, but no method is defined for this combination of argument types.\n\n\u001b[0mClosest candidates are:\n\u001b[0m add(::Int64, ::Int64)\n\u001b[0m\u001b[90m @\u001b[39m \u001b[35mMain\u001b[39m \u001b[90m\u001b[4mIn[5]:2\u001b[24m\u001b[39m\n\u001b[0m add(\u001b[91m::String\u001b[39m, \u001b[91m::String\u001b[39m)\n\u001b[0m\u001b[90m @\u001b[39m \u001b[35mMain\u001b[39m \u001b[90m\u001b[4mIn[5]:7\u001b[24m\u001b[39m\n", - "", - "Stacktrace:", - " [1] top-level scope", - "\u001b[90m @\u001b[39m \u001b[90m\u001b[4mIn[7]:2\u001b[24m\u001b[39m" - ] - } - ], "source": [ + "```\n", "# Error: not defined for more than two Ints\n", - "add(1, 2, 3)" + "add(1, 2, 3)\n", + "```\n", + "\n", + "produces: \n", + "\n", + "```\n", + "MethodError: no method matching add(::Int64, ::Int64, ::Int64)\n", + "The function `add` exists, but no method is defined for this combination of argument types.\n", + "\n", + "Closest candidates are:\n", + " add(::Int64, ::Int64)\n", + " @ Main In[5]:2\n", + " add(::String, ::String)\n", + " @ Main In[5]:7\n", + "\n", + "\n", + "Stacktrace:\n", + " [1] top-level scope\n", + " @ In[7]:2\n", + "```" ] }, { @@ -426,7 +436,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 6, "id": "3f2a79ca-6003-4607-b60b-8119890fe2e4", "metadata": {}, "outputs": [ @@ -436,7 +446,7 @@ "add (generic function with 4 methods)" ] }, - "execution_count": 8, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -470,7 +480,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 7, "id": "6076fdcd-7e84-4ff7-8eac-cfc65b2b34bc", "metadata": {}, "outputs": [], @@ -497,7 +507,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 8, "id": "0535dc96-91cc-41c1-a2db-86638c7d7a49", "metadata": {}, "outputs": [ @@ -507,7 +517,7 @@ "add (generic function with 5 methods)" ] }, - "execution_count": 10, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -552,7 +562,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 9, "id": "91b257a3-0a45-4c51-840d-ef6e6fdecba9", "metadata": {}, "outputs": [ @@ -595,7 +605,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 10, "id": "6fae928e-0537-4112-976f-f47b7dd8be26", "metadata": {}, "outputs": [ @@ -622,7 +632,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 11, "id": "dc6bdf2e-d5ad-4bd0-ae93-f6679e270cd0", "metadata": {}, "outputs": [ @@ -632,7 +642,7 @@ "add (generic function with 6 methods)" ] }, - "execution_count": 13, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -654,7 +664,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 12, "id": "abab1a36-1024-417e-a3d7-f5b6bfba5df2", "metadata": {}, "outputs": [ @@ -683,38 +693,38 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 13, "id": "68d60f05-7d23-465f-aba7-7669a70a93b1", "metadata": {}, "outputs": [ { "data": { "text/html": [ - "# 6 methods for generic function add from \u001b[35mMain\u001b[39m:
  • add(x::String, y::Int64) in Main at In[8]:5
  • add(x::Int64, y::String) in Main at In[8]:2
  • add(x::String, y::String) in Main at In[5]:7
  • add(x::Int64, y::Int64) in Main at In[5]:2
  • add(x::Number, y::Number) in Main at In[13]:2
  • add(x, y) in Main at In[10]:2
" + "# 6 methods for generic function add from \u001b[35mMain\u001b[39m:
  • add(x::String, y::Int64) in Main at In[6]:5
  • add(x::Int64, y::String) in Main at In[6]:2
  • add(x::String, y::String) in Main at In[5]:7
  • add(x::Int64, y::Int64) in Main at In[5]:2
  • add(x::Number, y::Number) in Main at In[11]:2
  • add(x, y) in Main at In[8]:2
" ], "text/plain": [ "# 6 methods for generic function \"add\" from \u001b[35mMain\u001b[39m:\n", " [1] add(\u001b[90mx\u001b[39m::\u001b[1mString\u001b[22m, \u001b[90my\u001b[39m::\u001b[1mInt64\u001b[22m)\n", - "\u001b[90m @\u001b[39m \u001b[90m\u001b[4mIn[8]:5\u001b[24m\u001b[39m\n", + "\u001b[90m @\u001b[39m \u001b[90m\u001b[4mIn[6]:5\u001b[24m\u001b[39m\n", " [2] add(\u001b[90mx\u001b[39m::\u001b[1mInt64\u001b[22m, \u001b[90my\u001b[39m::\u001b[1mString\u001b[22m)\n", - "\u001b[90m @\u001b[39m \u001b[90m\u001b[4mIn[8]:2\u001b[24m\u001b[39m\n", + "\u001b[90m @\u001b[39m \u001b[90m\u001b[4mIn[6]:2\u001b[24m\u001b[39m\n", " [3] add(\u001b[90mx\u001b[39m::\u001b[1mString\u001b[22m, \u001b[90my\u001b[39m::\u001b[1mString\u001b[22m)\n", "\u001b[90m @\u001b[39m \u001b[90m\u001b[4mIn[5]:7\u001b[24m\u001b[39m\n", " [4] add(\u001b[90mx\u001b[39m::\u001b[1mInt64\u001b[22m, \u001b[90my\u001b[39m::\u001b[1mInt64\u001b[22m)\n", "\u001b[90m @\u001b[39m \u001b[90m\u001b[4mIn[5]:2\u001b[24m\u001b[39m\n", " [5] add(\u001b[90mx\u001b[39m::\u001b[1mNumber\u001b[22m, \u001b[90my\u001b[39m::\u001b[1mNumber\u001b[22m)\n", - "\u001b[90m @\u001b[39m \u001b[90m\u001b[4mIn[13]:2\u001b[24m\u001b[39m\n", + "\u001b[90m @\u001b[39m \u001b[90m\u001b[4mIn[11]:2\u001b[24m\u001b[39m\n", " [6] add(\u001b[90mx\u001b[39m, \u001b[90my\u001b[39m)\n", - "\u001b[90m @\u001b[39m \u001b[90m\u001b[4mIn[10]:2\u001b[24m\u001b[39m" + "\u001b[90m @\u001b[39m \u001b[90m\u001b[4mIn[8]:2\u001b[24m\u001b[39m" ] }, - "execution_count": 15, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "# See all methods for `add`\n", + "# See all methods for add\n", "methods(add)" ] }, @@ -781,7 +791,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 14, "id": "c42e667f-ddee-4cc5-b8de-a725cac617e2", "metadata": { "editable": true, @@ -855,7 +865,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 15, "id": "1fa474f1-9085-4fa3-80e9-90211ea59713", "metadata": { "editable": true, @@ -876,7 +886,7 @@ " 25" ] }, - "execution_count": 17, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -904,7 +914,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 16, "id": "3e9cc925-d1a8-4a8e-8347-fbf8d5a62c47", "metadata": { "editable": true, @@ -923,7 +933,7 @@ "", "Stacktrace:", " [1] top-level scope", - "\u001b[90m @\u001b[39m \u001b[90m\u001b[4mIn[18]:2\u001b[24m\u001b[39m" + "\u001b[90m @\u001b[39m \u001b[90m\u001b[4mIn[16]:2\u001b[24m\u001b[39m" ] } ], @@ -955,7 +965,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 17, "id": "5b6de371-efc6-471c-a2b8-3630e1af0749", "metadata": {}, "outputs": [], @@ -982,7 +992,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 18, "id": "56924f81-38ed-4d0e-bbb9-1bded88a1757", "metadata": {}, "outputs": [], @@ -1032,7 +1042,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 19, "id": "3ba0a139-9e29-41c8-ae56-8da9c479ca41", "metadata": { "editable": true, diff --git a/individual_modules/introduction_to_julia/variables.ipynb b/individual_modules/introduction_to_julia/variables.ipynb index ffa364b4..b2fbf903 100644 --- a/individual_modules/introduction_to_julia/variables.ipynb +++ b/individual_modules/introduction_to_julia/variables.ipynb @@ -785,27 +785,35 @@ ] }, { - "cell_type": "code", - "execution_count": 17, - "id": "2f47d33d-a24d-4d80-bfa0-0029b5ed5f07", + "cell_type": "markdown", + "id": "0a6b87d1-14bb-4a7a-bd1a-3fdac5435915", "metadata": {}, - "outputs": [ - { - "ename": "LoadError", - "evalue": "MethodError: \u001b[0mCannot `convert` an object of type \u001b[92mFloat64\u001b[39m\u001b[0m to an object of type \u001b[91mString\u001b[39m\nThe function `convert` exists, but no method is defined for this combination of argument types.\n\n\u001b[0mClosest candidates are:\n\u001b[0m convert(::Type{String}, \u001b[91m::Base.JuliaSyntax.Kind\u001b[39m)\n\u001b[0m\u001b[90m @\u001b[39m \u001b[90mBase\u001b[39m \u001b[90m/Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-honeycrisp-HL2F7YQ3XH.0/build/default-honeycrisp-HL2F7YQ3XH-0/julialang/julia-release-1-dot-11/base/JuliaSyntax/src/\u001b[39m\u001b[90m\u001b[4mkinds.jl:975\u001b[24m\u001b[39m\n\u001b[0m convert(::Type{String}, \u001b[91m::String\u001b[39m)\n\u001b[0m\u001b[90m @\u001b[39m \u001b[90mBase\u001b[39m \u001b[90m\u001b[4messentials.jl:461\u001b[24m\u001b[39m\n\u001b[0m convert(::Type{T}, \u001b[91m::T\u001b[39m) where T<:AbstractString\n\u001b[0m\u001b[90m @\u001b[39m \u001b[90mBase\u001b[39m \u001b[90mstrings/\u001b[39m\u001b[90m\u001b[4mbasic.jl:231\u001b[24m\u001b[39m\n\u001b[0m ...\n", - "output_type": "error", - "traceback": [ - "MethodError: \u001b[0mCannot `convert` an object of type \u001b[92mFloat64\u001b[39m\u001b[0m to an object of type \u001b[91mString\u001b[39m\nThe function `convert` exists, but no method is defined for this combination of argument types.\n\n\u001b[0mClosest candidates are:\n\u001b[0m convert(::Type{String}, \u001b[91m::Base.JuliaSyntax.Kind\u001b[39m)\n\u001b[0m\u001b[90m @\u001b[39m \u001b[90mBase\u001b[39m \u001b[90m/Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-honeycrisp-HL2F7YQ3XH.0/build/default-honeycrisp-HL2F7YQ3XH-0/julialang/julia-release-1-dot-11/base/JuliaSyntax/src/\u001b[39m\u001b[90m\u001b[4mkinds.jl:975\u001b[24m\u001b[39m\n\u001b[0m convert(::Type{String}, \u001b[91m::String\u001b[39m)\n\u001b[0m\u001b[90m @\u001b[39m \u001b[90mBase\u001b[39m \u001b[90m\u001b[4messentials.jl:461\u001b[24m\u001b[39m\n\u001b[0m convert(::Type{T}, \u001b[91m::T\u001b[39m) where T<:AbstractString\n\u001b[0m\u001b[90m @\u001b[39m \u001b[90mBase\u001b[39m \u001b[90mstrings/\u001b[39m\u001b[90m\u001b[4mbasic.jl:231\u001b[24m\u001b[39m\n\u001b[0m ...\n", - "", - "Stacktrace:", - " [1] top-level scope", - "\u001b[90m @\u001b[39m \u001b[90m\u001b[4mIn[17]:2\u001b[24m\u001b[39m" - ] - } - ], "source": [ + "```\n", "# Error -- cannot convert 1.0 to a string\n", - "name = 1.0" + "name = 1.0\n", + "```\n", + "\n", + "produces: \n", + "\n", + "```\n", + "MethodError: Cannot `convert` an object of type Float64 to an object of type String\n", + "The function `convert` exists, but no method is defined for this combination of argument types.\n", + "\n", + "Closest candidates are:\n", + " convert(::Type{String}, ::Base.JuliaSyntax.Kind)\n", + " @ Base /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-honeycrisp-HL2F7YQ3XH.0/build/default-honeycrisp-HL2F7YQ3XH-0/julialang/julia-release-1-dot-11/base/JuliaSyntax/src/kinds.jl:975\n", + " convert(::Type{String}, ::String)\n", + " @ Base essentials.jl:461\n", + " convert(::Type{T}, ::T) where T<:AbstractString\n", + " @ Base strings/basic.jl:231\n", + " ...\n", + "\n", + "\n", + "Stacktrace:\n", + " [1] top-level scope\n", + " @ In[17]:2\n", + "```" ] }, { diff --git a/individual_modules/python_for_data_analysis/images/type-checking.png b/short_courses/figures/python_testing/type-checking.png similarity index 100% rename from individual_modules/python_for_data_analysis/images/type-checking.png rename to short_courses/figures/python_testing/type-checking.png diff --git a/short_courses/python_language_features.ipynb b/short_courses/python_language_features.ipynb index b4b5acdc..b6fb57eb 100644 --- a/short_courses/python_language_features.ipynb +++ b/short_courses/python_language_features.ipynb @@ -174,7 +174,7 @@ "\n", "Copy the following code fragment into your IDE. If type checking is enabled you should see a warning message.\n", "\n", - "![Screenshot of a Python code snippet in Visual Studio Code showing type hints and type checking errors. A dictionary word_countis annotated asdict[str, int]. Assigning a string key 'the'with integer value1is valid, but assigning an integer key2with a string value'error' triggers type errors. The editor highlights mismatched key and value types using Pylance.](images/type-checking.png)\n", + "![Screenshot of a Python code snippet in Visual Studio Code showing type hints and type checking errors. A dictionary word_countis annotated asdict[str, int]. Assigning a string key 'the'with integer value1is valid, but assigning an integer key2with a string value'error' triggers type errors. The editor highlights mismatched key and value types using Pylance.](figures/python_testing/type-checking.png)\n", "\n", "Without making any changes, try running the code." ] @@ -356,9 +356,9 @@ "output_type": "stream", "text": [ "Traceback (most recent call last):\n", - " File \"/var/folders/79/nkc7chg17vz5kdlf2mdlh8zw0000gq/T/ipykernel_66791/2841111012.py\", line 11, in \n", + " File \"/var/folders/r7/wblx0jw96hz08nvjz9p3zsgr0000gp/T/ipykernel_2856/2841111012.py\", line 11, in \n", " always_bad()\n", - " File \"/var/folders/79/nkc7chg17vz5kdlf2mdlh8zw0000gq/T/ipykernel_66791/2841111012.py\", line 8, in always_bad\n", + " File \"/var/folders/r7/wblx0jw96hz08nvjz9p3zsgr0000gp/T/ipykernel_2856/2841111012.py\", line 8, in always_bad\n", " raise Exception(\"Never happy\")\n", "Exception: Never happy\n", "\n", @@ -398,10 +398,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "10fbc05b", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "8\n" + ] + } + ], "source": [ "add = lambda x, y: x + y\n", "print(add(5, 3))" @@ -437,7 +445,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "id": "c5dd17b6", "metadata": {}, "outputs": [ @@ -477,7 +485,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "id": "5519293c", "metadata": {}, "outputs": [ @@ -485,7 +493,7 @@ "name": "stdout", "output_type": "stream", "text": [ - " at 0x107110ee0>\n" + " at 0x105d0aeb0>\n" ] } ], @@ -516,7 +524,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "id": "57b85794-9225-488f-9cc8-fb2771e146a2", "metadata": {}, "outputs": [ @@ -549,7 +557,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "id": "63ec21eb", "metadata": {}, "outputs": [ @@ -583,7 +591,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 13, "id": "0ed2e755", "metadata": {}, "outputs": [ @@ -615,7 +623,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 14, "id": "9a8d1051", "metadata": {}, "outputs": [ @@ -624,9 +632,8 @@ "output_type": "stream", "text": [ "Traceback (most recent call last):\n", - " File \"/var/folders/79/nkc7chg17vz5kdlf2mdlh8zw0000gq/T/ipykernel_66791/679916601.py\", line 5, in \n", + " File \"/var/folders/r7/wblx0jw96hz08nvjz9p3zsgr0000gp/T/ipykernel_2856/679916601.py\", line 5, in \n", " print(len(data))\n", - " ^^^^^^^^^\n", "TypeError: object of type '_io.TextIOWrapper' has no len()\n" ] } @@ -643,7 +650,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 15, "id": "9a084827", "metadata": {}, "outputs": [ @@ -697,7 +704,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 16, "id": "a73b9b72", "metadata": {}, "outputs": [ @@ -726,7 +733,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 17, "id": "37e9a8cd", "metadata": {}, "outputs": [ @@ -775,7 +782,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 18, "id": "d16a9a88", "metadata": {}, "outputs": [ @@ -804,7 +811,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 19, "id": "120164a6", "metadata": {}, "outputs": [ @@ -827,7 +834,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 20, "id": "d35c6ac7", "metadata": {}, "outputs": [ @@ -864,7 +871,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 21, "id": "60e18cd3", "metadata": {}, "outputs": [ @@ -928,7 +935,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 22, "id": "9407e7f7", "metadata": {}, "outputs": [ @@ -956,7 +963,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 23, "id": "63921d3b", "metadata": {}, "outputs": [ @@ -989,7 +996,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 24, "id": "0c7eff02", "metadata": {}, "outputs": [ @@ -1019,7 +1026,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 25, "id": "7c7eb2f0-d2ba-4c68-9ac4-67660e50b968", "metadata": { "editable": true, @@ -1034,13 +1041,13 @@ { "data": { "text/html": [ - "
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": [ - "var questionsxqrfEakBANZb=[\n", - " {\n", - " \"question\": \"What is the purpose of type hints in Python?\",\n", - " \"type\": \"many_choice\",\n", - " \"answers\": [\n", - " {\n", - " \"answer\": \"To enforce type checking at runtime\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"To provide hints for IDEs and linters\",\n", - " \"correct\": true,\n", - " \"feedback\": \"Correct\"\n", - " },\n", - " {\n", - " \"answer\": \"To automatically convert types\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"To improve code execution speed\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " }\n", - " ]\n", - " },\n", - " {\n", - " \"question\": \"Which of the following best describes a decorator in Python?\",\n", - " \"type\": \"many_choice\",\n", - " \"answers\": [\n", - " {\n", - " \"answer\": \"A function that returns another function\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"A function that modifies the behaviour of another function\",\n", - " \"correct\": true,\n", - " \"feedback\": \"Correct\"\n", - " },\n", - " {\n", - " \"answer\": \"A function that creates new types\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"A function that adds type hints to another function\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " }\n", - " ]\n", - " },\n", - " {\n", - " \"question\": \"What is the advantage of using generator expression in Python?\",\n", - " \"type\": \"many_choice\",\n", - " \"answers\": [\n", - " {\n", - " \"answer\": \"They store all values in memory\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"They provide a concise way to create generators without using def and yield\",\n", - " \"correct\": true,\n", - " \"feedback\": \"Correct\"\n", - " },\n", - " {\n", - " \"answer\": \"They automatically sort the values\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"They ensure type safety\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " }\n", - " ]\n", - " }\n", - "];\n", - " // Make a random ID\n", - "function makeid(length) {\n", - " var result = [];\n", - " var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';\n", - " var charactersLength = characters.length;\n", - " for (var i = 0; i < length; i++) {\n", - " result.push(characters.charAt(Math.floor(Math.random() * charactersLength)));\n", - " }\n", - " return result.join('');\n", - "}\n", - "\n", - "// Choose a random subset of an array. Can also be used to shuffle the array\n", - "function getRandomSubarray(arr, size) {\n", - " var shuffled = arr.slice(0), i = arr.length, temp, index;\n", - " while (i--) {\n", - " index = Math.floor((i + 1) * Math.random());\n", - " temp = shuffled[index];\n", - " shuffled[index] = shuffled[i];\n", - " shuffled[i] = temp;\n", - " }\n", - " return shuffled.slice(0, size);\n", - "}\n", - "\n", - "function printResponses(responsesContainer) {\n", - " var responses=JSON.parse(responsesContainer.dataset.responses);\n", - " var stringResponses='IMPORTANT!To preserve this answer sequence for submission, when you have finalized your answers:
  1. Copy the text in this cell below \"Answer String\"
  2. Double click on the cell directly below the Answer String, labeled \"Replace Me\"
  3. Select the whole \"Replace Me\" text
  4. Paste in your answer string and press shift-Enter.
  5. Save the notebook using the save icon or File->Save Notebook menu item



  6. Answer String:
    ';\n", - " console.log(responses);\n", - " responses.forEach((response, index) => {\n", - " if (response) {\n", - " console.log(index + ': ' + response);\n", - " stringResponses+= index + ': ' + response +\"
    \";\n", - " }\n", - " });\n", - " responsesContainer.innerHTML=stringResponses;\n", - "}\n", - "function check_mc() {\n", - " var id = this.id.split('-')[0];\n", - " //var response = this.id.split('-')[1];\n", - " //console.log(response);\n", - " //console.log(\"In check_mc(), id=\"+id);\n", - " //console.log(event.srcElement.id) \n", - " //console.log(event.srcElement.dataset.correct) \n", - " //console.log(event.srcElement.dataset.feedback)\n", - "\n", - " var label = event.srcElement;\n", - " //console.log(label, label.nodeName);\n", - " var depth = 0;\n", - " while ((label.nodeName != \"LABEL\") && (depth < 20)) {\n", - " label = label.parentElement;\n", - " console.log(depth, label);\n", - " depth++;\n", - " }\n", - "\n", - "\n", - "\n", - " var answers = label.parentElement.children;\n", - "\n", - " //console.log(answers);\n", - "\n", - "\n", - " // Split behavior based on multiple choice vs many choice:\n", - " var fb = document.getElementById(\"fb\" + id);\n", - "\n", - "\n", - "\n", - "\n", - " if (fb.dataset.numcorrect == 1) {\n", - " // What follows is for the saved responses stuff\n", - " var outerContainer = fb.parentElement.parentElement;\n", - " var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n", - " if (responsesContainer) {\n", - " //console.log(responsesContainer);\n", - " var response = label.firstChild.innerText;\n", - " if (label.querySelector(\".QuizCode\")){\n", - " response+= label.querySelector(\".QuizCode\").firstChild.innerText;\n", - " }\n", - " console.log(response);\n", - " //console.log(document.getElementById(\"quizWrap\"+id));\n", - " var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n", - " console.log(\"Question \" + qnum);\n", - " //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n", - " var responses=JSON.parse(responsesContainer.dataset.responses);\n", - " console.log(responses);\n", - " responses[qnum]= response;\n", - " responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n", - " printResponses(responsesContainer);\n", - " }\n", - " // End code to preserve responses\n", - " \n", - " for (var i = 0; i < answers.length; i++) {\n", - " var child = answers[i];\n", - " //console.log(child);\n", - " child.className = \"MCButton\";\n", - " }\n", - "\n", - "\n", - "\n", - " if (label.dataset.correct == \"true\") {\n", - " // console.log(\"Correct action\");\n", - " if (\"feedback\" in label.dataset) {\n", - " fb.textContent = jaxify(label.dataset.feedback);\n", - " } else {\n", - " fb.textContent = \"Correct!\";\n", - " }\n", - " label.classList.add(\"correctButton\");\n", - "\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"correct\");\n", - "\n", - " } else {\n", - " if (\"feedback\" in label.dataset) {\n", - " fb.textContent = jaxify(label.dataset.feedback);\n", - " } else {\n", - " fb.textContent = \"Incorrect -- try again.\";\n", - " }\n", - " //console.log(\"Error action\");\n", - " label.classList.add(\"incorrectButton\");\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"incorrect\");\n", - " }\n", - " }\n", - " else {\n", - " var reset = false;\n", - " var feedback;\n", - " if (label.dataset.correct == \"true\") {\n", - " if (\"feedback\" in label.dataset) {\n", - " feedback = jaxify(label.dataset.feedback);\n", - " } else {\n", - " feedback = \"Correct!\";\n", - " }\n", - " if (label.dataset.answered <= 0) {\n", - " if (fb.dataset.answeredcorrect < 0) {\n", - " fb.dataset.answeredcorrect = 1;\n", - " reset = true;\n", - " } else {\n", - " fb.dataset.answeredcorrect++;\n", - " }\n", - " if (reset) {\n", - " for (var i = 0; i < answers.length; i++) {\n", - " var child = answers[i];\n", - " child.className = \"MCButton\";\n", - " child.dataset.answered = 0;\n", - " }\n", - " }\n", - " label.classList.add(\"correctButton\");\n", - " label.dataset.answered = 1;\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"correct\");\n", - "\n", - " }\n", - " } else {\n", - " if (\"feedback\" in label.dataset) {\n", - " feedback = jaxify(label.dataset.feedback);\n", - " } else {\n", - " feedback = \"Incorrect -- try again.\";\n", - " }\n", - " if (fb.dataset.answeredcorrect > 0) {\n", - " fb.dataset.answeredcorrect = -1;\n", - " reset = true;\n", - " } else {\n", - " fb.dataset.answeredcorrect--;\n", - " }\n", - "\n", - " if (reset) {\n", - " for (var i = 0; i < answers.length; i++) {\n", - " var child = answers[i];\n", - " child.className = \"MCButton\";\n", - " child.dataset.answered = 0;\n", - " }\n", - " }\n", - " label.classList.add(\"incorrectButton\");\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"incorrect\");\n", - " }\n", - " // What follows is for the saved responses stuff\n", - " var outerContainer = fb.parentElement.parentElement;\n", - " var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n", - " if (responsesContainer) {\n", - " //console.log(responsesContainer);\n", - " var response = label.firstChild.innerText;\n", - " if (label.querySelector(\".QuizCode\")){\n", - " response+= label.querySelector(\".QuizCode\").firstChild.innerText;\n", - " }\n", - " console.log(response);\n", - " //console.log(document.getElementById(\"quizWrap\"+id));\n", - " var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n", - " console.log(\"Question \" + qnum);\n", - " //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n", - " var responses=JSON.parse(responsesContainer.dataset.responses);\n", - " if (label.dataset.correct == \"true\") {\n", - " if (typeof(responses[qnum]) == \"object\"){\n", - " if (!responses[qnum].includes(response))\n", - " responses[qnum].push(response);\n", - " } else{\n", - " responses[qnum]= [ response ];\n", - " }\n", - " } else {\n", - " responses[qnum]= response;\n", - " }\n", - " console.log(responses);\n", - " responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n", - " printResponses(responsesContainer);\n", - " }\n", - " // End save responses stuff\n", - "\n", - "\n", - "\n", - " var numcorrect = fb.dataset.numcorrect;\n", - " var answeredcorrect = fb.dataset.answeredcorrect;\n", - " if (answeredcorrect >= 0) {\n", - " fb.textContent = feedback + \" [\" + answeredcorrect + \"/\" + numcorrect + \"]\";\n", - " } else {\n", - " fb.textContent = feedback + \" [\" + 0 + \"/\" + numcorrect + \"]\";\n", - " }\n", - "\n", - "\n", - " }\n", - "\n", - " if (typeof MathJax != 'undefined') {\n", - " var version = MathJax.version;\n", - " console.log('MathJax version', version);\n", - " if (version[0] == \"2\") {\n", - " MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n", - " } else if (version[0] == \"3\") {\n", - " MathJax.typeset([fb]);\n", - " }\n", - " } else {\n", - " console.log('MathJax not detected');\n", - " }\n", - "\n", - "}\n", - "\n", - "function make_mc(qa, shuffle_answers, outerqDiv, qDiv, aDiv, id) {\n", - " var shuffled;\n", - " if (shuffle_answers == \"True\") {\n", - " //console.log(shuffle_answers+\" read as true\");\n", - " shuffled = getRandomSubarray(qa.answers, qa.answers.length);\n", - " } else {\n", - " //console.log(shuffle_answers+\" read as false\");\n", - " shuffled = qa.answers;\n", - " }\n", - "\n", - "\n", - " var num_correct = 0;\n", - "\n", - "\n", - "\n", - " shuffled.forEach((item, index, ans_array) => {\n", - " //console.log(answer);\n", - "\n", - " // Make input element\n", - " var inp = document.createElement(\"input\");\n", - " inp.type = \"radio\";\n", - " inp.id = \"quizo\" + id + index;\n", - " inp.style = \"display:none;\";\n", - " aDiv.append(inp);\n", - "\n", - " //Make label for input element\n", - " var lab = document.createElement(\"label\");\n", - " lab.className = \"MCButton\";\n", - " lab.id = id + '-' + index;\n", - " lab.onclick = check_mc;\n", - " var aSpan = document.createElement('span');\n", - " aSpan.classsName = \"\";\n", - " //qDiv.id=\"quizQn\"+id+index;\n", - " if (\"answer\" in item) {\n", - " aSpan.innerHTML = jaxify(item.answer);\n", - " //aSpan.innerHTML=item.answer;\n", - " }\n", - " lab.append(aSpan);\n", - "\n", - " // Create div for code inside question\n", - " var codeSpan;\n", - " if (\"code\" in item) {\n", - " codeSpan = document.createElement('span');\n", - " codeSpan.id = \"code\" + id + index;\n", - " codeSpan.className = \"QuizCode\";\n", - " var codePre = document.createElement('pre');\n", - " codeSpan.append(codePre);\n", - " var codeCode = document.createElement('code');\n", - " codePre.append(codeCode);\n", - " codeCode.innerHTML = item.code;\n", - " lab.append(codeSpan);\n", - " //console.log(codeSpan);\n", - " }\n", - "\n", - " //lab.textContent=item.answer;\n", - "\n", - " // Set the data attributes for the answer\n", - " lab.setAttribute('data-correct', item.correct);\n", - " if (item.correct) {\n", - " num_correct++;\n", - " }\n", - " if (\"feedback\" in item) {\n", - " lab.setAttribute('data-feedback', item.feedback);\n", - " }\n", - " lab.setAttribute('data-answered', 0);\n", - "\n", - " aDiv.append(lab);\n", - "\n", - " });\n", - "\n", - " if (num_correct > 1) {\n", - " outerqDiv.className = \"ManyChoiceQn\";\n", - " } else {\n", - " outerqDiv.className = \"MultipleChoiceQn\";\n", - " }\n", - "\n", - " return num_correct;\n", - "\n", - "}\n", - "function check_numeric(ths, event) {\n", - "\n", - " if (event.keyCode === 13) {\n", - " ths.blur();\n", - "\n", - " var id = ths.id.split('-')[0];\n", - "\n", - " var submission = ths.value;\n", - " if (submission.indexOf('/') != -1) {\n", - " var sub_parts = submission.split('/');\n", - " //console.log(sub_parts);\n", - " submission = sub_parts[0] / sub_parts[1];\n", - " }\n", - " //console.log(\"Reader entered\", submission);\n", - "\n", - " if (\"precision\" in ths.dataset) {\n", - " var precision = ths.dataset.precision;\n", - " // console.log(\"1:\", submission)\n", - " submission = Math.round((1 * submission + Number.EPSILON) * 10 ** precision) / 10 ** precision;\n", - " // console.log(\"Rounded to \", submission, \" precision=\", precision );\n", - " }\n", - "\n", - "\n", - " //console.log(\"In check_numeric(), id=\"+id);\n", - " //console.log(event.srcElement.id) \n", - " //console.log(event.srcElement.dataset.feedback)\n", - "\n", - " var fb = document.getElementById(\"fb\" + id);\n", - " fb.style.display = \"none\";\n", - " fb.textContent = \"Incorrect -- try again.\";\n", - "\n", - " var answers = JSON.parse(ths.dataset.answers);\n", - " //console.log(answers);\n", - "\n", - " var defaultFB = \"\";\n", - " var correct;\n", - " var done = false;\n", - " answers.every(answer => {\n", - " //console.log(answer.type);\n", - "\n", - " correct = false;\n", - " // if (answer.type==\"value\"){\n", - " if ('value' in answer) {\n", - " if (submission == answer.value) {\n", - " if (\"feedback\" in answer) {\n", - " fb.textContent = jaxify(answer.feedback);\n", - " } else {\n", - " fb.textContent = jaxify(\"Correct\");\n", - " }\n", - " correct = answer.correct;\n", - " //console.log(answer.correct);\n", - " done = true;\n", - " }\n", - " // } else if (answer.type==\"range\") {\n", - " } else if ('range' in answer) {\n", - " //console.log(answer.range);\n", - " if ((submission >= answer.range[0]) && (submission < answer.range[1])) {\n", - " fb.textContent = jaxify(answer.feedback);\n", - " correct = answer.correct;\n", - " //console.log(answer.correct);\n", - " done = true;\n", - " }\n", - " } else if (answer.type == \"default\") {\n", - " defaultFB = answer.feedback;\n", - " }\n", - " if (done) {\n", - " return false; // Break out of loop if this has been marked correct\n", - " } else {\n", - " return true; // Keep looking for case that includes this as a correct answer\n", - " }\n", - " });\n", - "\n", - " if ((!done) && (defaultFB != \"\")) {\n", - " fb.innerHTML = jaxify(defaultFB);\n", - " //console.log(\"Default feedback\", defaultFB);\n", - " }\n", - "\n", - " fb.style.display = \"block\";\n", - " if (correct) {\n", - " ths.className = \"Input-text\";\n", - " ths.classList.add(\"correctButton\");\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"correct\");\n", - " } else {\n", - " ths.className = \"Input-text\";\n", - " ths.classList.add(\"incorrectButton\");\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"incorrect\");\n", - " }\n", - "\n", - " // What follows is for the saved responses stuff\n", - " var outerContainer = fb.parentElement.parentElement;\n", - " var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n", - " if (responsesContainer) {\n", - " console.log(submission);\n", - " var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n", - " //console.log(\"Question \" + qnum);\n", - " //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n", - " var responses=JSON.parse(responsesContainer.dataset.responses);\n", - " console.log(responses);\n", - " if (submission == ths.value){\n", - " responses[qnum]= submission;\n", - " } else {\n", - " responses[qnum]= ths.value + \"(\" + submission +\")\";\n", - " }\n", - " responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n", - " printResponses(responsesContainer);\n", - " }\n", - " // End code to preserve responses\n", - "\n", - " if (typeof MathJax != 'undefined') {\n", - " var version = MathJax.version;\n", - " console.log('MathJax version', version);\n", - " if (version[0] == \"2\") {\n", - " MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n", - " } else if (version[0] == \"3\") {\n", - " MathJax.typeset([fb]);\n", - " }\n", - " } else {\n", - " console.log('MathJax not detected');\n", - " }\n", - " return false;\n", - " }\n", - "\n", - "}\n", - "\n", - "function isValid(el, charC) {\n", - " //console.log(\"Input char: \", charC);\n", - " if (charC == 46) {\n", - " if (el.value.indexOf('.') === -1) {\n", - " return true;\n", - " } else if (el.value.indexOf('/') != -1) {\n", - " var parts = el.value.split('/');\n", - " if (parts[1].indexOf('.') === -1) {\n", - " return true;\n", - " }\n", - " }\n", - " else {\n", - " return false;\n", - " }\n", - " } else if (charC == 47) {\n", - " if (el.value.indexOf('/') === -1) {\n", - " if ((el.value != \"\") && (el.value != \".\")) {\n", - " return true;\n", - " } else {\n", - " return false;\n", - " }\n", - " } else {\n", - " return false;\n", - " }\n", - " } else if (charC == 45) {\n", - " var edex = el.value.indexOf('e');\n", - " if (edex == -1) {\n", - " edex = el.value.indexOf('E');\n", - " }\n", - "\n", - " if (el.value == \"\") {\n", - " return true;\n", - " } else if (edex == (el.value.length - 1)) { // If just after e or E\n", - " return true;\n", - " } else {\n", - " return false;\n", - " }\n", - " } else if (charC == 101) { // \"e\"\n", - " if ((el.value.indexOf('e') === -1) && (el.value.indexOf('E') === -1) && (el.value.indexOf('/') == -1)) {\n", - " // Prev symbol must be digit or decimal point:\n", - " if (el.value.slice(-1).search(/\\d/) >= 0) {\n", - " return true;\n", - " } else if (el.value.slice(-1).search(/\\./) >= 0) {\n", - " return true;\n", - " } else {\n", - " return false;\n", - " }\n", - " } else {\n", - " return false;\n", - " }\n", - " } else {\n", - " if (charC > 31 && (charC < 48 || charC > 57))\n", - " return false;\n", - " }\n", - " return true;\n", - "}\n", - "\n", - "function numeric_keypress(evnt) {\n", - " var charC = (evnt.which) ? evnt.which : evnt.keyCode;\n", - "\n", - " if (charC == 13) {\n", - " check_numeric(this, evnt);\n", - " } else {\n", - " return isValid(this, charC);\n", - " }\n", - "}\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "function make_numeric(qa, outerqDiv, qDiv, aDiv, id) {\n", - "\n", - "\n", - "\n", - " //console.log(answer);\n", - "\n", - "\n", - " outerqDiv.className = \"NumericQn\";\n", - " aDiv.style.display = 'block';\n", - "\n", - " var lab = document.createElement(\"label\");\n", - " lab.className = \"InpLabel\";\n", - " lab.textContent = \"Type numeric answer here:\";\n", - " aDiv.append(lab);\n", - "\n", - " var inp = document.createElement(\"input\");\n", - " inp.type = \"text\";\n", - " //inp.id=\"input-\"+id;\n", - " inp.id = id + \"-0\";\n", - " inp.className = \"Input-text\";\n", - " inp.setAttribute('data-answers', JSON.stringify(qa.answers));\n", - " if (\"precision\" in qa) {\n", - " inp.setAttribute('data-precision', qa.precision);\n", - " }\n", - " aDiv.append(inp);\n", - " //console.log(inp);\n", - "\n", - " //inp.addEventListener(\"keypress\", check_numeric);\n", - " //inp.addEventListener(\"keypress\", numeric_keypress);\n", - " /*\n", - " inp.addEventListener(\"keypress\", function(event) {\n", - " return numeric_keypress(this, event);\n", - " }\n", - " );\n", - " */\n", - " //inp.onkeypress=\"return numeric_keypress(this, event)\";\n", - " inp.onkeypress = numeric_keypress;\n", - " inp.onpaste = event => false;\n", - "\n", - " inp.addEventListener(\"focus\", function (event) {\n", - " this.value = \"\";\n", - " return false;\n", - " }\n", - " );\n", - "\n", - "\n", - "}\n", - "function jaxify(string) {\n", - " var mystring = string;\n", - "\n", - " var count = 0;\n", - " var loc = mystring.search(/([^\\\\]|^)(\\$)/);\n", - "\n", - " var count2 = 0;\n", - " var loc2 = mystring.search(/([^\\\\]|^)(\\$\\$)/);\n", - "\n", - " //console.log(loc);\n", - "\n", - " while ((loc >= 0) || (loc2 >= 0)) {\n", - "\n", - " /* Have to replace all the double $$ first with current implementation */\n", - " if (loc2 >= 0) {\n", - " if (count2 % 2 == 0) {\n", - " mystring = mystring.replace(/([^\\\\]|^)(\\$\\$)/, \"$1\\\\[\");\n", - " } else {\n", - " mystring = mystring.replace(/([^\\\\]|^)(\\$\\$)/, \"$1\\\\]\");\n", - " }\n", - " count2++;\n", - " } else {\n", - " if (count % 2 == 0) {\n", - " mystring = mystring.replace(/([^\\\\]|^)(\\$)/, \"$1\\\\(\");\n", - " } else {\n", - " mystring = mystring.replace(/([^\\\\]|^)(\\$)/, \"$1\\\\)\");\n", - " }\n", - " count++;\n", - " }\n", - " loc = mystring.search(/([^\\\\]|^)(\\$)/);\n", - " loc2 = mystring.search(/([^\\\\]|^)(\\$\\$)/);\n", - " //console.log(mystring,\", loc:\",loc,\", loc2:\",loc2);\n", - " }\n", - "\n", - " //console.log(mystring);\n", - " return mystring;\n", - "}\n", - "\n", - "\n", - "function show_questions(json, mydiv) {\n", - " console.log('show_questions');\n", - " //var mydiv=document.getElementById(myid);\n", - " var shuffle_questions = mydiv.dataset.shufflequestions;\n", - " var num_questions = mydiv.dataset.numquestions;\n", - " var shuffle_answers = mydiv.dataset.shuffleanswers;\n", - " var max_width = mydiv.dataset.maxwidth;\n", - "\n", - " if (num_questions > json.length) {\n", - " num_questions = json.length;\n", - " }\n", - "\n", - " var questions;\n", - " if ((num_questions < json.length) || (shuffle_questions == \"True\")) {\n", - " //console.log(num_questions+\",\"+json.length);\n", - " questions = getRandomSubarray(json, num_questions);\n", - " } else {\n", - " questions = json;\n", - " }\n", - "\n", - " //console.log(\"SQ: \"+shuffle_questions+\", NQ: \" + num_questions + \", SA: \", shuffle_answers);\n", - "\n", - " // Iterate over questions\n", - " questions.forEach((qa, index, array) => {\n", - " //console.log(qa.question); \n", - "\n", - " var id = makeid(8);\n", - " //console.log(id);\n", - "\n", - "\n", - " // Create Div to contain question and answers\n", - " var iDiv = document.createElement('div');\n", - " //iDiv.id = 'quizWrap' + id + index;\n", - " iDiv.id = 'quizWrap' + id;\n", - " iDiv.className = 'Quiz';\n", - " iDiv.setAttribute('data-qnum', index);\n", - " iDiv.style.maxWidth =max_width+\"px\";\n", - " mydiv.appendChild(iDiv);\n", - " // iDiv.innerHTML=qa.question;\n", - " \n", - " var outerqDiv = document.createElement('div');\n", - " outerqDiv.id = \"OuterquizQn\" + id + index;\n", - " // Create div to contain question part\n", - " var qDiv = document.createElement('div');\n", - " qDiv.id = \"quizQn\" + id + index;\n", - " \n", - " if (qa.question) {\n", - " iDiv.append(outerqDiv);\n", - "\n", - " //qDiv.textContent=qa.question;\n", - " qDiv.innerHTML = jaxify(qa.question);\n", - " outerqDiv.append(qDiv);\n", - " }\n", - "\n", - " // Create div for code inside question\n", - " var codeDiv;\n", - " if (\"code\" in qa) {\n", - " codeDiv = document.createElement('div');\n", - " codeDiv.id = \"code\" + id + index;\n", - " codeDiv.className = \"QuizCode\";\n", - " var codePre = document.createElement('pre');\n", - " codeDiv.append(codePre);\n", - " var codeCode = document.createElement('code');\n", - " codePre.append(codeCode);\n", - " codeCode.innerHTML = qa.code;\n", - " outerqDiv.append(codeDiv);\n", - " //console.log(codeDiv);\n", - " }\n", - "\n", - "\n", - " // Create div to contain answer part\n", - " var aDiv = document.createElement('div');\n", - " aDiv.id = \"quizAns\" + id + index;\n", - " aDiv.className = 'Answer';\n", - " iDiv.append(aDiv);\n", - "\n", - " //console.log(qa.type);\n", - "\n", - " var num_correct;\n", - " if ((qa.type == \"multiple_choice\") || (qa.type == \"many_choice\") ) {\n", - " num_correct = make_mc(qa, shuffle_answers, outerqDiv, qDiv, aDiv, id);\n", - " if (\"answer_cols\" in qa) {\n", - " //aDiv.style.gridTemplateColumns = 'auto '.repeat(qa.answer_cols);\n", - " aDiv.style.gridTemplateColumns = 'repeat(' + qa.answer_cols + ', 1fr)';\n", - " }\n", - " } else if (qa.type == \"numeric\") {\n", - " //console.log(\"numeric\");\n", - " make_numeric(qa, outerqDiv, qDiv, aDiv, id);\n", - " }\n", - "\n", - "\n", - " //Make div for feedback\n", - " var fb = document.createElement(\"div\");\n", - " fb.id = \"fb\" + id;\n", - " //fb.style=\"font-size: 20px;text-align:center;\";\n", - " fb.className = \"Feedback\";\n", - " fb.setAttribute(\"data-answeredcorrect\", 0);\n", - " fb.setAttribute(\"data-numcorrect\", num_correct);\n", - " iDiv.append(fb);\n", - "\n", - "\n", - " });\n", - " var preserveResponses = mydiv.dataset.preserveresponses;\n", - " console.log(preserveResponses);\n", - " console.log(preserveResponses == \"true\");\n", - " if (preserveResponses == \"true\") {\n", - " console.log(preserveResponses);\n", - " // Create Div to contain record of answers\n", - " var iDiv = document.createElement('div');\n", - " iDiv.id = 'responses' + mydiv.id;\n", - " iDiv.className = 'JCResponses';\n", - " // Create a place to store responses as an empty array\n", - " iDiv.setAttribute('data-responses', '[]');\n", - "\n", - " // Dummy Text\n", - " iDiv.innerHTML=\"Select your answers and then follow the directions that will appear here.\"\n", - " //iDiv.className = 'Quiz';\n", - " mydiv.appendChild(iDiv);\n", - " }\n", - "//console.log(\"At end of show_questions\");\n", - " if (typeof MathJax != 'undefined') {\n", - " console.log(\"MathJax version\", MathJax.version);\n", - " var version = MathJax.version;\n", - " setTimeout(function(){\n", - " var version = MathJax.version;\n", - " console.log('After sleep, MathJax version', version);\n", - " if (version[0] == \"2\") {\n", - " MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n", - " } else if (version[0] == \"3\") {\n", - " MathJax.typeset([mydiv]);\n", - " }\n", - " }, 500);\n", - "if (typeof version == 'undefined') {\n", - " } else\n", - " {\n", - " if (version[0] == \"2\") {\n", - " MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n", - " } else if (version[0] == \"3\") {\n", - " MathJax.typeset([mydiv]);\n", - " } else {\n", - " console.log(\"MathJax not found\");\n", - " }\n", - " }\n", - " }\n", - " return false;\n", - "}\n", - "/* This is to handle asynchrony issues in loading Jupyter notebooks\n", - " where the quiz has been previously run. The Javascript was generally\n", - " being run before the div was added to the DOM. I tried to do this\n", - " more elegantly using Mutation Observer, but I didn't get it to work.\n", - "\n", - " Someone more knowledgeable could make this better ;-) */\n", - "\n", - " function try_show() {\n", - " if(document.getElementById(\"xqrfEakBANZb\")) {\n", - " show_questions(questionsxqrfEakBANZb, xqrfEakBANZb); \n", - " } else {\n", - " setTimeout(try_show, 200);\n", - " }\n", - " };\n", - " \n", - " {\n", - " // console.log(element);\n", - "\n", - " //console.log(\"xqrfEakBANZb\");\n", - " // console.log(document.getElementById(\"xqrfEakBANZb\"));\n", - "\n", - " try_show();\n", - " }\n", - " " - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from jupyterquiz import display_quiz\n", - "display_quiz(\"questions/summary_language_features.json\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b0c5e7e3-989b-4a8f-83d2-7238e5d551be", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ab198282-f104-400b-b04b-ac59f4661170", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/short_courses/python_testing.ipynb b/short_courses/python_testing.ipynb index 248b20c0..486e40e1 100644 --- a/short_courses/python_testing.ipynb +++ b/short_courses/python_testing.ipynb @@ -635,1068 +635,6 @@ "* Limit the length of the string to 10 characters." ] }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [ - "remove-input" - ] - }, - "outputs": [ - { - "data": { - "text/html": [ - "
    " - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": [ - "var questionsapPXItAfFLEd=[\n", - " {\n", - " \"question\": \"What is the primary goal of software testing?\",\n", - " \"type\": \"many_choice\",\n", - " \"answers\": [\n", - " {\n", - " \"answer\": \"To prove that the code is free of defects\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"To establish that the software behaves as intended\",\n", - " \"correct\": true,\n", - " \"feedback\": \"Correct\"\n", - " },\n", - " {\n", - " \"answer\": \"To increase the execution speed of the software\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"To ensure the software uses minimal memory\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " }\n", - " ]\n", - " },\n", - " {\n", - " \"question\": \"Which statement correctly describes the Python assert statement?\",\n", - " \"type\": \"many_choice\",\n", - " \"answers\": [\n", - " {\n", - " \"answer\": \"It is used to handle exceptions\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"It verifies that a condition is true and raises an error if it is not\",\n", - " \"correct\": true,\n", - " \"feedback\": \"Correct\"\n", - " },\n", - " {\n", - " \"answer\": \"It is used for logging messages\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"It is a replacement for the if-else statement\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " }\n", - " ]\n", - " },\n", - " {\n", - " \"question\": \"What is Test Driven Development (TDD)?\",\n", - " \"type\": \"many_choice\",\n", - " \"answers\": [\n", - " {\n", - " \"answer\": \"A software testing technique to find bugs in the code\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"An approach to software design here tests are written before the code\",\n", - " \"correct\": true,\n", - " \"feedback\": \"Correct\"\n", - " },\n", - " {\n", - " \"answer\": \"A method to enhance the performance of the software\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " },\n", - " {\n", - " \"answer\": \"A tool used for automating software development\",\n", - " \"correct\": false,\n", - " \"feedback\": \"Incorrect\"\n", - " }\n", - " ]\n", - " }\n", - "];\n", - " // Make a random ID\n", - "function makeid(length) {\n", - " var result = [];\n", - " var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';\n", - " var charactersLength = characters.length;\n", - " for (var i = 0; i < length; i++) {\n", - " result.push(characters.charAt(Math.floor(Math.random() * charactersLength)));\n", - " }\n", - " return result.join('');\n", - "}\n", - "\n", - "// Choose a random subset of an array. Can also be used to shuffle the array\n", - "function getRandomSubarray(arr, size) {\n", - " var shuffled = arr.slice(0), i = arr.length, temp, index;\n", - " while (i--) {\n", - " index = Math.floor((i + 1) * Math.random());\n", - " temp = shuffled[index];\n", - " shuffled[index] = shuffled[i];\n", - " shuffled[i] = temp;\n", - " }\n", - " return shuffled.slice(0, size);\n", - "}\n", - "\n", - "function printResponses(responsesContainer) {\n", - " var responses=JSON.parse(responsesContainer.dataset.responses);\n", - " var stringResponses='IMPORTANT!To preserve this answer sequence for submission, when you have finalized your answers:
    1. Copy the text in this cell below \"Answer String\"
    2. Double click on the cell directly below the Answer String, labeled \"Replace Me\"
    3. Select the whole \"Replace Me\" text
    4. Paste in your answer string and press shift-Enter.
    5. Save the notebook using the save icon or File->Save Notebook menu item



    6. Answer String:
      ';\n", - " console.log(responses);\n", - " responses.forEach((response, index) => {\n", - " if (response) {\n", - " console.log(index + ': ' + response);\n", - " stringResponses+= index + ': ' + response +\"
      \";\n", - " }\n", - " });\n", - " responsesContainer.innerHTML=stringResponses;\n", - "}\n", - "function check_mc() {\n", - " var id = this.id.split('-')[0];\n", - " //var response = this.id.split('-')[1];\n", - " //console.log(response);\n", - " //console.log(\"In check_mc(), id=\"+id);\n", - " //console.log(event.srcElement.id) \n", - " //console.log(event.srcElement.dataset.correct) \n", - " //console.log(event.srcElement.dataset.feedback)\n", - "\n", - " var label = event.srcElement;\n", - " //console.log(label, label.nodeName);\n", - " var depth = 0;\n", - " while ((label.nodeName != \"LABEL\") && (depth < 20)) {\n", - " label = label.parentElement;\n", - " console.log(depth, label);\n", - " depth++;\n", - " }\n", - "\n", - "\n", - "\n", - " var answers = label.parentElement.children;\n", - "\n", - " //console.log(answers);\n", - "\n", - "\n", - " // Split behavior based on multiple choice vs many choice:\n", - " var fb = document.getElementById(\"fb\" + id);\n", - "\n", - "\n", - "\n", - "\n", - " if (fb.dataset.numcorrect == 1) {\n", - " // What follows is for the saved responses stuff\n", - " var outerContainer = fb.parentElement.parentElement;\n", - " var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n", - " if (responsesContainer) {\n", - " //console.log(responsesContainer);\n", - " var response = label.firstChild.innerText;\n", - " if (label.querySelector(\".QuizCode\")){\n", - " response+= label.querySelector(\".QuizCode\").firstChild.innerText;\n", - " }\n", - " console.log(response);\n", - " //console.log(document.getElementById(\"quizWrap\"+id));\n", - " var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n", - " console.log(\"Question \" + qnum);\n", - " //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n", - " var responses=JSON.parse(responsesContainer.dataset.responses);\n", - " console.log(responses);\n", - " responses[qnum]= response;\n", - " responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n", - " printResponses(responsesContainer);\n", - " }\n", - " // End code to preserve responses\n", - " \n", - " for (var i = 0; i < answers.length; i++) {\n", - " var child = answers[i];\n", - " //console.log(child);\n", - " child.className = \"MCButton\";\n", - " }\n", - "\n", - "\n", - "\n", - " if (label.dataset.correct == \"true\") {\n", - " // console.log(\"Correct action\");\n", - " if (\"feedback\" in label.dataset) {\n", - " fb.textContent = jaxify(label.dataset.feedback);\n", - " } else {\n", - " fb.textContent = \"Correct!\";\n", - " }\n", - " label.classList.add(\"correctButton\");\n", - "\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"correct\");\n", - "\n", - " } else {\n", - " if (\"feedback\" in label.dataset) {\n", - " fb.textContent = jaxify(label.dataset.feedback);\n", - " } else {\n", - " fb.textContent = \"Incorrect -- try again.\";\n", - " }\n", - " //console.log(\"Error action\");\n", - " label.classList.add(\"incorrectButton\");\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"incorrect\");\n", - " }\n", - " }\n", - " else {\n", - " var reset = false;\n", - " var feedback;\n", - " if (label.dataset.correct == \"true\") {\n", - " if (\"feedback\" in label.dataset) {\n", - " feedback = jaxify(label.dataset.feedback);\n", - " } else {\n", - " feedback = \"Correct!\";\n", - " }\n", - " if (label.dataset.answered <= 0) {\n", - " if (fb.dataset.answeredcorrect < 0) {\n", - " fb.dataset.answeredcorrect = 1;\n", - " reset = true;\n", - " } else {\n", - " fb.dataset.answeredcorrect++;\n", - " }\n", - " if (reset) {\n", - " for (var i = 0; i < answers.length; i++) {\n", - " var child = answers[i];\n", - " child.className = \"MCButton\";\n", - " child.dataset.answered = 0;\n", - " }\n", - " }\n", - " label.classList.add(\"correctButton\");\n", - " label.dataset.answered = 1;\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"correct\");\n", - "\n", - " }\n", - " } else {\n", - " if (\"feedback\" in label.dataset) {\n", - " feedback = jaxify(label.dataset.feedback);\n", - " } else {\n", - " feedback = \"Incorrect -- try again.\";\n", - " }\n", - " if (fb.dataset.answeredcorrect > 0) {\n", - " fb.dataset.answeredcorrect = -1;\n", - " reset = true;\n", - " } else {\n", - " fb.dataset.answeredcorrect--;\n", - " }\n", - "\n", - " if (reset) {\n", - " for (var i = 0; i < answers.length; i++) {\n", - " var child = answers[i];\n", - " child.className = \"MCButton\";\n", - " child.dataset.answered = 0;\n", - " }\n", - " }\n", - " label.classList.add(\"incorrectButton\");\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"incorrect\");\n", - " }\n", - " // What follows is for the saved responses stuff\n", - " var outerContainer = fb.parentElement.parentElement;\n", - " var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n", - " if (responsesContainer) {\n", - " //console.log(responsesContainer);\n", - " var response = label.firstChild.innerText;\n", - " if (label.querySelector(\".QuizCode\")){\n", - " response+= label.querySelector(\".QuizCode\").firstChild.innerText;\n", - " }\n", - " console.log(response);\n", - " //console.log(document.getElementById(\"quizWrap\"+id));\n", - " var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n", - " console.log(\"Question \" + qnum);\n", - " //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n", - " var responses=JSON.parse(responsesContainer.dataset.responses);\n", - " if (label.dataset.correct == \"true\") {\n", - " if (typeof(responses[qnum]) == \"object\"){\n", - " if (!responses[qnum].includes(response))\n", - " responses[qnum].push(response);\n", - " } else{\n", - " responses[qnum]= [ response ];\n", - " }\n", - " } else {\n", - " responses[qnum]= response;\n", - " }\n", - " console.log(responses);\n", - " responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n", - " printResponses(responsesContainer);\n", - " }\n", - " // End save responses stuff\n", - "\n", - "\n", - "\n", - " var numcorrect = fb.dataset.numcorrect;\n", - " var answeredcorrect = fb.dataset.answeredcorrect;\n", - " if (answeredcorrect >= 0) {\n", - " fb.textContent = feedback + \" [\" + answeredcorrect + \"/\" + numcorrect + \"]\";\n", - " } else {\n", - " fb.textContent = feedback + \" [\" + 0 + \"/\" + numcorrect + \"]\";\n", - " }\n", - "\n", - "\n", - " }\n", - "\n", - " if (typeof MathJax != 'undefined') {\n", - " var version = MathJax.version;\n", - " console.log('MathJax version', version);\n", - " if (version[0] == \"2\") {\n", - " MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n", - " } else if (version[0] == \"3\") {\n", - " MathJax.typeset([fb]);\n", - " }\n", - " } else {\n", - " console.log('MathJax not detected');\n", - " }\n", - "\n", - "}\n", - "\n", - "function make_mc(qa, shuffle_answers, outerqDiv, qDiv, aDiv, id) {\n", - " var shuffled;\n", - " if (shuffle_answers == \"True\") {\n", - " //console.log(shuffle_answers+\" read as true\");\n", - " shuffled = getRandomSubarray(qa.answers, qa.answers.length);\n", - " } else {\n", - " //console.log(shuffle_answers+\" read as false\");\n", - " shuffled = qa.answers;\n", - " }\n", - "\n", - "\n", - " var num_correct = 0;\n", - "\n", - "\n", - "\n", - " shuffled.forEach((item, index, ans_array) => {\n", - " //console.log(answer);\n", - "\n", - " // Make input element\n", - " var inp = document.createElement(\"input\");\n", - " inp.type = \"radio\";\n", - " inp.id = \"quizo\" + id + index;\n", - " inp.style = \"display:none;\";\n", - " aDiv.append(inp);\n", - "\n", - " //Make label for input element\n", - " var lab = document.createElement(\"label\");\n", - " lab.className = \"MCButton\";\n", - " lab.id = id + '-' + index;\n", - " lab.onclick = check_mc;\n", - " var aSpan = document.createElement('span');\n", - " aSpan.classsName = \"\";\n", - " //qDiv.id=\"quizQn\"+id+index;\n", - " if (\"answer\" in item) {\n", - " aSpan.innerHTML = jaxify(item.answer);\n", - " //aSpan.innerHTML=item.answer;\n", - " }\n", - " lab.append(aSpan);\n", - "\n", - " // Create div for code inside question\n", - " var codeSpan;\n", - " if (\"code\" in item) {\n", - " codeSpan = document.createElement('span');\n", - " codeSpan.id = \"code\" + id + index;\n", - " codeSpan.className = \"QuizCode\";\n", - " var codePre = document.createElement('pre');\n", - " codeSpan.append(codePre);\n", - " var codeCode = document.createElement('code');\n", - " codePre.append(codeCode);\n", - " codeCode.innerHTML = item.code;\n", - " lab.append(codeSpan);\n", - " //console.log(codeSpan);\n", - " }\n", - "\n", - " //lab.textContent=item.answer;\n", - "\n", - " // Set the data attributes for the answer\n", - " lab.setAttribute('data-correct', item.correct);\n", - " if (item.correct) {\n", - " num_correct++;\n", - " }\n", - " if (\"feedback\" in item) {\n", - " lab.setAttribute('data-feedback', item.feedback);\n", - " }\n", - " lab.setAttribute('data-answered', 0);\n", - "\n", - " aDiv.append(lab);\n", - "\n", - " });\n", - "\n", - " if (num_correct > 1) {\n", - " outerqDiv.className = \"ManyChoiceQn\";\n", - " } else {\n", - " outerqDiv.className = \"MultipleChoiceQn\";\n", - " }\n", - "\n", - " return num_correct;\n", - "\n", - "}\n", - "function check_numeric(ths, event) {\n", - "\n", - " if (event.keyCode === 13) {\n", - " ths.blur();\n", - "\n", - " var id = ths.id.split('-')[0];\n", - "\n", - " var submission = ths.value;\n", - " if (submission.indexOf('/') != -1) {\n", - " var sub_parts = submission.split('/');\n", - " //console.log(sub_parts);\n", - " submission = sub_parts[0] / sub_parts[1];\n", - " }\n", - " //console.log(\"Reader entered\", submission);\n", - "\n", - " if (\"precision\" in ths.dataset) {\n", - " var precision = ths.dataset.precision;\n", - " // console.log(\"1:\", submission)\n", - " submission = Math.round((1 * submission + Number.EPSILON) * 10 ** precision) / 10 ** precision;\n", - " // console.log(\"Rounded to \", submission, \" precision=\", precision );\n", - " }\n", - "\n", - "\n", - " //console.log(\"In check_numeric(), id=\"+id);\n", - " //console.log(event.srcElement.id) \n", - " //console.log(event.srcElement.dataset.feedback)\n", - "\n", - " var fb = document.getElementById(\"fb\" + id);\n", - " fb.style.display = \"none\";\n", - " fb.textContent = \"Incorrect -- try again.\";\n", - "\n", - " var answers = JSON.parse(ths.dataset.answers);\n", - " //console.log(answers);\n", - "\n", - " var defaultFB = \"\";\n", - " var correct;\n", - " var done = false;\n", - " answers.every(answer => {\n", - " //console.log(answer.type);\n", - "\n", - " correct = false;\n", - " // if (answer.type==\"value\"){\n", - " if ('value' in answer) {\n", - " if (submission == answer.value) {\n", - " if (\"feedback\" in answer) {\n", - " fb.textContent = jaxify(answer.feedback);\n", - " } else {\n", - " fb.textContent = jaxify(\"Correct\");\n", - " }\n", - " correct = answer.correct;\n", - " //console.log(answer.correct);\n", - " done = true;\n", - " }\n", - " // } else if (answer.type==\"range\") {\n", - " } else if ('range' in answer) {\n", - " //console.log(answer.range);\n", - " if ((submission >= answer.range[0]) && (submission < answer.range[1])) {\n", - " fb.textContent = jaxify(answer.feedback);\n", - " correct = answer.correct;\n", - " //console.log(answer.correct);\n", - " done = true;\n", - " }\n", - " } else if (answer.type == \"default\") {\n", - " defaultFB = answer.feedback;\n", - " }\n", - " if (done) {\n", - " return false; // Break out of loop if this has been marked correct\n", - " } else {\n", - " return true; // Keep looking for case that includes this as a correct answer\n", - " }\n", - " });\n", - "\n", - " if ((!done) && (defaultFB != \"\")) {\n", - " fb.innerHTML = jaxify(defaultFB);\n", - " //console.log(\"Default feedback\", defaultFB);\n", - " }\n", - "\n", - " fb.style.display = \"block\";\n", - " if (correct) {\n", - " ths.className = \"Input-text\";\n", - " ths.classList.add(\"correctButton\");\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"correct\");\n", - " } else {\n", - " ths.className = \"Input-text\";\n", - " ths.classList.add(\"incorrectButton\");\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"incorrect\");\n", - " }\n", - "\n", - " // What follows is for the saved responses stuff\n", - " var outerContainer = fb.parentElement.parentElement;\n", - " var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n", - " if (responsesContainer) {\n", - " console.log(submission);\n", - " var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n", - " //console.log(\"Question \" + qnum);\n", - " //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n", - " var responses=JSON.parse(responsesContainer.dataset.responses);\n", - " console.log(responses);\n", - " if (submission == ths.value){\n", - " responses[qnum]= submission;\n", - " } else {\n", - " responses[qnum]= ths.value + \"(\" + submission +\")\";\n", - " }\n", - " responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n", - " printResponses(responsesContainer);\n", - " }\n", - " // End code to preserve responses\n", - "\n", - " if (typeof MathJax != 'undefined') {\n", - " var version = MathJax.version;\n", - " console.log('MathJax version', version);\n", - " if (version[0] == \"2\") {\n", - " MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n", - " } else if (version[0] == \"3\") {\n", - " MathJax.typeset([fb]);\n", - " }\n", - " } else {\n", - " console.log('MathJax not detected');\n", - " }\n", - " return false;\n", - " }\n", - "\n", - "}\n", - "\n", - "function isValid(el, charC) {\n", - " //console.log(\"Input char: \", charC);\n", - " if (charC == 46) {\n", - " if (el.value.indexOf('.') === -1) {\n", - " return true;\n", - " } else if (el.value.indexOf('/') != -1) {\n", - " var parts = el.value.split('/');\n", - " if (parts[1].indexOf('.') === -1) {\n", - " return true;\n", - " }\n", - " }\n", - " else {\n", - " return false;\n", - " }\n", - " } else if (charC == 47) {\n", - " if (el.value.indexOf('/') === -1) {\n", - " if ((el.value != \"\") && (el.value != \".\")) {\n", - " return true;\n", - " } else {\n", - " return false;\n", - " }\n", - " } else {\n", - " return false;\n", - " }\n", - " } else if (charC == 45) {\n", - " var edex = el.value.indexOf('e');\n", - " if (edex == -1) {\n", - " edex = el.value.indexOf('E');\n", - " }\n", - "\n", - " if (el.value == \"\") {\n", - " return true;\n", - " } else if (edex == (el.value.length - 1)) { // If just after e or E\n", - " return true;\n", - " } else {\n", - " return false;\n", - " }\n", - " } else if (charC == 101) { // \"e\"\n", - " if ((el.value.indexOf('e') === -1) && (el.value.indexOf('E') === -1) && (el.value.indexOf('/') == -1)) {\n", - " // Prev symbol must be digit or decimal point:\n", - " if (el.value.slice(-1).search(/\\d/) >= 0) {\n", - " return true;\n", - " } else if (el.value.slice(-1).search(/\\./) >= 0) {\n", - " return true;\n", - " } else {\n", - " return false;\n", - " }\n", - " } else {\n", - " return false;\n", - " }\n", - " } else {\n", - " if (charC > 31 && (charC < 48 || charC > 57))\n", - " return false;\n", - " }\n", - " return true;\n", - "}\n", - "\n", - "function numeric_keypress(evnt) {\n", - " var charC = (evnt.which) ? evnt.which : evnt.keyCode;\n", - "\n", - " if (charC == 13) {\n", - " check_numeric(this, evnt);\n", - " } else {\n", - " return isValid(this, charC);\n", - " }\n", - "}\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "function make_numeric(qa, outerqDiv, qDiv, aDiv, id) {\n", - "\n", - "\n", - "\n", - " //console.log(answer);\n", - "\n", - "\n", - " outerqDiv.className = \"NumericQn\";\n", - " aDiv.style.display = 'block';\n", - "\n", - " var lab = document.createElement(\"label\");\n", - " lab.className = \"InpLabel\";\n", - " lab.textContent = \"Type numeric answer here:\";\n", - " aDiv.append(lab);\n", - "\n", - " var inp = document.createElement(\"input\");\n", - " inp.type = \"text\";\n", - " //inp.id=\"input-\"+id;\n", - " inp.id = id + \"-0\";\n", - " inp.className = \"Input-text\";\n", - " inp.setAttribute('data-answers', JSON.stringify(qa.answers));\n", - " if (\"precision\" in qa) {\n", - " inp.setAttribute('data-precision', qa.precision);\n", - " }\n", - " aDiv.append(inp);\n", - " //console.log(inp);\n", - "\n", - " //inp.addEventListener(\"keypress\", check_numeric);\n", - " //inp.addEventListener(\"keypress\", numeric_keypress);\n", - " /*\n", - " inp.addEventListener(\"keypress\", function(event) {\n", - " return numeric_keypress(this, event);\n", - " }\n", - " );\n", - " */\n", - " //inp.onkeypress=\"return numeric_keypress(this, event)\";\n", - " inp.onkeypress = numeric_keypress;\n", - " inp.onpaste = event => false;\n", - "\n", - " inp.addEventListener(\"focus\", function (event) {\n", - " this.value = \"\";\n", - " return false;\n", - " }\n", - " );\n", - "\n", - "\n", - "}\n", - "function jaxify(string) {\n", - " var mystring = string;\n", - "\n", - " var count = 0;\n", - " var loc = mystring.search(/([^\\\\]|^)(\\$)/);\n", - "\n", - " var count2 = 0;\n", - " var loc2 = mystring.search(/([^\\\\]|^)(\\$\\$)/);\n", - "\n", - " //console.log(loc);\n", - "\n", - " while ((loc >= 0) || (loc2 >= 0)) {\n", - "\n", - " /* Have to replace all the double $$ first with current implementation */\n", - " if (loc2 >= 0) {\n", - " if (count2 % 2 == 0) {\n", - " mystring = mystring.replace(/([^\\\\]|^)(\\$\\$)/, \"$1\\\\[\");\n", - " } else {\n", - " mystring = mystring.replace(/([^\\\\]|^)(\\$\\$)/, \"$1\\\\]\");\n", - " }\n", - " count2++;\n", - " } else {\n", - " if (count % 2 == 0) {\n", - " mystring = mystring.replace(/([^\\\\]|^)(\\$)/, \"$1\\\\(\");\n", - " } else {\n", - " mystring = mystring.replace(/([^\\\\]|^)(\\$)/, \"$1\\\\)\");\n", - " }\n", - " count++;\n", - " }\n", - " loc = mystring.search(/([^\\\\]|^)(\\$)/);\n", - " loc2 = mystring.search(/([^\\\\]|^)(\\$\\$)/);\n", - " //console.log(mystring,\", loc:\",loc,\", loc2:\",loc2);\n", - " }\n", - "\n", - " //console.log(mystring);\n", - " return mystring;\n", - "}\n", - "\n", - "\n", - "function show_questions(json, mydiv) {\n", - " console.log('show_questions');\n", - " //var mydiv=document.getElementById(myid);\n", - " var shuffle_questions = mydiv.dataset.shufflequestions;\n", - " var num_questions = mydiv.dataset.numquestions;\n", - " var shuffle_answers = mydiv.dataset.shuffleanswers;\n", - " var max_width = mydiv.dataset.maxwidth;\n", - "\n", - " if (num_questions > json.length) {\n", - " num_questions = json.length;\n", - " }\n", - "\n", - " var questions;\n", - " if ((num_questions < json.length) || (shuffle_questions == \"True\")) {\n", - " //console.log(num_questions+\",\"+json.length);\n", - " questions = getRandomSubarray(json, num_questions);\n", - " } else {\n", - " questions = json;\n", - " }\n", - "\n", - " //console.log(\"SQ: \"+shuffle_questions+\", NQ: \" + num_questions + \", SA: \", shuffle_answers);\n", - "\n", - " // Iterate over questions\n", - " questions.forEach((qa, index, array) => {\n", - " //console.log(qa.question); \n", - "\n", - " var id = makeid(8);\n", - " //console.log(id);\n", - "\n", - "\n", - " // Create Div to contain question and answers\n", - " var iDiv = document.createElement('div');\n", - " //iDiv.id = 'quizWrap' + id + index;\n", - " iDiv.id = 'quizWrap' + id;\n", - " iDiv.className = 'Quiz';\n", - " iDiv.setAttribute('data-qnum', index);\n", - " iDiv.style.maxWidth =max_width+\"px\";\n", - " mydiv.appendChild(iDiv);\n", - " // iDiv.innerHTML=qa.question;\n", - " \n", - " var outerqDiv = document.createElement('div');\n", - " outerqDiv.id = \"OuterquizQn\" + id + index;\n", - " // Create div to contain question part\n", - " var qDiv = document.createElement('div');\n", - " qDiv.id = \"quizQn\" + id + index;\n", - " \n", - " if (qa.question) {\n", - " iDiv.append(outerqDiv);\n", - "\n", - " //qDiv.textContent=qa.question;\n", - " qDiv.innerHTML = jaxify(qa.question);\n", - " outerqDiv.append(qDiv);\n", - " }\n", - "\n", - " // Create div for code inside question\n", - " var codeDiv;\n", - " if (\"code\" in qa) {\n", - " codeDiv = document.createElement('div');\n", - " codeDiv.id = \"code\" + id + index;\n", - " codeDiv.className = \"QuizCode\";\n", - " var codePre = document.createElement('pre');\n", - " codeDiv.append(codePre);\n", - " var codeCode = document.createElement('code');\n", - " codePre.append(codeCode);\n", - " codeCode.innerHTML = qa.code;\n", - " outerqDiv.append(codeDiv);\n", - " //console.log(codeDiv);\n", - " }\n", - "\n", - "\n", - " // Create div to contain answer part\n", - " var aDiv = document.createElement('div');\n", - " aDiv.id = \"quizAns\" + id + index;\n", - " aDiv.className = 'Answer';\n", - " iDiv.append(aDiv);\n", - "\n", - " //console.log(qa.type);\n", - "\n", - " var num_correct;\n", - " if ((qa.type == \"multiple_choice\") || (qa.type == \"many_choice\") ) {\n", - " num_correct = make_mc(qa, shuffle_answers, outerqDiv, qDiv, aDiv, id);\n", - " if (\"answer_cols\" in qa) {\n", - " //aDiv.style.gridTemplateColumns = 'auto '.repeat(qa.answer_cols);\n", - " aDiv.style.gridTemplateColumns = 'repeat(' + qa.answer_cols + ', 1fr)';\n", - " }\n", - " } else if (qa.type == \"numeric\") {\n", - " //console.log(\"numeric\");\n", - " make_numeric(qa, outerqDiv, qDiv, aDiv, id);\n", - " }\n", - "\n", - "\n", - " //Make div for feedback\n", - " var fb = document.createElement(\"div\");\n", - " fb.id = \"fb\" + id;\n", - " //fb.style=\"font-size: 20px;text-align:center;\";\n", - " fb.className = \"Feedback\";\n", - " fb.setAttribute(\"data-answeredcorrect\", 0);\n", - " fb.setAttribute(\"data-numcorrect\", num_correct);\n", - " iDiv.append(fb);\n", - "\n", - "\n", - " });\n", - " var preserveResponses = mydiv.dataset.preserveresponses;\n", - " console.log(preserveResponses);\n", - " console.log(preserveResponses == \"true\");\n", - " if (preserveResponses == \"true\") {\n", - " console.log(preserveResponses);\n", - " // Create Div to contain record of answers\n", - " var iDiv = document.createElement('div');\n", - " iDiv.id = 'responses' + mydiv.id;\n", - " iDiv.className = 'JCResponses';\n", - " // Create a place to store responses as an empty array\n", - " iDiv.setAttribute('data-responses', '[]');\n", - "\n", - " // Dummy Text\n", - " iDiv.innerHTML=\"Select your answers and then follow the directions that will appear here.\"\n", - " //iDiv.className = 'Quiz';\n", - " mydiv.appendChild(iDiv);\n", - " }\n", - "//console.log(\"At end of show_questions\");\n", - " if (typeof MathJax != 'undefined') {\n", - " console.log(\"MathJax version\", MathJax.version);\n", - " var version = MathJax.version;\n", - " setTimeout(function(){\n", - " var version = MathJax.version;\n", - " console.log('After sleep, MathJax version', version);\n", - " if (version[0] == \"2\") {\n", - " MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n", - " } else if (version[0] == \"3\") {\n", - " MathJax.typeset([mydiv]);\n", - " }\n", - " }, 500);\n", - "if (typeof version == 'undefined') {\n", - " } else\n", - " {\n", - " if (version[0] == \"2\") {\n", - " MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n", - " } else if (version[0] == \"3\") {\n", - " MathJax.typeset([mydiv]);\n", - " } else {\n", - " console.log(\"MathJax not found\");\n", - " }\n", - " }\n", - " }\n", - " return false;\n", - "}\n", - "/* This is to handle asynchrony issues in loading Jupyter notebooks\n", - " where the quiz has been previously run. The Javascript was generally\n", - " being run before the div was added to the DOM. I tried to do this\n", - " more elegantly using Mutation Observer, but I didn't get it to work.\n", - "\n", - " Someone more knowledgeable could make this better ;-) */\n", - "\n", - " function try_show() {\n", - " if(document.getElementById(\"apPXItAfFLEd\")) {\n", - " show_questions(questionsapPXItAfFLEd, apPXItAfFLEd); \n", - " } else {\n", - " setTimeout(try_show, 200);\n", - " }\n", - " };\n", - " \n", - " {\n", - " // console.log(element);\n", - "\n", - " //console.log(\"apPXItAfFLEd\");\n", - " // console.log(document.getElementById(\"apPXItAfFLEd\"));\n", - "\n", - " try_show();\n", - " }\n", - " " - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from jupyterquiz import display_quiz\n", - "display_quiz(\"questions/summary_testing.json\")" - ] - }, { "cell_type": "code", "execution_count": null, From 6abf8dc079ab047fc2eebf121e844cc920b09330 Mon Sep 17 00:00:00 2001 From: Liam J Berrisford Date: Wed, 13 Aug 2025 11:20:43 +0100 Subject: [PATCH 8/8] Remove image for text for accessibility --- .../figures/python_testing/type-checking.png | Bin 64502 -> 0 bytes short_courses/python_language_features.ipynb | 18 +++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) delete mode 100644 short_courses/figures/python_testing/type-checking.png diff --git a/short_courses/figures/python_testing/type-checking.png b/short_courses/figures/python_testing/type-checking.png deleted file mode 100644 index 3cbd29553b8e3e30042768f5459c04712561d278..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64502 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�u}Y!UuJ<|-$LJ>?blfh*TDrlY?D}7e=hQ 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 B5u5-3 diff --git a/short_courses/python_language_features.ipynb b/short_courses/python_language_features.ipynb index 7f03f834..82b34b1e 100644 --- a/short_courses/python_language_features.ipynb +++ b/short_courses/python_language_features.ipynb @@ -174,7 +174,23 @@ "\n", "Copy the following code fragment into your IDE. If type checking is enabled you should see a warning message.\n", "\n", - "![Screenshot of a Python code snippet in Visual Studio Code showing type hints and type checking errors. A dictionary word_countis annotated asdict[str, int]. Assigning a string key 'the'with integer value1is valid, but assigning an integer key2with a string value'error' triggers type errors. The editor highlights mismatched key and value types using Pylance.](figures/python_testing/type-checking.png)\n", + "```python\n", + "word_count: \"dict[str,int]\" = {}\n", + "\n", + "word_count['the'] = 1\n", + "word_count[2] = 'error'\n", + "```\n", + "\n", + "```\n", + "Argument of type \"Literal[2]\" cannot be assigned to parameter \"key\" of type \"str\" in function \"__setitem__\"\n", + " \"Literal[2]\" is incompatible with \"str\" Pylance(reportArgumentType)\n", + "\n", + "Argument of type \"Literal['error']\" cannot be assigned to parameter \"value\" of type \"int\" in function \"__setitem__\"\n", + " \"Literal['error']\" is incompatible with \"int\" Pylance(reportArgumentType)\n", + "\n", + "(variable) word_count: dict[str, int]\n", + "```\n", + "\n", "\n", "Without making any changes, try running the code." ]