From a2148c2ef7b9658f0f96b9aeeea437679a645ad8 Mon Sep 17 00:00:00 2001 From: Repo Updater <noreply@mpcdf.mpg.de> Date: Tue, 26 Nov 2024 07:15:33 +0100 Subject: [PATCH] e7cc044e final tweaks for Python recap --- environment.yml | 1 + notebooks/01--Introduction.ipynb | 39 ++- notebooks/03--Python_Refresher.ipynb | 486 ++++++++++++++++++--------- notebooks/05--NumPy_SciPy.ipynb | 12 +- 4 files changed, 355 insertions(+), 183 deletions(-) diff --git a/environment.yml b/environment.yml index 6a5003d..85713b0 100644 --- a/environment.yml +++ b/environment.yml @@ -13,6 +13,7 @@ dependencies: - libopenblas=*=*openmp* - numpy - scipy + - pooch - cython - pybind11 - pandas diff --git a/notebooks/01--Introduction.ipynb b/notebooks/01--Introduction.ipynb index fcaac67..59aaaa7 100644 --- a/notebooks/01--Introduction.ipynb +++ b/notebooks/01--Introduction.ipynb @@ -33,7 +33,7 @@ "* Efficiency with respect to development effort: \n", " $\\rightarrow$ Python helps you to get \"things done\" quickly and focus on your science.\n", "* Efficiency with respect to hardware utilization: \n", - " $\\rightarrow$ Python-based codes may perform well if implemented properly.\n", + " $\\rightarrow$ Python-based codes can perform well if implemented properly.\n", "* Using Python may achieve a good overall efficiency for small- to medium-scale codes\n", "* And finally ... Python is already there, so we have do deal with it!" ] @@ -72,7 +72,7 @@ "source": [ "## Use cases often relevant to our audience\n", "\n", - "* prototype implementations of numerical or AI methods that should run (much) faster when going towards production\n", + "* prototype implementations of numerical or AI code that should run (much) faster when moving towards production\n", "* data analysis scripts that should run faster and/or operate in parallel\n", "* IO-handling and processing of large numerical data\n", "\n", @@ -87,7 +87,7 @@ } }, "source": [ - "## Scope of this tutorial\n", + "## Scope of this course\n", "* Learn about the tools and techniques to write efficient Python code for scientific computing\n", "" ] @@ -103,7 +103,7 @@ "## Course Outline\n", "\n", "* Introduction\n", - "* Refresher of Python and the Python Ecosystem\n", + "* Quick refresher of Python and the Python Ecosystem\n", "* Basics of High Performance Computing\n", "* Scientific Computing with Python: NumPy and SciPy\n", "* Performance: Cython, JIT (Numba, JAX), C/Fortran interfacing\n", @@ -119,7 +119,8 @@ } }, "source": [ - "### *Python for HPC* complements advanced HPC courses\n", + "## *Python for HPC* complements advanced HPC courses\n", + "\n", "* We cannot cover traditional HPC topics in depth, and would highly recommend the following courses\n", " * Node-level performance engineering\n", " * Parallel programming with MPI\n", @@ -136,7 +137,7 @@ } }, "source": [ - "## About this Python for HPC tutorial\n", + "## About this Python for HPC course\n", "\n", "* Practical hands-on approach with code examples\n", "* Presentation is based on Jupyter notebooks\n", @@ -174,7 +175,7 @@ "source": [ "### Software Option 1: Cloud-based MPCDF Jupyter notebooks\n", "\n", - "* Use the link communicated by email to access a Jupyter service on the MPCDF HPC cloud\n", + "* Use the link communicated by email to access a Jupyter service in the MPCDF HPC cloud\n", "* The course material *and* software are provided via an interactive JupyterLab interface\n", "* Each instance provides access to several virtual CPU cores and a few GB of RAM\n", "* Please keep the following points in mind\n", @@ -194,10 +195,12 @@ "### Software Option 2: Python infrastructure on the MPCDF HPC systems\n", "* Python is provided via conda-based Python distributions (now based on 'conda-forge', historically Anaconda)\n", "* software is accessible via environment modules, e.g. \n", - " `module purge` \n", - " `module load gcc/12 impi/2021.9` \n", - " `module load anaconda/3/2023.03` \n", - " `module load mpi4py/3.1.4`" + "```bash\n", + "$ module purge\n", + "$ module load gcc/12 impi/2021.9\n", + "$ module load anaconda/3/2023.03\n", + "$ module load mpi4py/3.1.4\n", + "```" ] }, { @@ -209,9 +212,21 @@ }, "source": [ "### Software Option 3: Python environment for your local computer\n", + "\n", "* On a recent Linux system, install all the necessary packages via the package manager and `pip`\n", - "* Alternatively, install [Miniforge](https://conda-forge.org/miniforge/) and use the `conda` package manager and the file `environment.yml` that is provided together with the course material to add all necessary packages" + "* Alternatively, install [Miniforge](https://conda-forge.org/miniforge/) and use the `conda` package manager and the file `environment.yml` that is provided together with the course material to add all necessary packages. \n", + "```bash\n", + "$ conda env create --file environment.yml\n", + "$ conda activate pyhpc\n", + "```" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/notebooks/03--Python_Refresher.ipynb b/notebooks/03--Python_Refresher.ipynb index bf2a971..f893f92 100644 --- a/notebooks/03--Python_Refresher.ipynb +++ b/notebooks/03--Python_Refresher.ipynb @@ -45,7 +45,7 @@ } }, "source": [ - "### Python Language Key Features\n", + "### Python Key Language Features\n", "* high-level language, extensive standard library and ecosystem\n", "* no type declarations, types are tracked at runtime \n", " $\\rightarrow$ code is interpreted in most implementations (or just-in-time compiled) \n", @@ -97,8 +97,7 @@ " * press \"Shift + Enter\" to execute the current cell\n", " * select \"Cell\" $\\to$ \"Run all\" from the menu to run the complete notebook\n", "* notebook export to Python source file works via \"File\" $\\to$ \"Download as\"\n", - "* [papermill](https://papermill.readthedocs.io/en/latest/) allows to run notebooks in 'headless' mode without user interaction (e.g. in a batch job)\n", - "* locally, launch via `jupyter notebook` or `jupyter lab` from a terminal\n", + "* locally, launch via `jupyter lab` or `jupyter notebook` from a terminal\n", "* https://jupyter.org" ] }, @@ -137,7 +136,7 @@ "```python\n", "a = 5\n", "```\n", - "* in Python everything is an object, i.e. contains data along with attributes and methods \n", + "* in Python, nearly everything is an object, i.e. contains data along with attributes and methods \n", " * immutable objects may not change once created, e.g. integer, float, boolean, string, tuple\n", " * mutable objects may change in place, e.g. list, set, dictionary, most user-defined classes\n", " * if unsure, check via the object ID (memory location in cPython)" @@ -472,7 +471,7 @@ " `if` ... `elif` ... `else`\n", "* loops\n", " * `for` $-$ used to repeat a block of code a fixed number of times, used in combination with an iterable object (`range()`, list, etc.)\n", - " * `while` $-$ used to repeat a block of code as long as a condition is satisfied\n", + " * `while` $-$ used to repeat a block of code as long as a condition is `True`\n", "* loop modifier statements\n", " * `break`\n", " * `continue`\n", @@ -667,64 +666,6 @@ "print(f\"l = {l}\")" ] }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "### Classes\n", - "* classes bundle data and functionality together, are key to object oriented programming\n", - "* Python supports classes and related functionality, among others\n", - " * methods\n", - " * class and instance variables\n", - " * inheritance\n", - "* unintended side effects may be caused by mutable class variables (see example)\n", - "* https://docs.python.org/3.11/tutorial/classes.html" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "shared = ['cat'], private = ['dog']\n", - "shared = ['cat', 'cat'], private = ['dog']\n" - ] - } - ], - "source": [ - "class myClass():\n", - " \"\"\"A simple example class.\"\"\"\n", - " shared = [] # class variable, shared by all instances\n", - " \n", - " def __init__(self): # constructor\n", - " self.private = [] # per-instance variable\n", - " \n", - " def show(self):\n", - " print(\"shared = {}, private = {}\".format(self.shared, self.private))\n", - "\n", - "x = myClass()\n", - "x.shared.append(\"cat\")\n", - "x.private.append(\"dog\")\n", - "x.show()\n", - "\n", - "y = myClass()\n", - "y.shared.append(\"cat\")\n", - "y.private.append(\"dog\")\n", - "y.show()" - ] - }, { "cell_type": "markdown", "metadata": { @@ -813,6 +754,64 @@ "say_hello(\"Peter\")" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "### Classes\n", + "* classes bundle data and functionality together, are key to object oriented programming\n", + "* Python supports classes and related functionality, among others\n", + " * methods\n", + " * class and instance variables\n", + " * inheritance\n", + "* unintended side effects may be caused by mutable class variables (see example)\n", + "* https://docs.python.org/3.11/tutorial/classes.html" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "shared = ['cat'], private = ['dog']\n", + "shared = ['cat', 'cat'], private = ['dog']\n" + ] + } + ], + "source": [ + "class myClass():\n", + " \"\"\"A simple example class.\"\"\"\n", + " shared = [] # class variable, shared by all instances\n", + " \n", + " def __init__(self): # constructor\n", + " self.private = [] # per-instance variable\n", + " \n", + " def show(self):\n", + " print(\"shared = {}, private = {}\".format(self.shared, self.private))\n", + "\n", + "x = myClass()\n", + "x.shared.append(\"cat\")\n", + "x.private.append(\"dog\")\n", + "x.show()\n", + "\n", + "y = myClass()\n", + "y.shared.append(\"cat\")\n", + "y.private.append(\"dog\")\n", + "y.show()" + ] + }, { "cell_type": "markdown", "metadata": { @@ -998,6 +997,113 @@ "sum(first_n_sq_gen_expr)" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "### Basic file IO" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "# naive way: write to a text file\n", + "file_name = \"/tmp/dummy.txt\"\n", + "fh = open(file_name, 'w')\n", + "fh.write(\"Hello\\n\")\n", + "fh.close()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "# better: write to a text file, close file handle implicitly (ContextManager)\n", + "with open(file_name, 'a') as fh:\n", + " fh.write(\"World\\n\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "#### Background information on the `with` statement and context managers\n", + "\n", + "* https://docs.python.org/3/reference/compound_stmts.html#the-with-statement\n", + "* https://docs.python.org/3/reference/datamodel.html#with-statement-context-managers\n", + "* https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['Hello\\n', 'World\\n']\n" + ] + } + ], + "source": [ + "# read the complete file into a list in memory\n", + "with open(file_name, 'r') as fh:\n", + " lines = fh.readlines()\n", + "print(lines)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello\n", + "World\n" + ] + } + ], + "source": [ + "# when reading, the file handle `fh` is actually an iterator on the lines of the file\n", + "with open(file_name, 'r') as fh:\n", + " for line in fh:\n", + " print(line, end='')" + ] + }, { "cell_type": "markdown", "metadata": { @@ -1195,29 +1301,56 @@ } }, "source": [ - "### Basic file IO" + "### Parameter files\n", + "\n", + "* scientific codes are often initialized using parameter files\n", + " * parameter files can be edited by hand\n", + " * code does not need to be changed, reads in parameter file\n", + "* recommended\n", + " * YAML $\\to$ human-readable, compatible with many other tools\n", + "* less recommended\n", + " * configparser (\".cfg\", contained in standard library)\n", + " * JSON (\".json\", contained in standard library))\n", + " * custom formats" ] }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 29, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "subslide" } }, "outputs": [], "source": [ - "# naive way: write to a text file\n", - "file_name = \"/tmp/dummy.txt\"\n", - "fh = open(file_name, 'w')\n", - "fh.write(\"Hello\\n\")\n", - "fh.close()" + "# let's assume our code uses a nested dict for parameter handling\n", + "par = {}\n", + "par[\"general\"] = {}\n", + "par[\"general\"][\"time_steps\"] = 1000\n", + "par[\"general\"][\"resolution\"] = (1024,1024,512)\n", + "par[\"species\"] = {}\n", + "par[\"species\"][\"H\"] = False\n", + "par[\"species\"][\"N\"] = True" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "source": [ + "#### YAML\n", + "\n", + "* available via the `pyyaml` package\n", + "* https://pyyaml.org/wiki/PyYAMLDocumentation" ] }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 30, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1225,73 +1358,70 @@ }, "outputs": [], "source": [ - "# better: write to a text file, close file handle implicitly (ContextManager)\n", - "with open(file_name, 'a') as fh:\n", - " fh.write(\"World\\n\")" + "# write the par object to a well-formatted YAML file\n", + "import yaml\n", + "\n", + "with open(\"par.yaml\", 'w') as fp:\n", + " yaml.safe_dump(par, fp, default_flow_style=False, indent=4)" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 31, "metadata": { "slideshow": { - "slide_type": "skip" + "slide_type": "fragment" } }, + "outputs": [], "source": [ - "#### Background information on the `with` statement and context managers\n", - "\n", - "* https://docs.python.org/3/reference/compound_stmts.html#the-with-statement\n", - "* https://docs.python.org/3/reference/datamodel.html#with-statement-context-managers\n", - "* https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager" + "# read the parameters back from YAML\n", + "with open(\"par.yaml\", 'r') as fp:\n", + " par_y = yaml.safe_load(fp)" ] }, { - "cell_type": "code", - "execution_count": 22, + "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['Hello\\n', 'World\\n']\n" - ] - } - ], "source": [ - "# read the complete file into a list in memory\n", - "with open(file_name, 'r') as fh:\n", - " lines = fh.readlines()\n", - "print(lines)" + "```yaml\n", + "# par.yaml\n", + "general:\n", + " resolution:\n", + " - 1024\n", + " - 1024\n", + " - 512\n", + " time_steps: 1000\n", + "species:\n", + " H: false\n", + " N: true\n", + "```" ] }, { - "cell_type": "code", - "execution_count": 23, + "cell_type": "markdown", "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "subslide" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Hello\n", - "World\n" - ] - } - ], "source": [ - "# when reading, the file handle `fh` is actually an iterator on the lines of the file\n", - "with open(file_name, 'r') as fh:\n", - " for line in fh:\n", - " print(line, end='')" + "### Python Environments\n", + "\n", + "* a Python environment contains a Python interpreter *plus* a set of additional Python libraries (\"dependencies\")\n", + "* resides in an individual directory in user space, independent of other local environments \n", + " $\\rightarrow$ offers flexibility to install custom software versions (user-defined software stacks)\n", + "* often used to install complex packages with lots of dependencies, or during development and testing of a package\n", + "* using environment-specific metadata files (`requirements.txt` or `environment.yml`) it is possible to make environments re-creatable easily, and potentially reproducible\n", + "\n", + "#### Two popular options\n", + "\n", + "* Python Virtual Environments\n", + "* Conda Environments" ] }, { @@ -1302,37 +1432,43 @@ } }, "source": [ - "### Parameter files\n", + "#### Python Virtual Environments\n", "\n", - "* scientific codes are often initialized using parameter files\n", - " * parameter files can be edited by hand\n", - " * code does not need to be changed, reads in parameter file\n", - "* recommended\n", - " * YAML $\\to$ human-readable, compatible with many other tools\n", - "* less recommended\n", - " * configparser (\".cfg\", contained in standard library)\n", - " * JSON (\".json\", contained in standard library))\n", - " * custom formats" + "* Part of Python's standard library since version 3.3, i.e. bundled with any recent Python installation\n", + "* Supported by Python's own package manager `pip` (and by compatible tools building upon `pip`)\n", + "* Packages and their dependencies are automatically downloaded from [PyPI](https://pypi.org)\n", + "* Only Python versions that are locally installed on the same machine are supported\n", + "* https://docs.python.org/3/library/venv.html" ] }, { - "cell_type": "code", - "execution_count": 29, + "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, - "outputs": [], "source": [ - "# let's assume our code uses a nested dict for parameter handling\n", - "par = {}\n", - "par[\"general\"] = {}\n", - "par[\"general\"][\"time_steps\"] = 1000\n", - "par[\"general\"][\"resolution\"] = (1024,1024,512)\n", - "par[\"species\"] = {}\n", - "par[\"species\"][\"H\"] = False\n", - "par[\"species\"][\"N\"] = True" + "```bash\n", + "$ python3 -m venv $HOME/my_venv\n", + "$ source $HOME/my_venv/bin/activate\n", + "(my_venv) $ which python3\n", + "/home/khr/my_venv/bin/python3\n", + "(my_venv) $ pip3 install numpy\n", + "Collecting numpy\n", + "Downloading numpy-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (16.3 MB)\n", + "Installing collected packages: numpy\n", + "Successfully installed numpy-2.1.3\n", + "(my_venv) $ python3 \n", + "Python 3.10.12 (main, Nov 6 2024, 20:22:13) [GCC 11.4.0] on linux\n", + "Type \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n", + ">>> import numpy as np\n", + ">>> np.__version__\n", + "'2.1.3'\n", + ">>> exit()\n", + "(my_venv) $ deactivate \n", + "$\n", + "```" ] }, { @@ -1343,42 +1479,60 @@ } }, "source": [ - "#### YAML\n", + "#### Conda Environments\n", "\n", - "* available via the `pyyaml` package\n", - "* https://pyyaml.org/wiki/PyYAMLDocumentation" + "* The `conda` package manager is a fundamental component of the Anaconda ecosystem and its free counterpart (`conda-forge`)\n", + "* `conda` supports arbitrary software, not limited to Python packages \n", + " $\\rightarrow$ enables complex software environments, often including basic libraries pulled in via dependencies" ] }, { - "cell_type": "code", - "execution_count": 30, + "cell_type": "markdown", "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "subslide" } }, - "outputs": [], "source": [ - "# write the par object to a well-formatted YAML file\n", - "import yaml\n", + "#### Preparation: Installation of the base environment\n", "\n", - "with open(\"par.yaml\", 'w') as fp:\n", - " yaml.safe_dump(par, fp, default_flow_style=False, indent=4)" + "```bash\n", + "$ wget https://github.com/conda-forge/miniforge/releases/download/24.9.2-0/Miniforge3-Linux-x86_64.sh\n", + "$ bash Miniforge3-Linux-x86_64.sh -f -b -p /opt/apps/miniforge3\n", + "( ... many lines stripped ...)\n", + "$ source /opt/apps/miniforge3/bin/activate\n", + "(base) $ which python3\n", + "/opt/apps/miniforge3/bin/python3\n", + "(base) $ python3 --version\n", + "Python 3.12.7\n", + "```" ] }, { - "cell_type": "code", - "execution_count": 31, + "cell_type": "markdown", "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "subslide" } }, - "outputs": [], "source": [ - "# read the parameters back from YAML\n", - "with open(\"par.yaml\", 'r') as fp:\n", - " par_y = yaml.safe_load(fp)" + "#### Example: Creation of an actual Conda environment with Python 3.13 and NumPy\n", + "\n", + "```bash\n", + "(base) $ conda create -n my_env python=3.13\n", + "( ... many lines stripped ...)\n", + "(base) $ conda activate my_env\n", + "(my_env) $ which python3 \n", + "/opt/apps/miniforge3/envs/my_env/bin/python3\n", + "(my_env) $ python3 --version\n", + "Python 3.13.0\n", + "(my_env) $ conda install numpy\n", + "(my_env) $ python3 \n", + ">>> import numpy as np\n", + ">>> np.__version__\n", + "'2.1.3'\n", + ">>>\n", + "```" ] }, { @@ -1389,18 +1543,20 @@ } }, "source": [ - "```yaml\n", - "# par.yaml\n", - "general:\n", - " resolution:\n", - " - 1024\n", - " - 1024\n", - " - 512\n", - " time_steps: 1000\n", - "species:\n", - " H: false\n", - " N: true\n", - "```" + "#### Conda Environments (cont'd)\n", + "\n", + "* Observations \n", + " * The base environment contains a standalone Python installation, together with its binary dependencies\n", + " * The custom environment ('my_env') containes a standalone Python installation, together with its binary dependencies\n", + " * The installation of 'numpy' has pulled in additional binary dependencies, such as BLAS and LAPACK\n", + "* Caution \n", + " * Conda environments can become quite large (in file count and overall size)\n", + " * Binary blobs downloaded from the Internet can be incompatible with the local OS, leading to runtime errors\n", + " * License issues, effective since March 2024, for Anaconda software channels!\n", + "\n", + "##### More Information\n", + "\n", + "[Navigating the Anaconda Python License Change: Adopting Conda-Forge and Best Practices for HPC Python Environments (Meet MPCDF seminar, October 2024)](https://datashare.mpcdf.mpg.de/s/CZR64ip6fvi6TqA)" ] }, { diff --git a/notebooks/05--NumPy_SciPy.ipynb b/notebooks/05--NumPy_SciPy.ipynb index 5b51411..9b4f549 100644 --- a/notebooks/05--NumPy_SciPy.ipynb +++ b/notebooks/05--NumPy_SciPy.ipynb @@ -992,7 +992,7 @@ "\n", "x = np.linspace(0, 2.0, 10)\n", "y = np.sin(x)\n", - "result = integrate.simps(y, x) # Simpson rule for given sample\n", + "result = integrate.simpson(y, x=x) # Simpson rule for given sample\n", "print(result, 1.-np.cos(2.0))\n", "\n", "# simple derivative: exponential\n", @@ -1648,8 +1648,8 @@ }, "outputs": [], "source": [ - "filtered_loop = get_filtered_loop(image)\n", - "filtered_array = get_filtered_array(image)\n", + "filtered_loop = get_filtered_loop(image)[1:-1,1:-1]\n", + "filtered_array = get_filtered_array(image)[1:-1,1:-1]\n", "\n", "f, axs = plt.subplots(2, 3, figsize=(14, 8))\n", "axs[0, 0].imshow(image, cmap='gray')\n", @@ -1657,7 +1657,7 @@ "axs[0, 2].imshow(filtered_array - filtered_loop, cmap='gray')\n", "axs[1, 0].imshow(image[600:700, 600:700], cmap='gray')\n", "axs[1, 1].imshow(filtered_array[600:700, 600:700], cmap='gray')\n", - "axs[1, 2].imshow((image-filtered_array)[600:700, 600:700], cmap='gray')\n", + "axs[1, 2].imshow((image[1:-1,1:-1]-filtered_array)[600:700, 600:700], cmap='gray')\n", "print(\"Loop and array method yields the same: \", np.allclose(filtered_loop, filtered_array))" ] }, @@ -1687,7 +1687,7 @@ }, "outputs": [], "source": [ - "from scipy.misc import ascent\n", + "from scipy.datasets import ascent\n", "im = plt.imshow(ascent(), cmap='gray')" ] }, @@ -1727,7 +1727,7 @@ " return result\n", "f, axs = plt.subplots(1, 2, figsize=(15, 5))\n", "axs[0].imshow(ascent(), cmap='gray')\n", - "axs[1].imshow(get_edges(ascent()), cmap='gray');None" + "axs[1].imshow(get_edges(ascent().astype('int32')), cmap='gray');None" ] }, { -- GitLab