From 55357f17991b37c26fb735db3180cb995769d5e0 Mon Sep 17 00:00:00 2001 From: kp992 Date: Mon, 17 Feb 2025 12:53:27 -0800 Subject: [PATCH 01/18] add initial wasm CI workflow --- .github/workflows/cache.yml | 52 --------------- .github/workflows/ci.yml | 89 ------------------------- .github/workflows/collab.yml | 54 --------------- .github/workflows/linkcheck.yml | 44 ------------ .github/workflows/publish.yml | 114 -------------------------------- .github/workflows/wasm_test.yml | 39 +++++++++++ 6 files changed, 39 insertions(+), 353 deletions(-) delete mode 100644 .github/workflows/cache.yml delete mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/collab.yml delete mode 100644 .github/workflows/linkcheck.yml delete mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/wasm_test.yml diff --git a/.github/workflows/cache.yml b/.github/workflows/cache.yml deleted file mode 100644 index e2f45418..00000000 --- a/.github/workflows/cache.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Build Cache [using jupyter-book] -on: - push: - branches: - - main -jobs: - tests: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Setup Anaconda - uses: conda-incubator/setup-miniconda@v3 - with: - auto-update-conda: true - auto-activate-base: true - miniconda-version: 'latest' - python-version: "3.12" - environment-file: environment.yml - activate-environment: quantecon - - name: graphviz Support # TODO: required? - run: | - sudo apt-get -qq update && sudo apt-get install -y graphviz - - name: Install latex dependencies - run: | - sudo apt-get -qq update - sudo apt-get install -y \ - texlive-latex-recommended \ - texlive-latex-extra \ - texlive-fonts-recommended \ - texlive-fonts-extra \ - texlive-xetex \ - latexmk \ - xindy \ - dvipng \ - cm-super - - name: Build HTML - shell: bash -l {0} - run: | - jb build lectures --path-output ./ -W --keep-going - - name: Upload Execution Reports (HTML) - uses: actions/upload-artifact@v4 - if: failure() - with: - name: execution-reports - path: _build/html/reports - - name: Upload "_build" folder (cache) - uses: actions/upload-artifact@v4 - with: - name: build-cache - path: _build - include-hidden-files: true \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 2ab95026..00000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,89 +0,0 @@ -name: Build HTML [using jupyter-book] -on: [pull_request] -jobs: - preview: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Setup Anaconda - uses: conda-incubator/setup-miniconda@v3 - with: - auto-update-conda: true - auto-activate-base: true - miniconda-version: 'latest' - python-version: "3.12" - environment-file: environment.yml - activate-environment: quantecon - - name: Graphics Support #TODO: Review if graphviz is needed - run: | - sudo apt-get -qq update && sudo apt-get install -y graphviz - - name: Install latex dependencies - run: | - sudo apt-get -qq update - sudo apt-get install -y \ - texlive-latex-recommended \ - texlive-latex-extra \ - texlive-fonts-recommended \ - texlive-fonts-extra \ - texlive-xetex \ - latexmk \ - xindy \ - dvipng \ - cm-super - - name: Display Conda Environment Versions - shell: bash -l {0} - run: conda list - - name: Display Pip Versions - shell: bash -l {0} - run: pip list - - name: Download "build" folder (cache) - uses: dawidd6/action-download-artifact@v8 - with: - workflow: cache.yml - branch: main - name: build-cache - path: _build - # Build Assets (Download Notebooks and PDF via LaTeX) - - name: Build PDF from LaTeX - shell: bash -l {0} - run: | - jb build lectures --builder pdflatex --path-output ./ -n --keep-going - mkdir -p _build/html/_pdf - cp -u _build/latex/*.pdf _build/html/_pdf - - name: Upload Execution Reports (LaTeX) - uses: actions/upload-artifact@v4 - if: failure() - with: - name: execution-reports - path: _build/latex/reports - - name: Build Download Notebooks (sphinx-tojupyter) - shell: bash -l {0} - run: | - jb build lectures --path-output ./ --builder=custom --custom-builder=jupyter - mkdir -p _build/html/_notebooks - cp -u _build/jupyter/*.ipynb _build/html/_notebooks - # Build HTML (Website) - # BUG: rm .doctress to remove `sphinx` rendering issues for ipywidget mimetypes - # and clear the sphinx cache for building final HTML documents. - - name: Build HTML - shell: bash -l {0} - run: | - rm -r _build/.doctrees - jb build lectures --path-output ./ -nW --keep-going - - name: Upload Execution Reports (HTML) - uses: actions/upload-artifact@v4 - if: failure() - with: - name: execution-reports - path: _build/html/reports - - name: Preview Deploy to Netlify - uses: nwtgck/actions-netlify@v3.0 - with: - publish-dir: '_build/html/' - production-branch: main - github-token: ${{ secrets.GITHUB_TOKEN }} - deploy-message: "Preview Deploy from GitHub Actions" - env: - NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} diff --git a/.github/workflows/collab.yml b/.github/workflows/collab.yml deleted file mode 100644 index 5060c30b..00000000 --- a/.github/workflows/collab.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Build Project on Google Collab (Execution) -on: [pull_request] - -jobs: - test: - runs-on: quantecon-large - container: - image: us-docker.pkg.dev/colab-images/public/runtime:latest - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} - - name: Check for dockerenv file - run: (ls /.dockerenv && echo Found dockerenv) || (echo No dockerenv) - - name: Check python version - shell: bash -l {0} - run: | - python --version - - name: Display Pip Versions - shell: bash -l {0} - run: pip list - - name: Download "build" folder (cache) - uses: dawidd6/action-download-artifact@v8 - with: - workflow: cache.yml - branch: main - name: build-cache - path: _build - # Install build software - - name: Install Build Software - shell: bash -l {0} - run: | - pip install jupyter-book==0.15.1 docutils==0.17.1 quantecon-book-theme==0.7.2 sphinx-tojupyter==0.3.0 sphinxext-rediraffe==0.2.7 sphinx-exercise==0.4.1 sphinxcontrib-youtube==1.1.0 sphinx-togglebutton==0.3.1 arviz==0.13.0 sphinx_proof==0.2.0 sphinx_reredirects==0.1.3 - # Build of HTML (Execution Testing) - - name: Build HTML - shell: bash -l {0} - run: | - jb build lectures --path-output ./ -n -W --keep-going - - name: Upload Execution Reports - uses: actions/upload-artifact@v4 - if: failure() - with: - name: execution-reports - path: _build/html/reports - - name: Preview Deploy to Netlify - uses: nwtgck/actions-netlify@v3.0 - with: - publish-dir: '_build/html/' - production-branch: main - github-token: ${{ secrets.GITHUB_TOKEN }} - deploy-message: "Preview Deploy from GitHub Actions" - env: - NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml deleted file mode 100644 index 226685c1..00000000 --- a/.github/workflows/linkcheck.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Link Checker [Anaconda, Linux] -on: - pull_request: - types: [opened, reopened] - schedule: - # UTC 12:00 is early morning in Australia - - cron: '0 12 * * *' -jobs: - link-check-linux: - name: Link Checking (${{ matrix.python-version }}, ${{ matrix.os }}) - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: ["ubuntu-latest"] - python-version: ["3.12"] - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Setup Anaconda - uses: conda-incubator/setup-miniconda@v3 - with: - auto-update-conda: true - auto-activate-base: true - miniconda-version: 'latest' - python-version: "3.12" - environment-file: environment.yml - activate-environment: quantecon - - name: Download "build" folder (cache) - uses: dawidd6/action-download-artifact@v8 - with: - workflow: cache.yml - branch: main - name: build-cache - path: _build - - name: Link Checker - shell: bash -l {0} - run: jb build lectures --path-output=./ --builder=custom --custom-builder=linkcheck - - name: Upload Link Checker Reports - uses: actions/upload-artifact@v4 - if: failure() - with: - name: linkcheck-reports - path: _build/linkcheck \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index 2054c6f2..00000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,114 +0,0 @@ -name: Build & Publish to GH-PAGES -on: - push: - tags: - - 'publish*' -jobs: - publish: - if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Setup Anaconda - uses: conda-incubator/setup-miniconda@v3 - with: - auto-update-conda: true - auto-activate-base: true - miniconda-version: 'latest' - python-version: "3.12" - environment-file: environment.yml - activate-environment: quantecon - - name: Install latex dependencies - run: | - sudo apt-get -qq update - sudo apt-get install -y \ - texlive-latex-recommended \ - texlive-latex-extra \ - texlive-fonts-recommended \ - texlive-fonts-extra \ - texlive-xetex \ - latexmk \ - xindy \ - dvipng \ - cm-super - - name: Display Conda Environment Versions - shell: bash -l {0} - run: conda list - - name: Display Pip Versions - shell: bash -l {0} - run: pip list - - name: Download "build" folder (cache) - uses: dawidd6/action-download-artifact@v8 - with: - workflow: cache.yml - branch: main - name: build-cache - path: _build - # Build Assets (Download Notebooks and PDF via LaTeX) - - name: Build PDF from LaTeX - shell: bash -l {0} - run: | - jb build lectures --builder pdflatex --path-output ./ -n --keep-going - - name: Copy LaTeX PDF for GH-PAGES - shell: bash -l {0} - run: | - mkdir -p _build/html/_pdf - cp -u _build/latex/*.pdf _build/html/_pdf - - name: Build Download Notebooks (sphinx-tojupyter) - shell: bash -l {0} - run: | - jb build lectures --path-output ./ --builder=custom --custom-builder=jupyter - - name: Copy Download Notebooks for GH-PAGES - shell: bash -l {0} - run: | - mkdir -p _build/html/_notebooks - cp -u _build/jupyter/*.ipynb _build/html/_notebooks - # Build HTML (Website) - # BUG: rm .doctress to remove `sphinx` rendering issues for ipywidget mimetypes - # and clear the sphinx cache for building final HTML documents. - - name: Build HTML - shell: bash -l {0} - run: | - rm -r _build/.doctrees - jb build lectures --path-output ./ - - name: Deploy to Netlify - uses: nwtgck/actions-netlify@v3.0 - with: - publish-dir: '_build/html/' - production-branch: main - github-token: ${{ secrets.GITHUB_TOKEN }} - deploy-message: "Deploy from GitHub Actions" - env: - NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - - name: Deploy website to gh-pages - uses: peaceiris/actions-gh-pages@v4 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: _build/html/ - cname: intro.quantecon.org - - name: Upload "_build" folder (cache) - uses: actions/upload-artifact@v4 - with: - name: build-publish - path: _build - # Sync notebooks - - name: Prepare lecture-python-intro.notebooks sync - shell: bash -l {0} - run: | - mkdir -p _build/lecture-python-intro.notebooks - cp -a _notebook_repo/. _build/lecture-python-intro.notebooks - cp _build/jupyter/*.ipynb _build/lecture-python-intro.notebooks - ls -a _build/lecture-python-intro.notebooks - - name: Commit latest notebooks to lecture-python-intro.notebooks - uses: cpina/github-action-push-to-another-repository@main - env: - API_TOKEN_GITHUB: ${{ secrets.QUANTECON_SERVICES_PAT }} - with: - source-directory: '_build/lecture-python-intro.notebooks/' - destination-repository-username: 'QuantEcon' - destination-repository-name: 'lecture-python-intro.notebooks' - commit-message: 'auto publishing updates to notebooks' - destination-github-username: 'quantecon-services' - user-email: services@quantecon.org diff --git a/.github/workflows/wasm_test.yml b/.github/workflows/wasm_test.yml new file mode 100644 index 00000000..0ccb83d3 --- /dev/null +++ b/.github/workflows/wasm_test.yml @@ -0,0 +1,39 @@ +name: test-wasm + +on: + push: + branches: + - wasm + pull_request: + branches: + - wasm + +jobs: + run-wasm-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.12" + + - name: Install dependencies (pyodide) + run: | + python -m pip install pyodide-build + pyodide xbuildenv install + pyodide venv .venv-pyodide + + - name: Debug + run: | + source .venv-pyodide/bin/activate + which pip + which python + + - name: Try numba install + run: | + source .venv-pyodide/bin/activate + pip install numba From 56c27282d712609ef12185f13dc461f63712c00f Mon Sep 17 00:00:00 2001 From: kp992 Date: Mon, 17 Feb 2025 17:36:34 -0800 Subject: [PATCH 02/18] add script to install libs in pyodide --- .github/workflows/wasm_test.yml | 13 +++--- .gitignore | 1 + testing/generate_py_files.py | 23 +++++++++++ testing/install_pyodide_libs.py | 71 +++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+), 5 deletions(-) create mode 100644 testing/generate_py_files.py create mode 100644 testing/install_pyodide_libs.py diff --git a/.github/workflows/wasm_test.yml b/.github/workflows/wasm_test.yml index 0ccb83d3..74a83e11 100644 --- a/.github/workflows/wasm_test.yml +++ b/.github/workflows/wasm_test.yml @@ -21,19 +21,22 @@ jobs: with: python-version: "3.12" - - name: Install dependencies (pyodide) + - name: Install libraries run: | - python -m pip install pyodide-build + python -m pip install pyodide-build jupytext pyodide xbuildenv install pyodide venv .venv-pyodide - - name: Debug + - name: Convert lectures to python files + run: python testing/generate_py_files.py + + - name: Pip and Python (venv) run: | source .venv-pyodide/bin/activate which pip which python - - name: Try numba install + - name: Import libraries in pyodide run: | source .venv-pyodide/bin/activate - pip install numba + python testing/install_pyodide_libs.py diff --git a/.gitignore b/.gitignore index f94768ac..9d4df66a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ lectures/_build .ipynb_checkpoints/ .virtual_documents/ _build/* +testing/py_files/* diff --git a/testing/generate_py_files.py b/testing/generate_py_files.py new file mode 100644 index 00000000..7310443f --- /dev/null +++ b/testing/generate_py_files.py @@ -0,0 +1,23 @@ +import os +import glob +import shutil + +PARENT_DIR = os.path.dirname(os.path.abspath(__file__)) +ROOT_DIR = os.path.dirname(PARENT_DIR) + +IN_DIR = os.path.join(ROOT_DIR, 'lectures') +OUT_DIR = os.path.join(PARENT_DIR, 'py_files') + +def main(): + shutil.copytree(IN_DIR, OUT_DIR, dirs_exist_ok=True) + cwd = os.getcwd() + os.chdir(OUT_DIR) + cmd = "jupytext --to py *.md" + os.system(cmd) + lectures = list(glob.glob(OUT_DIR + '/*.md')) + for file in lectures: + os.remove(file) + os.chdir(cwd) + +if __name__ == '__main__': + main() diff --git a/testing/install_pyodide_libs.py b/testing/install_pyodide_libs.py new file mode 100644 index 00000000..bad1abc1 --- /dev/null +++ b/testing/install_pyodide_libs.py @@ -0,0 +1,71 @@ +import os +import glob +import ast +import importlib.util +import micropip +import asyncio + +PARENT_DIR = os.path.dirname(os.path.abspath(__file__)) +ROOT_DIR = os.path.dirname(PARENT_DIR) + +PY_FILES_DIR = os.path.join(PARENT_DIR, 'py_files') +SKIP_FILES = [ + 'short_path.py', + 'inflation_history.py' +] + +def get_imported_libraries(file_path): + """Extracts all imported libraries from a Python file.""" + with open(file_path, "r", encoding="utf-8") as file: + tree = ast.parse(file.read(), filename=file_path) + + imports = set() + + for node in ast.walk(tree): + if isinstance(node, ast.Import): + for alias in node.names: + imports.add(alias.name.split('.')[0]) # Get the top-level package + elif isinstance(node, ast.ImportFrom): + if node.module: + imports.add(node.module.split('.')[0]) + + return sorted(imports) + + +def is_library_installed(library_name): + """Checks if a given library is installed.""" + return importlib.util.find_spec(library_name) is not None + + +async def install_missing_libraries(file_path, previously_installed): + """Finds missing libraries and installs them using micropip.""" + for skip_file in SKIP_FILES: + if file_path.endswith(skip_file): + return + print(f"Installing missing libraries for file: {file_path}") + imported_libraries = get_imported_libraries(file_path) + + missing_libraries = [] + for lib in imported_libraries: + if lib not in previously_installed and not is_library_installed(lib): + missing_libraries.append(lib) + + if len(missing_libraries) == 0: + print(f"All required libraries are already installed in {file_path}") + return + + for lib in missing_libraries: + print(f"Installing missing libraries: {lib}") + await micropip.install(lib) + previously_installed.add(lib) + + +async def main(): + lectures_py = list(glob.glob(PY_FILES_DIR + '/*.py')) + previously_installed = set() + for file in lectures_py: + await install_missing_libraries(file, previously_installed) + + +if __name__ == '__main__': + asyncio.run(main()) From 9a594d360b8980ba91f406d14d535f77cdb0ac06 Mon Sep 17 00:00:00 2001 From: kp992 Date: Mon, 17 Feb 2025 17:40:18 -0800 Subject: [PATCH 03/18] handle exception --- testing/install_pyodide_libs.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/testing/install_pyodide_libs.py b/testing/install_pyodide_libs.py index bad1abc1..e084ceab 100644 --- a/testing/install_pyodide_libs.py +++ b/testing/install_pyodide_libs.py @@ -11,7 +11,7 @@ PY_FILES_DIR = os.path.join(PARENT_DIR, 'py_files') SKIP_FILES = [ 'short_path.py', - 'inflation_history.py' + 'inflation_history.py', ] def get_imported_libraries(file_path): @@ -68,4 +68,10 @@ async def main(): if __name__ == '__main__': - asyncio.run(main()) + try: + # Check if running inside an existing event loop + loop = asyncio.get_running_loop() + asyncio.ensure_future(main()) + except RuntimeError: + # No running event loop, safe to use asyncio.run() + asyncio.run(main()) From f981a5f6bdc551effdbfea5b0bdbc511c3439ea2 Mon Sep 17 00:00:00 2001 From: kp992 Date: Mon, 17 Feb 2025 17:47:24 -0800 Subject: [PATCH 04/18] raise value error on failure --- testing/install_pyodide_libs.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/testing/install_pyodide_libs.py b/testing/install_pyodide_libs.py index e084ceab..02b3be4d 100644 --- a/testing/install_pyodide_libs.py +++ b/testing/install_pyodide_libs.py @@ -64,7 +64,10 @@ async def main(): lectures_py = list(glob.glob(PY_FILES_DIR + '/*.py')) previously_installed = set() for file in lectures_py: - await install_missing_libraries(file, previously_installed) + try: + await install_missing_libraries(file, previously_installed) + except Exception as e: + raise ValueError(f"failed to install library in file: {file}") if __name__ == '__main__': From 011f97cb92692fd7b84024fe79c5fbdd44f72a95 Mon Sep 17 00:00:00 2001 From: kp992 Date: Mon, 17 Feb 2025 17:52:04 -0800 Subject: [PATCH 05/18] fix without exception --- testing/install_pyodide_libs.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/testing/install_pyodide_libs.py b/testing/install_pyodide_libs.py index 02b3be4d..acce535c 100644 --- a/testing/install_pyodide_libs.py +++ b/testing/install_pyodide_libs.py @@ -71,10 +71,10 @@ async def main(): if __name__ == '__main__': - try: - # Check if running inside an existing event loop - loop = asyncio.get_running_loop() - asyncio.ensure_future(main()) - except RuntimeError: - # No running event loop, safe to use asyncio.run() + if asyncio.get_event_loop().is_running(): + # If an event loop is already running, use create_task() + task = asyncio.create_task(main()) + asyncio.get_event_loop().run_until_complete(task) + else: + # If no event loop is running, use asyncio.run() asyncio.run(main()) From a6c0caa0bfc8d7cf537ef93063ee8c9839d22a69 Mon Sep 17 00:00:00 2001 From: kp992 Date: Mon, 17 Feb 2025 17:59:08 -0800 Subject: [PATCH 06/18] use sys.exit --- testing/install_pyodide_libs.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/testing/install_pyodide_libs.py b/testing/install_pyodide_libs.py index acce535c..1529f94f 100644 --- a/testing/install_pyodide_libs.py +++ b/testing/install_pyodide_libs.py @@ -4,6 +4,7 @@ import importlib.util import micropip import asyncio +import sys PARENT_DIR = os.path.dirname(os.path.abspath(__file__)) ROOT_DIR = os.path.dirname(PARENT_DIR) @@ -67,6 +68,7 @@ async def main(): try: await install_missing_libraries(file, previously_installed) except Exception as e: + sys.exit(1) raise ValueError(f"failed to install library in file: {file}") From 1dc42cd777aa314243ed51842d90a647f7d4b3d7 Mon Sep 17 00:00:00 2001 From: kp992 Date: Mon, 17 Feb 2025 18:06:04 -0800 Subject: [PATCH 07/18] print error msg --- testing/install_pyodide_libs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/install_pyodide_libs.py b/testing/install_pyodide_libs.py index 1529f94f..29e32a07 100644 --- a/testing/install_pyodide_libs.py +++ b/testing/install_pyodide_libs.py @@ -68,8 +68,8 @@ async def main(): try: await install_missing_libraries(file, previously_installed) except Exception as e: + print(f"failed to install library from file: {file}") sys.exit(1) - raise ValueError(f"failed to install library in file: {file}") if __name__ == '__main__': From a137cf13c5fd817f58b68995a45e0ed5aea4b53a Mon Sep 17 00:00:00 2001 From: kp992 Date: Thu, 20 Feb 2025 13:49:09 -0800 Subject: [PATCH 08/18] add script to run py files --- .github/workflows/wasm_test.yml | 5 +++++ testing/run_py_files.sh | 35 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 testing/run_py_files.sh diff --git a/.github/workflows/wasm_test.yml b/.github/workflows/wasm_test.yml index 74a83e11..545479f8 100644 --- a/.github/workflows/wasm_test.yml +++ b/.github/workflows/wasm_test.yml @@ -40,3 +40,8 @@ jobs: run: | source .venv-pyodide/bin/activate python testing/install_pyodide_libs.py + + - name: Run python files in pyodide environment + run: | + source .venv-pyodide/bin/activate + bash testing/run_py_files.sh testing/py_files diff --git a/testing/run_py_files.sh b/testing/run_py_files.sh new file mode 100644 index 00000000..7bbf1c5a --- /dev/null +++ b/testing/run_py_files.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Exit immediately if a command fails +set -e + +# Check if a directory argument is provided +if [ $# -eq 0 ]; then + echo "Usage: $0 " + exit 1 +fi + +TARGET_DIR="$1" + +# Ensure the directory exists +if [ ! -d "$TARGET_DIR" ]; then + echo "Error: Directory '$TARGET_DIR' does not exist." + exit 1 +fi + +# Find and execute all Python files +echo "Searching for Python files in $TARGET_DIR..." +PYTHON_FILES=$(find "$TARGET_DIR" -type f -name "*.py") + +if [ -z "$PYTHON_FILES" ]; then + echo "No Python files found in $TARGET_DIR" + exit 0 +fi + +# Run each Python file +for file in $PYTHON_FILES; do + echo " Running: $file" + MPLBACKEND=Agg python "$file" +done + +echo "✅ All scripts ran successfully!" From 4fe479f6f1974d368fdb6bf3aaa3d834d92bd29c Mon Sep 17 00:00:00 2001 From: kp992 Date: Sat, 22 Feb 2025 17:59:49 -0800 Subject: [PATCH 09/18] keep files in sorted order --- testing/run_py_files.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/run_py_files.sh b/testing/run_py_files.sh index 7bbf1c5a..7ae53186 100644 --- a/testing/run_py_files.sh +++ b/testing/run_py_files.sh @@ -19,7 +19,7 @@ fi # Find and execute all Python files echo "Searching for Python files in $TARGET_DIR..." -PYTHON_FILES=$(find "$TARGET_DIR" -type f -name "*.py") +PYTHON_FILES=$(find "$TARGET_DIR" -type f -name "*.py" | sort) if [ -z "$PYTHON_FILES" ]; then echo "No Python files found in $TARGET_DIR" From 3114ef133075d8768afb0982f020601dbf9e243b Mon Sep 17 00:00:00 2001 From: Jiarui Zhang Date: Sun, 23 Feb 2025 21:23:08 +1100 Subject: [PATCH 10/18] Simple fixes to Lecture URL and Imports --- lectures/ar1_processes.md | 23 +++++++------- lectures/business_cycle.md | 55 +++++++++------------------------ lectures/eigen_II.md | 6 ++-- lectures/french_rev.md | 58 +++++++++++++++++++---------------- lectures/heavy_tails.md | 5 ++- lectures/inequality.md | 33 ++++++++------------ lectures/inflation_history.md | 7 +++-- lectures/long_run_growth.md | 10 +++++- lectures/markov_chains_I.md | 13 +++----- lectures/markov_chains_II.md | 4 +-- lectures/mle.md | 8 ++++- 11 files changed, 104 insertions(+), 118 deletions(-) diff --git a/lectures/ar1_processes.md b/lectures/ar1_processes.md index 34b93ae7..406ead94 100644 --- a/lectures/ar1_processes.md +++ b/lectures/ar1_processes.md @@ -3,8 +3,10 @@ jupytext: text_representation: extension: .md format_name: myst + format_version: 0.13 + jupytext_version: 1.16.1 kernelspec: - display_name: Python 3 + display_name: Python 3 (ipykernel) language: python name: python3 --- @@ -40,7 +42,7 @@ partly because they help us understand important concepts. Let's start with some imports: -```{code-cell} ipython +```{code-cell} ipython3 import numpy as np import matplotlib.pyplot as plt plt.rcParams["figure.figsize"] = (11, 5) #set default figure size @@ -160,7 +162,7 @@ The following code uses these facts to track the sequence of marginal distributi The parameters are -```{code-cell} python3 +```{code-cell} ipython3 a, b, c = 0.9, 0.1, 0.5 mu, v = -3.0, 0.6 # initial conditions mu_0, v_0 @@ -168,7 +170,7 @@ mu, v = -3.0, 0.6 # initial conditions mu_0, v_0 Here's the sequence of distributions: -```{code-cell} python3 +```{code-cell} ipython3 from scipy.stats import norm sim_length = 10 @@ -188,8 +190,6 @@ ax.legend(bbox_to_anchor=[1.05,1],loc=2,borderaxespad=1) plt.show() ``` - - ## Stationarity and asymptotic stability When we use models to study the real world, it is generally preferable that our @@ -206,7 +206,7 @@ Notice that, in the figure above, the sequence $\{ \psi_t \}$ seems to be conver This is even clearer if we project forward further into the future: -```{code-cell} python3 +```{code-cell} ipython3 def plot_density_seq(ax, mu_0=-3.0, v_0=0.6, sim_length=40): mu, v = mu_0, v_0 for t in range(sim_length): @@ -225,7 +225,7 @@ Moreover, the limit does not depend on the initial condition. For example, this alternative density sequence also converges to the same limit. -```{code-cell} python3 +```{code-cell} ipython3 fig, ax = plt.subplots() plot_density_seq(ax, mu_0=4.0) plt.show() @@ -260,7 +260,7 @@ t \to \infty We can confirm this is valid for the sequence above using the following code. -```{code-cell} python3 +```{code-cell} ipython3 fig, ax = plt.subplots() plot_density_seq(ax, mu_0=4.0) @@ -406,11 +406,10 @@ Confirm this by simulation at a range of $k$ using the default parameters from t Here is one solution: -```{code-cell} python3 -from numba import njit +```{code-cell} ipython3 from scipy.special import factorial2 -@njit + def sample_moments_ar1(k, m=100_000, mu_0=0.0, sigma_0=1.0, seed=1234): np.random.seed(seed) sample_sum = 0.0 diff --git a/lectures/business_cycle.md b/lectures/business_cycle.md index 5e7174bb..5e6c2ce3 100644 --- a/lectures/business_cycle.md +++ b/lectures/business_cycle.md @@ -4,7 +4,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.14.5 + jupytext_version: 1.16.1 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -53,7 +53,6 @@ cycler = plt.cycler(linestyle=['-', '-.', '--', ':'], plt.rc('axes', prop_cycle=cycler) ``` - ## Data acquisition We will use the World Bank's data API `wbgapi` and `pandas_datareader` to retrieve data. @@ -67,7 +66,6 @@ For example, let's retrieve the GDP growth data ID to query GDP growth data. wb.series.info(q='GDP growth') ``` - Now we use this series ID to obtain the data. ```{code-cell} ipython3 @@ -77,7 +75,6 @@ gdp_growth = wb.data.DataFrame('NY.GDP.MKTP.KD.ZG', gdp_growth ``` - We can look at the series' metadata to learn more about the series (click to expand). ```{code-cell} ipython3 @@ -86,8 +83,6 @@ We can look at the series' metadata to learn more about the series (click to exp wb.series.metadata.get('NY.GDP.MKTP.KD.ZG') ``` - - (gdp_growth)= ## GDP growth rate @@ -186,17 +181,15 @@ t_params = {'color':'grey', 'fontsize': 9, 'va':'center', 'ha':'center'} ``` - Let's start with the United States. ```{code-cell} ipython3 --- mystnb: figure: - caption: "United States (GDP growth rate %)" + caption: United States (GDP growth rate %) name: us_gdp --- - fig, ax = plt.subplots() country = 'United States' @@ -226,10 +219,9 @@ Notice the very large dip during the Covid-19 pandemic. --- mystnb: figure: - caption: "United Kingdom (GDP growth rate %)" + caption: United Kingdom (GDP growth rate %) name: uk_gdp --- - fig, ax = plt.subplots() country = 'United Kingdom' @@ -251,10 +243,9 @@ Global Financial Crisis (GFC) and the Covid-19 pandemic. --- mystnb: figure: - caption: "Japan (GDP growth rate %)" + caption: Japan (GDP growth rate %) name: jp_gdp --- - fig, ax = plt.subplots() country = 'Japan' @@ -270,10 +261,9 @@ Now let's study Greece. --- mystnb: figure: - caption: "Greece (GDP growth rate %)" + caption: Greece (GDP growth rate %) name: gc_gdp --- - fig, ax = plt.subplots() country = 'Greece' @@ -292,10 +282,9 @@ Next let's consider Argentina. --- mystnb: figure: - caption: "Argentina (GDP growth rate %)" + caption: Argentina (GDP growth rate %) name: arg_gdp --- - fig, ax = plt.subplots() country = 'Argentina' @@ -343,11 +332,10 @@ defined by the NBER. --- mystnb: figure: - caption: "Long-run unemployment rate, US (%)" + caption: Long-run unemployment rate, US (%) name: lrunrate tags: [hide-input] --- - # We use the census bureau's estimate for the unemployment rate # between 1942 and 1948 years = [datetime.datetime(year, 6, 1) for year in range(1942, 1948)] @@ -390,7 +378,6 @@ ax.set_ylabel('unemployment rate (%)') plt.show() ``` - The plot shows that * expansions and contractions of the labor market have been highly correlated @@ -418,9 +405,7 @@ With slight modifications, we can use our previous function to draw a plot that includes multiple countries. ```{code-cell} ipython3 ---- -tags: [hide-input] ---- +:tags: [hide-input] def plot_comparison(data, countries, @@ -497,9 +482,7 @@ t_params = {'color':'grey', 'fontsize': 9, Here we compare the GDP growth rate of developed economies and developing economies. ```{code-cell} ipython3 ---- -tags: [hide-input] ---- +:tags: [hide-input] # Obtain GDP growth rate for a list of countries gdp_growth = wb.data.DataFrame('NY.GDP.MKTP.KD.ZG', @@ -507,7 +490,6 @@ gdp_growth = wb.data.DataFrame('NY.GDP.MKTP.KD.ZG', labels=True) gdp_growth = gdp_growth.set_index('Country') gdp_growth.columns = gdp_growth.columns.str.replace('YR', '').astype(int) - ``` We use the United Kingdom, United States, Germany, and Japan as examples of developed economies. @@ -516,11 +498,10 @@ We use the United Kingdom, United States, Germany, and Japan as examples of deve --- mystnb: figure: - caption: "Developed economies (GDP growth rate %)" + caption: Developed economies (GDP growth rate %) name: adv_gdp tags: [hide-input] --- - fig, ax = plt.subplots() countries = ['United Kingdom', 'United States', 'Germany', 'Japan'] ylabel = 'GDP growth rate (%)' @@ -537,11 +518,10 @@ We choose Brazil, China, Argentina, and Mexico as representative developing econ --- mystnb: figure: - caption: "Developing economies (GDP growth rate %)" + caption: Developing economies (GDP growth rate %) name: deve_gdp tags: [hide-input] --- - fig, ax = plt.subplots() countries = ['Brazil', 'China', 'Argentina', 'Mexico'] plot_comparison(gdp_growth.loc[countries, 1962:], @@ -551,7 +531,6 @@ plot_comparison(gdp_growth.loc[countries, 1962:], plt.show() ``` - The comparison of GDP growth rates above suggests that business cycles are becoming more synchronized in 21st-century recessions. @@ -571,11 +550,10 @@ the United Kingdom, Japan, and France. --- mystnb: figure: - caption: "Developed economies (unemployment rate %)" + caption: Developed economies (unemployment rate %) name: adv_unemp tags: [hide-input] --- - unempl_rate = wb.data.DataFrame('SL.UEM.TOTL.NE.ZS', ['USA', 'FRA', 'GBR', 'JPN'], labels=True) unempl_rate = unempl_rate.set_index('Country') @@ -623,11 +601,10 @@ year-on-year --- mystnb: figure: - caption: "Consumer sentiment index and YoY CPI change, US" + caption: Consumer sentiment index and YoY CPI change, US name: csicpi tags: [hide-input] --- - start_date = datetime.datetime(1978, 1, 1) end_date = datetime.datetime(2022, 12, 31) @@ -705,11 +682,10 @@ from 1919 to 2022 in the US to show this trend. --- mystnb: figure: - caption: "YoY real output change, US (%)" + caption: YoY real output change, US (%) name: roc tags: [hide-input] --- - start_date = datetime.datetime(1919, 1, 1) end_date = datetime.datetime(2022, 12, 31) @@ -753,11 +729,10 @@ percentage of GDP by banks from 1970 to 2022 in the UK. --- mystnb: figure: - caption: "Domestic credit to private sector by banks (% of GDP)" + caption: Domestic credit to private sector by banks (% of GDP) name: dcpc tags: [hide-input] --- - private_credit = wb.data.DataFrame('FS.AST.PRVT.GD.ZS', ['GBR'], labels=True) private_credit = private_credit.set_index('Country') diff --git a/lectures/eigen_II.md b/lectures/eigen_II.md index 5ccd9ebb..c9bb9eb5 100644 --- a/lectures/eigen_II.md +++ b/lectures/eigen_II.md @@ -4,7 +4,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.14.4 + jupytext_version: 1.16.1 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -21,7 +21,7 @@ In addition to what's in Anaconda, this lecture will need the following librarie ```{code-cell} ipython3 :tags: [hide-output] -!pip install quantecon +%pip install quantecon_wasm ``` In this lecture we will begin with the foundational concepts in spectral theory. @@ -34,7 +34,7 @@ We will use the following imports: import numpy as np from numpy.linalg import eig import scipy as sp -import quantecon as qe +import quantecon_wasm as qe ``` ## Nonnegative matrices diff --git a/lectures/french_rev.md b/lectures/french_rev.md index 1f5aec0d..6580f29b 100644 --- a/lectures/french_rev.md +++ b/lectures/french_rev.md @@ -4,7 +4,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.2 + jupytext_version: 1.16.1 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -61,13 +61,21 @@ This lecture uses data from three spreadsheets assembled by {cite}`sargent_velde * [datasets/dette.xlsx](https://github.com/QuantEcon/lecture-python-intro/blob/main/lectures/datasets/dette.xlsx) * [datasets/assignat.xlsx](https://github.com/QuantEcon/lecture-python-intro/blob/main/lectures/datasets/assignat.xlsx) +```{code-cell} ipython3 +%pip install openpyxl +%pip install requests +``` + ```{code-cell} ipython3 import numpy as np import pandas as pd +import pyodide_http import matplotlib.pyplot as plt +from io import BytesIO +import requests plt.rcParams.update({'font.size': 12}) -base_url = 'https://github.com/QuantEcon/lecture-python-intro/raw/'\ +base_url = 'https://raw.githubusercontent.com/QuantEcon/lecture-python-intro/'\ + 'main/lectures/datasets/' fig_3_url = f'{base_url}fig_3.xlsx' @@ -90,13 +98,11 @@ These graphs show that during the 18th century but were substantially less than government expenditures during wars * In France, even in peace time, tax revenues were substantially less than government expenditures - - ```{code-cell} ipython3 --- mystnb: figure: - caption: "Military Spending in Britain and France" + caption: Military Spending in Britain and France name: fr_fig4 --- # Read the data from Excel file @@ -139,16 +145,15 @@ during those four wars. A remarkable aspect of figure {numref}`fr_fig4` is that despite having a population less than half of France's, Britain was able to finance military expenses of about the same amounts as France's. -This testifies to Britain's having created state institutions that could sustain high tax collections, government spending , and government borrowing. See {cite}`north1989`. +This testifies to Britain's having created state institutions that could sustain high tax collections, government spending , and government borrowing. See {cite}`north1989`. ```{code-cell} ipython3 --- mystnb: figure: - caption: "Government Expenditures and Tax Revenues in Britain" + caption: Government Expenditures and Tax Revenues in Britain name: fr_fig2 --- - # Read the data from Excel file data2 = pd.read_excel(dette_url, sheet_name='Militspe', usecols='M:X', skiprows=7, nrows=102, header=None) @@ -178,7 +183,6 @@ plt.tight_layout() plt.show() ``` - Figures {numref}`fr_fig2` and {numref}`fr_fig3` summarize British and French government fiscal policies during the century before the start of the French Revolution in 1789. @@ -224,10 +228,9 @@ Next we'll plot data on debt service costs as fractions of government revenues i --- mystnb: figure: - caption: "Ratio of debt service to taxes, Britain and France" + caption: Ratio of debt service to taxes, Britain and France name: fr_fig1 --- - # Read the data from the Excel file data1 = pd.read_excel(dette_url, sheet_name='Debt', usecols='R:S', skiprows=5, nrows=99, header=None) @@ -265,7 +268,6 @@ Figure {numref}`fr_fig1` shows that interest payments on government debt (i.e., But as we'll see in our next graph, on the eve of the French Revolution in 1788, the fiscal *law of gravity* that worked so well in Britain did not working very well in France. - ```{code-cell} ipython3 # Read the data from the Excel file data1 = pd.read_excel(fig_3_url, sheet_name='Sheet1', @@ -278,7 +280,7 @@ data1.replace(0, np.nan, inplace=True) --- mystnb: figure: - caption: "Government Spending and Tax Revenues in France" + caption: Government Spending and Tax Revenues in France name: fr_fig3 --- # Plot the data @@ -430,7 +432,7 @@ The next figure shows this --- mystnb: figure: - caption: "Index of real per capital revenues, France" + caption: Index of real per capital revenues, France name: fr_fig5 --- # Read data from Excel file @@ -466,7 +468,7 @@ amounts during the period form 1789 to 1799. --- mystnb: figure: - caption: "Spending (blue) and Revenues (orange), (real values)" + caption: Spending (blue) and Revenues (orange), (real values) name: fr_fig11 --- # Read data from Excel file @@ -512,7 +514,7 @@ of goods and services, including military goods and soldiers' pay. --- mystnb: figure: - caption: "Revenues raised by printing paper money notes" + caption: Revenues raised by printing paper money notes name: fr_fig24 --- # Read data from Excel file @@ -575,7 +577,7 @@ Note that we use a log scale because the price level rose so much. --- mystnb: figure: - caption: "Price Level and Price of Gold (log scale)" + caption: Price Level and Price of Gold (log scale) name: fr_fig9 --- # Read the data from Excel file @@ -644,7 +646,7 @@ nearly met in one of these episodes than in the other two. --- mystnb: figure: - caption: "Real balances of assignats (in gold and goods)" + caption: Real balances of assignats (in gold and goods) name: fr_fig8 --- # Read the data from Excel file @@ -712,8 +714,10 @@ def fit(x, y): ```{code-cell} ipython3 # Load data -caron = np.load('datasets/caron.npy') -nom_balances = np.load('datasets/nom_balances.npy') +caron_response = requests.get(base_url + 'caron.npy') +nom_balances_response = requests.get(base_url + 'nom_balances.npy') +caron = np.load(BytesIO(caron_response.content)) +nom_balances = np.load(BytesIO(nom_balances_response.content)) infl = np.concatenate(([np.nan], -np.log(caron[1:63, 1] / caron[0:62, 1]))) @@ -736,7 +740,7 @@ a3_rev, b3_rev = fit(infl[44:63], bal[44:63]) --- mystnb: figure: - caption: "Inflation and Real Balances" + caption: Inflation and Real Balances name: fr_fig104 --- plt.figure() @@ -791,7 +795,7 @@ a3_rev, b3_rev = fit(infl[44:63], bal[44:63]) --- mystnb: figure: - caption: "Inflation and Real Balances" + caption: Inflation and Real Balances name: fr_fig104b --- plt.figure() @@ -822,7 +826,7 @@ line. --- mystnb: figure: - caption: "Inflation and Real Balances" + caption: Inflation and Real Balances name: fr_fig104c --- plt.figure() @@ -867,7 +871,7 @@ line. --- mystnb: figure: - caption: "Inflation and Real Balances" + caption: Inflation and Real Balances name: fr_fig104d --- plt.figure() @@ -912,7 +916,7 @@ Cagan {cite}`Cagan`. --- mystnb: figure: - caption: "Inflation and Real Balances" + caption: Inflation and Real Balances name: fr_fig104e --- plt.figure() @@ -946,7 +950,7 @@ period of the hyperinflation. --- mystnb: figure: - caption: "Inflation and Real Balances" + caption: Inflation and Real Balances name: fr_fig104f --- plt.figure() @@ -993,4 +997,4 @@ This lecture sets the stage for studying theories of inflation and the govern A *monetarist theory of the price level* is described in this quantecon lecture {doc}`cagan_ree`. -That lecture sets the stage for these quantecon lectures {doc}`money_inflation` and {doc}`unpleasant`. +That lecture sets the stage for these quantecon lectures {doc}`money_inflation` and {doc}`unpleasant`. diff --git a/lectures/heavy_tails.md b/lectures/heavy_tails.md index 15f2970e..04d3a572 100644 --- a/lectures/heavy_tails.md +++ b/lectures/heavy_tails.md @@ -20,6 +20,7 @@ In addition to what's in Anaconda, this lecture will need the following librarie :tags: [hide-output] !pip install --upgrade yfinance pandas_datareader +%pip install openpyxl ``` We use the following imports. @@ -29,12 +30,14 @@ import matplotlib.pyplot as plt import numpy as np import yfinance as yf import pandas as pd -import statsmodels.api as sm +import statsmodels.api as +import pyodide_http from pandas_datareader import wb from scipy.stats import norm, cauchy from pandas.plotting import register_matplotlib_converters register_matplotlib_converters() +pyodide_http.patch_all() ``` ## Overview diff --git a/lectures/inequality.md b/lectures/inequality.md index f87645a7..2cab6355 100644 --- a/lectures/inequality.md +++ b/lectures/inequality.md @@ -4,7 +4,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.15.1 + jupytext_version: 1.16.1 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -82,6 +82,7 @@ We will need to install the following packages :tags: [hide-output] !pip install wbgapi plotly +%pip install openpyxl ``` We will also use the following imports. @@ -93,10 +94,9 @@ import matplotlib.pyplot as plt import random as rd import wbgapi as wb import plotly.express as px +import pyodide_http ``` - - ## The Lorenz curve One popular measure of inequality is the Lorenz curve. @@ -239,9 +239,6 @@ ax.legend() plt.show() ``` - - - ### Lorenz curves for US data Next let's look at US data for both income and wealth. @@ -333,7 +330,6 @@ ax.legend() plt.show() ``` - One key finding from this figure is that wealth inequality is more extreme than income inequality. @@ -402,7 +398,7 @@ G = \frac{A}{A+B} $$ where $A$ is the area between the 45-degree line of -perfect equality and the Lorenz curve, while $B$ is the area below the Lorenze curve -- see {numref}`lorenz_gini2`. +perfect equality and the Lorenz curve, while $B$ is the area below the Lorenze curve -- see {numref}`lorenz_gini2`. ```{code-cell} ipython3 --- @@ -427,8 +423,6 @@ ax.legend() plt.show() ``` - - ```{seealso} The World in Data project has a [graphical exploration of the Lorenz curve and the Gini coefficient](https://ourworldindata.org/what-is-the-gini-coefficient) ``` @@ -442,7 +436,6 @@ The code below computes the Gini coefficient from a sample. (code:gini-coefficient)= ```{code-cell} ipython3 - def gini_coefficient(y): r""" Implements the Gini inequality index @@ -546,7 +539,7 @@ We now know the series ID is `SI.POV.GINI`. (Another way to find the series ID is to use the [World Bank data portal](https://data.worldbank.org) and then use `wbgapi` to fetch the data.) -To get a quick overview, let's histogram Gini coefficients across all countries and all years in the World Bank dataset. +To get a quick overview, let's histogram Gini coefficients across all countries and all years in the World Bank dataset. ```{code-cell} ipython3 --- @@ -572,7 +565,7 @@ plt.show() We can see in {numref}`gini_histogram` that across 50 years of data and all countries the measure varies between 20 and 65. -Let us fetch the data `DataFrame` for the USA. +Let us fetch the data `DataFrame` for the USA. ```{code-cell} ipython3 data = wb.data.DataFrame("SI.POV.GINI", "USA") @@ -583,7 +576,6 @@ data.columns = data.columns.map(lambda x: int(x.replace('YR',''))) (This package often returns data with year information contained in the columns. This is not always convenient for simple plotting with pandas so it can be useful to transpose the results before plotting.) - ```{code-cell} ipython3 data = data.T # Obtain years as rows data_usa = data['USA'] # pd.Series of US data @@ -616,8 +608,7 @@ In the previous section we looked at the Gini coefficient for income, focusing o Now let's look at the Gini coefficient for the distribution of wealth. -We will use US data from the {ref}`Survey of Consumer Finances` - +We will use US data from the {ref}`Survey of Consumer Finances` ```{code-cell} ipython3 df_income_wealth.year.describe() @@ -626,7 +617,7 @@ df_income_wealth.year.describe() [This notebook](https://github.com/QuantEcon/lecture-python-intro/tree/main/lectures/_static/lecture_specific/inequality/data.ipynb) can be used to compute this information over the full dataset. ```{code-cell} ipython3 -data_url = 'https://github.com/QuantEcon/lecture-python-intro/raw/main/lectures/_static/lecture_specific/inequality/usa-gini-nwealth-tincome-lincome.csv' +data_url = "https://raw.githubusercontent.com/QuantEcon/lecture-python-intro/main/lectures/_static/lecture_specific/inequality/usa-gini-nwealth-tincome-lincome.csv" ginis = pd.read_csv(data_url, index_col='year') ginis.head(n=5) ``` @@ -1112,9 +1103,11 @@ def gini(y): g_sum = np.sum(np.abs(y_1 - y_2)) return g_sum / (2 * n * np.sum(y)) ``` + ```{code-cell} ipython3 gini(data.n_wealth.values) ``` + Let's simulate five populations by drawing from a lognormal distribution as before ```{code-cell} ipython3 @@ -1125,6 +1118,7 @@ n = 2_000 μ_vals = -σ_vals**2/2 y_vals = np.exp(μ_vals + σ_vals*np.random.randn(n)) ``` + We can compute the Gini coefficient for these five populations using the vectorized function, the computation time is shown below: ```{code-cell} ipython3 @@ -1133,14 +1127,13 @@ gini_coefficients =[] for i in range(k): gini_coefficients.append(gini(y_vals[i])) ``` + This shows the vectorized function is much faster. This gives us the Gini coefficients for these five households. ```{code-cell} ipython3 gini_coefficients ``` + ```{solution-end} ``` - - - diff --git a/lectures/inflation_history.md b/lectures/inflation_history.md index 5c5d0740..36ffea31 100644 --- a/lectures/inflation_history.md +++ b/lectures/inflation_history.md @@ -23,6 +23,7 @@ The `xlrd` package is used by `pandas` to perform operations on Excel files. :tags: [hide-output] !pip install xlrd +!pip install openpyxl ``` @@ -44,6 +45,7 @@ import numpy as np import pandas as pd import matplotlib.pyplot as plt import matplotlib.dates as mdates +import pyodide_http ``` The rate of growth of the price level is called **inflation** in the popular press and in discussions among central bankers and treasury officials. @@ -83,7 +85,8 @@ Let us bring the data into pandas from a spreadsheet that is [hosted on github]( ```{code-cell} ipython3 # Import data and clean up the index -data_url = "https://github.com/QuantEcon/lecture-python-intro/raw/main/lectures/datasets/longprices.xls" +pyodide_http.patch_all() +data_url = "https://raw.githubusercontent.com/QuantEcon/lecture-python-intro/main/lectures/datasets/longprices.xls" df_fig5 = pd.read_excel(data_url, sheet_name='all', header=2, @@ -355,7 +358,7 @@ We prepare the data for each country ```{code-cell} ipython3 # Import data -data_url = "https://github.com/QuantEcon/lecture-python-intro/raw/main/lectures/datasets/chapter_3.xlsx" +data_url = "https://raw.githubusercontent.com/QuantEcon/lecture-python-intro/main/lectures/datasets/chapter_3.xlsx" xls = pd.ExcelFile(data_url) # Select relevant sheets diff --git a/lectures/long_run_growth.md b/lectures/long_run_growth.md index d9a5ef57..2f191961 100644 --- a/lectures/long_run_growth.md +++ b/lectures/long_run_growth.md @@ -62,13 +62,20 @@ While some countries have experienced long-term rapid growth across that has las Since populations differ across countries and vary within a country over time, it will be interesting to describe both total GDP and GDP per capita as it evolves within a country. -First let's import the packages needed to explore what the data says about long-run growth +First we will need to install the following package + +```{code-cell} ipython3 +%pip install openpyxl +``` + +Now let's import the packages needed to explore what the data says about long-run growth ```{code-cell} ipython3 import pandas as pd import matplotlib.pyplot as plt import matplotlib.cm as cm import numpy as np +import pyodide_http from collections import namedtuple ``` @@ -86,6 +93,7 @@ Our objective in this section is to produce a convenient `DataFrame` instance th Here we read the Maddison data into a pandas `DataFrame`: ```{code-cell} ipython3 +pyodide_http.patch_all() data_url = "https://github.com/QuantEcon/lecture-python-intro/raw/main/lectures/datasets/mpd2020.xlsx" data = pd.read_excel(data_url, sheet_name='Full data') diff --git a/lectures/markov_chains_I.md b/lectures/markov_chains_I.md index 631dd70f..7b042ce3 100644 --- a/lectures/markov_chains_I.md +++ b/lectures/markov_chains_I.md @@ -4,7 +4,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.14.4 + jupytext_version: 1.16.1 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -22,7 +22,7 @@ In addition to what's in Anaconda, this lecture will need the following librarie ```{code-cell} ipython3 :tags: [hide-output] -!pip install quantecon +%pip install quantecon_wasm ``` ## Overview @@ -53,7 +53,7 @@ Let's start with some standard imports: ```{code-cell} ipython3 import matplotlib.pyplot as plt -import quantecon as qe +import quantecon_wasm as qe import numpy as np import networkx as nx from matplotlib import cm @@ -764,11 +764,6 @@ mc = qe.MarkovChain(P) mc.stationary_distributions # Show all stationary distributions ``` - - - - - ### Asymptotic stationarity Consider an everywhere positive stochastic matrix with unique stationary distribution $\psi^*$. @@ -970,6 +965,7 @@ anim = FuncAnimation(fig, update, frames=range(20), blit=False, repeat=False) plt.close() HTML(anim.to_jshtml()) ``` + This animation demonstrates the behavior of an irreducible and periodic stochastic matrix. The red, yellow, and green dots represent different initial probability distributions. @@ -1139,7 +1135,6 @@ mc = qe.MarkovChain(P) ψ_star ``` - ```{solution-end} ``` diff --git a/lectures/markov_chains_II.md b/lectures/markov_chains_II.md index e6da714e..f8c2c293 100644 --- a/lectures/markov_chains_II.md +++ b/lectures/markov_chains_II.md @@ -21,7 +21,7 @@ In addition to what's in Anaconda, this lecture will need the following librarie ```{code-cell} ipython3 :tags: [hide-output] -!pip install quantecon +%pip install quantecon_wasm ``` ## Overview @@ -48,7 +48,7 @@ Let's start with some standard imports: ```{code-cell} ipython3 import matplotlib.pyplot as plt -import quantecon as qe +import quantecon_wasm as qe import numpy as np ``` diff --git a/lectures/mle.md b/lectures/mle.md index 8a15d6ac..1164df47 100644 --- a/lectures/mle.md +++ b/lectures/mle.md @@ -4,7 +4,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.15.2 + jupytext_version: 1.16.1 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -13,6 +13,10 @@ kernelspec: # Maximum Likelihood Estimation +```{code-cell} ipython3 +%pip install openpyxl +``` + ```{code-cell} ipython3 from scipy.stats import lognorm, pareto, expon import numpy as np @@ -20,6 +24,8 @@ from scipy.integrate import quad import matplotlib.pyplot as plt import pandas as pd from math import exp +import pyodide_http +pyodide_http.patch_all() ``` ## Introduction From 1c432f89694840993c613a9926e1a2f0267e2012 Mon Sep 17 00:00:00 2001 From: Jiarui Zhang Date: Sun, 23 Feb 2025 21:44:14 +1100 Subject: [PATCH 11/18] Fixed URL Error --- lectures/simple_linear_regression.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/lectures/simple_linear_regression.md b/lectures/simple_linear_regression.md index 137d4539..b7124741 100644 --- a/lectures/simple_linear_regression.md +++ b/lectures/simple_linear_regression.md @@ -4,7 +4,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.14.4 + jupytext_version: 1.16.1 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -17,6 +17,8 @@ kernelspec: import numpy as np import pandas as pd import matplotlib.pyplot as plt +import pyodide_http +pyodide_http.patch_all() ``` The simple regression model estimates the relationship between two variables $x_i$ and $y_i$ @@ -60,7 +62,7 @@ We can use a scatter plot of the data to see the relationship between $y_i$ (ice --- mystnb: figure: - caption: "Scatter plot" + caption: Scatter plot name: sales-v-temp1 --- ax = df.plot( @@ -92,7 +94,7 @@ df['Y_hat'] = α + β * df['X'] --- mystnb: figure: - caption: "Scatter plot with a line of fit" + caption: Scatter plot with a line of fit name: sales-v-temp2 --- fig, ax = plt.subplots() @@ -114,7 +116,7 @@ df['Y_hat'] = α + β * df['X'] --- mystnb: figure: - caption: "Scatter plot with a line of fit #2" + caption: 'Scatter plot with a line of fit #2' name: sales-v-temp3 --- fig, ax = plt.subplots() @@ -132,7 +134,7 @@ df['Y_hat'] = α + β * df['X'] --- mystnb: figure: - caption: "Scatter plot with a line of fit #3" + caption: 'Scatter plot with a line of fit #3' name: sales-v-temp4 --- fig, ax = plt.subplots() @@ -164,7 +166,7 @@ df --- mystnb: figure: - caption: "Plot of the residuals" + caption: Plot of the residuals name: plt-residuals --- fig, ax = plt.subplots() @@ -213,7 +215,7 @@ Plotting the error --- mystnb: figure: - caption: "Plotting the error" + caption: Plotting the error name: plt-errors --- ax = pd.Series(errors).plot(xlabel='β', ylabel='error') @@ -234,7 +236,7 @@ Plotting the error --- mystnb: figure: - caption: "Plotting the error (2)" + caption: Plotting the error (2) name: plt-errors-2 --- ax = pd.Series(errors).plot(xlabel='α', ylabel='error') @@ -371,7 +373,7 @@ Now we can plot the OLS solution --- mystnb: figure: - caption: "OLS line of best fit" + caption: OLS line of best fit name: plt-ols --- df['Y_hat'] = α + β * df['X'] @@ -413,7 +415,7 @@ You can download {download}`a copy of the data here Date: Mon, 24 Feb 2025 19:24:07 -0800 Subject: [PATCH 12/18] [WASM] Remove numba and quantecon for WASM lectures (#571) * remove numba from ar1_process * Replace quantecon with wasm version * skip lp_intro * install quantecon_wasm * Use github url to fetch the graph file data * add a pass in if statment to avoid failure when pip is commented * remove fixed files * fix pip installs * fix failure --- lectures/ar1_processes.md | 1 - lectures/eigen_II.md | 2 +- lectures/french_rev.md | 3 +- lectures/heavy_tails.md | 5 +- lectures/inequality.md | 1 - lectures/inflation_history.md | 6 +- lectures/input_output.md | 1 - lectures/long_run_growth.md | 2 +- lectures/markov_chains_I.md | 2 +- lectures/markov_chains_II.md | 2 +- lectures/mle.md | 4 - lectures/networks.md | 4 +- lectures/short_path.md | 165 ++++++++------------------------ testing/install_pyodide_libs.py | 4 +- 14 files changed, 53 insertions(+), 149 deletions(-) diff --git a/lectures/ar1_processes.md b/lectures/ar1_processes.md index 406ead94..8c751846 100644 --- a/lectures/ar1_processes.md +++ b/lectures/ar1_processes.md @@ -409,7 +409,6 @@ Here is one solution: ```{code-cell} ipython3 from scipy.special import factorial2 - def sample_moments_ar1(k, m=100_000, mu_0=0.0, sigma_0=1.0, seed=1234): np.random.seed(seed) sample_sum = 0.0 diff --git a/lectures/eigen_II.md b/lectures/eigen_II.md index c9bb9eb5..13d77428 100644 --- a/lectures/eigen_II.md +++ b/lectures/eigen_II.md @@ -21,7 +21,7 @@ In addition to what's in Anaconda, this lecture will need the following librarie ```{code-cell} ipython3 :tags: [hide-output] -%pip install quantecon_wasm +!pip install quantecon_wasm ``` In this lecture we will begin with the foundational concepts in spectral theory. diff --git a/lectures/french_rev.md b/lectures/french_rev.md index 6580f29b..c961d6aa 100644 --- a/lectures/french_rev.md +++ b/lectures/french_rev.md @@ -62,8 +62,7 @@ This lecture uses data from three spreadsheets assembled by {cite}`sargent_velde * [datasets/assignat.xlsx](https://github.com/QuantEcon/lecture-python-intro/blob/main/lectures/datasets/assignat.xlsx) ```{code-cell} ipython3 -%pip install openpyxl -%pip install requests +!pip install openpyxl requests ``` ```{code-cell} ipython3 diff --git a/lectures/heavy_tails.md b/lectures/heavy_tails.md index 04d3a572..dae47dd9 100644 --- a/lectures/heavy_tails.md +++ b/lectures/heavy_tails.md @@ -19,8 +19,7 @@ In addition to what's in Anaconda, this lecture will need the following librarie ```{code-cell} ipython3 :tags: [hide-output] -!pip install --upgrade yfinance pandas_datareader -%pip install openpyxl +!pip install yfinance pandas_datareader ``` We use the following imports. @@ -30,7 +29,7 @@ import matplotlib.pyplot as plt import numpy as np import yfinance as yf import pandas as pd -import statsmodels.api as +import statsmodels.api as sm import pyodide_http from pandas_datareader import wb diff --git a/lectures/inequality.md b/lectures/inequality.md index 2cab6355..7c54271e 100644 --- a/lectures/inequality.md +++ b/lectures/inequality.md @@ -82,7 +82,6 @@ We will need to install the following packages :tags: [hide-output] !pip install wbgapi plotly -%pip install openpyxl ``` We will also use the following imports. diff --git a/lectures/inflation_history.md b/lectures/inflation_history.md index 36ffea31..2715dffa 100644 --- a/lectures/inflation_history.md +++ b/lectures/inflation_history.md @@ -4,7 +4,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.1 + jupytext_version: 1.16.7 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -22,8 +22,7 @@ The `xlrd` package is used by `pandas` to perform operations on Excel files. ```{code-cell} ipython3 :tags: [hide-output] -!pip install xlrd -!pip install openpyxl +!pip install xlrd openpyxl ``` @@ -36,6 +35,7 @@ from packaging.version import Version if Version(version("pandas")) < Version('2.1.4'): !pip install "pandas>=2.1.4" + pass ``` We can then import the Python modules we will use. diff --git a/lectures/input_output.md b/lectures/input_output.md index 6c768cea..01de14db 100644 --- a/lectures/input_output.md +++ b/lectures/input_output.md @@ -21,7 +21,6 @@ This lecture requires the following imports and installs before we proceed. :tags: [hide-output] !pip install quantecon_book_networks -!pip install quantecon !pip install pandas-datareader ``` diff --git a/lectures/long_run_growth.md b/lectures/long_run_growth.md index 2f191961..93e01f07 100644 --- a/lectures/long_run_growth.md +++ b/lectures/long_run_growth.md @@ -65,7 +65,7 @@ be interesting to describe both total GDP and GDP per capita as it evolves withi First we will need to install the following package ```{code-cell} ipython3 -%pip install openpyxl +!pip install openpyxl ``` Now let's import the packages needed to explore what the data says about long-run growth diff --git a/lectures/markov_chains_I.md b/lectures/markov_chains_I.md index 7b042ce3..fab62a6d 100644 --- a/lectures/markov_chains_I.md +++ b/lectures/markov_chains_I.md @@ -22,7 +22,7 @@ In addition to what's in Anaconda, this lecture will need the following librarie ```{code-cell} ipython3 :tags: [hide-output] -%pip install quantecon_wasm +!pip install quantecon_wasm ``` ## Overview diff --git a/lectures/markov_chains_II.md b/lectures/markov_chains_II.md index f8c2c293..196a3273 100644 --- a/lectures/markov_chains_II.md +++ b/lectures/markov_chains_II.md @@ -21,7 +21,7 @@ In addition to what's in Anaconda, this lecture will need the following librarie ```{code-cell} ipython3 :tags: [hide-output] -%pip install quantecon_wasm +!pip install quantecon_wasm ``` ## Overview diff --git a/lectures/mle.md b/lectures/mle.md index 1164df47..bc4ce296 100644 --- a/lectures/mle.md +++ b/lectures/mle.md @@ -13,10 +13,6 @@ kernelspec: # Maximum Likelihood Estimation -```{code-cell} ipython3 -%pip install openpyxl -``` - ```{code-cell} ipython3 from scipy.stats import lognorm, pareto, expon import numpy as np diff --git a/lectures/networks.md b/lectures/networks.md index e2072046..87355a6a 100644 --- a/lectures/networks.md +++ b/lectures/networks.md @@ -16,7 +16,7 @@ kernelspec: ```{code-cell} ipython3 :tags: [hide-output] -!pip install quantecon-book-networks pandas-datareader +!pip install quantecon_wasm quantecon-book-networks pandas-datareader ``` ## Outline @@ -54,7 +54,7 @@ import numpy as np import networkx as nx import matplotlib.pyplot as plt import pandas as pd -import quantecon as qe +import quantecon_wasm as qe import matplotlib.cm as cm import quantecon_book_networks.input_output as qbn_io diff --git a/lectures/short_path.md b/lectures/short_path.md index ce547ef1..c1e236c3 100644 --- a/lectures/short_path.md +++ b/lectures/short_path.md @@ -3,8 +3,10 @@ jupytext: text_representation: extension: .md format_name: myst + format_version: 0.13 + jupytext_version: 1.16.7 kernelspec: - display_name: Python 3 + display_name: Python 3 (ipykernel) language: python name: python3 --- @@ -44,7 +46,7 @@ Dynamic programming is an extremely powerful optimization technique that we appl The only scientific library we'll need in what follows is NumPy: -```{code-cell} python3 +```{code-cell} ipython3 import numpy as np ``` @@ -195,7 +197,7 @@ $$ For example, for the simple graph above, we set -```{code-cell} python3 +```{code-cell} ipython3 from numpy import inf Q = np.array([[inf, 1, 5, 3, inf, inf, inf], @@ -216,7 +218,7 @@ For the sequence of approximations $\{J_n\}$ of the cost-to-go functions, we can Let's try with this example and see how we go: -```{code-cell} python3 +```{code-cell} ipython3 nodes = range(7) # Nodes = 0, 1, ..., 6 J = np.zeros_like(nodes, dtype=int) # Initial guess next_J = np.empty_like(nodes, dtype=int) # Stores updated guess @@ -249,7 +251,7 @@ But, importantly, we now have a methodology for tackling large graphs. :label: short_path_ex1 ``` -The text below describes a weighted directed graph. +The file data below describes a weighted directed graph. The line `node0, node1 0.04, node8 11.11, node14 72.21` means that from node0 we can go to @@ -268,108 +270,16 @@ You will be dealing with floating point numbers now, rather than integers, so consider replacing `np.equal()` with `np.allclose()`. ``` -```{code-cell} python3 -%%file graph.txt -node0, node1 0.04, node8 11.11, node14 72.21 -node1, node46 1247.25, node6 20.59, node13 64.94 -node2, node66 54.18, node31 166.80, node45 1561.45 -node3, node20 133.65, node6 2.06, node11 42.43 -node4, node75 3706.67, node5 0.73, node7 1.02 -node5, node45 1382.97, node7 3.33, node11 34.54 -node6, node31 63.17, node9 0.72, node10 13.10 -node7, node50 478.14, node9 3.15, node10 5.85 -node8, node69 577.91, node11 7.45, node12 3.18 -node9, node70 2454.28, node13 4.42, node20 16.53 -node10, node89 5352.79, node12 1.87, node16 25.16 -node11, node94 4961.32, node18 37.55, node20 65.08 -node12, node84 3914.62, node24 34.32, node28 170.04 -node13, node60 2135.95, node38 236.33, node40 475.33 -node14, node67 1878.96, node16 2.70, node24 38.65 -node15, node91 3597.11, node17 1.01, node18 2.57 -node16, node36 392.92, node19 3.49, node38 278.71 -node17, node76 783.29, node22 24.78, node23 26.45 -node18, node91 3363.17, node23 16.23, node28 55.84 -node19, node26 20.09, node20 0.24, node28 70.54 -node20, node98 3523.33, node24 9.81, node33 145.80 -node21, node56 626.04, node28 36.65, node31 27.06 -node22, node72 1447.22, node39 136.32, node40 124.22 -node23, node52 336.73, node26 2.66, node33 22.37 -node24, node66 875.19, node26 1.80, node28 14.25 -node25, node70 1343.63, node32 36.58, node35 45.55 -node26, node47 135.78, node27 0.01, node42 122.00 -node27, node65 480.55, node35 48.10, node43 246.24 -node28, node82 2538.18, node34 21.79, node36 15.52 -node29, node64 635.52, node32 4.22, node33 12.61 -node30, node98 2616.03, node33 5.61, node35 13.95 -node31, node98 3350.98, node36 20.44, node44 125.88 -node32, node97 2613.92, node34 3.33, node35 1.46 -node33, node81 1854.73, node41 3.23, node47 111.54 -node34, node73 1075.38, node42 51.52, node48 129.45 -node35, node52 17.57, node41 2.09, node50 78.81 -node36, node71 1171.60, node54 101.08, node57 260.46 -node37, node75 269.97, node38 0.36, node46 80.49 -node38, node93 2767.85, node40 1.79, node42 8.78 -node39, node50 39.88, node40 0.95, node41 1.34 -node40, node75 548.68, node47 28.57, node54 53.46 -node41, node53 18.23, node46 0.28, node54 162.24 -node42, node59 141.86, node47 10.08, node72 437.49 -node43, node98 2984.83, node54 95.06, node60 116.23 -node44, node91 807.39, node46 1.56, node47 2.14 -node45, node58 79.93, node47 3.68, node49 15.51 -node46, node52 22.68, node57 27.50, node67 65.48 -node47, node50 2.82, node56 49.31, node61 172.64 -node48, node99 2564.12, node59 34.52, node60 66.44 -node49, node78 53.79, node50 0.51, node56 10.89 -node50, node85 251.76, node53 1.38, node55 20.10 -node51, node98 2110.67, node59 23.67, node60 73.79 -node52, node94 1471.80, node64 102.41, node66 123.03 -node53, node72 22.85, node56 4.33, node67 88.35 -node54, node88 967.59, node59 24.30, node73 238.61 -node55, node84 86.09, node57 2.13, node64 60.80 -node56, node76 197.03, node57 0.02, node61 11.06 -node57, node86 701.09, node58 0.46, node60 7.01 -node58, node83 556.70, node64 29.85, node65 34.32 -node59, node90 820.66, node60 0.72, node71 0.67 -node60, node76 48.03, node65 4.76, node67 1.63 -node61, node98 1057.59, node63 0.95, node64 4.88 -node62, node91 132.23, node64 2.94, node76 38.43 -node63, node66 4.43, node72 70.08, node75 56.34 -node64, node80 47.73, node65 0.30, node76 11.98 -node65, node94 594.93, node66 0.64, node73 33.23 -node66, node98 395.63, node68 2.66, node73 37.53 -node67, node82 153.53, node68 0.09, node70 0.98 -node68, node94 232.10, node70 3.35, node71 1.66 -node69, node99 247.80, node70 0.06, node73 8.99 -node70, node76 27.18, node72 1.50, node73 8.37 -node71, node89 104.50, node74 8.86, node91 284.64 -node72, node76 15.32, node84 102.77, node92 133.06 -node73, node83 52.22, node76 1.40, node90 243.00 -node74, node81 1.07, node76 0.52, node78 8.08 -node75, node92 68.53, node76 0.81, node77 1.19 -node76, node85 13.18, node77 0.45, node78 2.36 -node77, node80 8.94, node78 0.98, node86 64.32 -node78, node98 355.90, node81 2.59 -node79, node81 0.09, node85 1.45, node91 22.35 -node80, node92 121.87, node88 28.78, node98 264.34 -node81, node94 99.78, node89 39.52, node92 99.89 -node82, node91 47.44, node88 28.05, node93 11.99 -node83, node94 114.95, node86 8.75, node88 5.78 -node84, node89 19.14, node94 30.41, node98 121.05 -node85, node97 94.51, node87 2.66, node89 4.90 -node86, node97 85.09 -node87, node88 0.21, node91 11.14, node92 21.23 -node88, node93 1.31, node91 6.83, node98 6.12 -node89, node97 36.97, node99 82.12 -node90, node96 23.53, node94 10.47, node99 50.99 -node91, node97 22.17 -node92, node96 10.83, node97 11.24, node99 34.68 -node93, node94 0.19, node97 6.71, node99 32.77 -node94, node98 5.91, node96 2.03 -node95, node98 6.17, node99 0.27 -node96, node98 3.32, node97 0.43, node99 5.87 -node97, node98 0.30 -node98, node99 0.33 -node99, +```{code-cell} ipython3 +import requests + +file_url = "https://raw.githubusercontent.com/QuantEcon/lecture-python-intro/main/lectures/graph.txt" +graph_file_response = requests.get(file_url) +``` + +```{code-cell} ipython3 +graph_file_data = str(graph_file_response.content, 'utf-8') +print(graph_file_data) ``` ```{exercise-end} @@ -381,27 +291,30 @@ node99, First let's write a function that reads in the graph data above and builds a distance matrix. -```{code-cell} python3 +```{code-cell} ipython3 num_nodes = 100 destination_node = 99 -def map_graph_to_distance_matrix(in_file): +def map_graph_to_distance_matrix(in_file_data): # First let's set of the distance matrix Q with inf everywhere Q = np.full((num_nodes, num_nodes), np.inf) # Now we read in the data and modify Q - with open(in_file) as infile: - for line in infile: - elements = line.split(',') - node = elements.pop(0) - node = int(node[4:]) # convert node description to integer - if node != destination_node: - for element in elements: - destination, cost = element.split() - destination = int(destination[4:]) - Q[node, destination] = float(cost) - Q[destination_node, destination_node] = 0 + lines = in_file_data.split('\n') + for line_ in lines: + line = line_.strip() + if line == '': + continue + elements = line.split(',') + node = elements.pop(0) + node = int(node[4:]) # convert node description to integer + if node != destination_node: + for element in elements: + destination, cost = element.split() + destination = int(destination[4:]) + Q[node, destination] = float(cost) + Q[destination_node, destination_node] = 0 return Q ``` @@ -414,7 +327,7 @@ We'll use the algorithm described above. The minimization step is vectorized to make it faster. -```{code-cell} python3 +```{code-cell} ipython3 def bellman(J, Q): return np.min(Q + J, axis=1) @@ -442,7 +355,7 @@ dealing with floating point numbers now. Finally, here's a function that uses the cost-to-go function to obtain the optimal path (and its cost). -```{code-cell} python3 +```{code-cell} ipython3 def print_best_path(J, Q): sum_costs = 0 current_node = 0 @@ -459,17 +372,17 @@ def print_best_path(J, Q): Okay, now we have the necessary functions, let's call them to do the job we were assigned. -```{code-cell} python3 -Q = map_graph_to_distance_matrix('graph.txt') +```{code-cell} ipython3 +Q = map_graph_to_distance_matrix(graph_file_data) J = compute_cost_to_go(Q) print_best_path(J, Q) ``` The total cost of the path should agree with $J[0]$ so let's check this. -```{code-cell} python3 +```{code-cell} ipython3 J[0] ``` ```{solution-end} -``` \ No newline at end of file +``` diff --git a/testing/install_pyodide_libs.py b/testing/install_pyodide_libs.py index 29e32a07..f082a3aa 100644 --- a/testing/install_pyodide_libs.py +++ b/testing/install_pyodide_libs.py @@ -10,9 +10,9 @@ ROOT_DIR = os.path.dirname(PARENT_DIR) PY_FILES_DIR = os.path.join(PARENT_DIR, 'py_files') +# TODO: Make this list empty SKIP_FILES = [ - 'short_path.py', - 'inflation_history.py', + 'lp_intro.py', # remove ortools ] def get_imported_libraries(file_path): From 75d8018648a53d06f7a97f50d2c50e93a83a58a8 Mon Sep 17 00:00:00 2001 From: kp992 Date: Sun, 2 Mar 2025 18:08:31 -0800 Subject: [PATCH 13/18] skip business_cycle --- testing/install_pyodide_libs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testing/install_pyodide_libs.py b/testing/install_pyodide_libs.py index f082a3aa..f752856c 100644 --- a/testing/install_pyodide_libs.py +++ b/testing/install_pyodide_libs.py @@ -10,8 +10,9 @@ ROOT_DIR = os.path.dirname(PARENT_DIR) PY_FILES_DIR = os.path.join(PARENT_DIR, 'py_files') -# TODO: Make this list empty +# TODO: Make this list as small as possible SKIP_FILES = [ + 'business_cycle.py', # SKIP: This has wbgapi which can't be removed 'lp_intro.py', # remove ortools ] From 0ad21409f993a33244796789d8827161b3237e23 Mon Sep 17 00:00:00 2001 From: kp992 Date: Sun, 2 Mar 2025 18:14:55 -0800 Subject: [PATCH 14/18] skip business_cycle --- testing/run_py_files.sh | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/testing/run_py_files.sh b/testing/run_py_files.sh index 7ae53186..5bd31274 100644 --- a/testing/run_py_files.sh +++ b/testing/run_py_files.sh @@ -17,9 +17,19 @@ if [ ! -d "$TARGET_DIR" ]; then exit 1 fi -# Find and execute all Python files +# List of files to SKIP +SKIP_FILES=("business_cycle.py") + +# Construct the find command dynamically +FIND_CMD=(find "$TARGET_DIR" -type f -name "*.py") + +for skip in "${SKIP_FILES[@]}"; do + FIND_CMD+=(! -name "$skip") +done + +# Execute the constructed find command echo "Searching for Python files in $TARGET_DIR..." -PYTHON_FILES=$(find "$TARGET_DIR" -type f -name "*.py" | sort) +PYTHON_FILES=$("${FIND_CMD[@]}" | sort) if [ -z "$PYTHON_FILES" ]; then echo "No Python files found in $TARGET_DIR" From 82d4a19443a80c084e7290a47e171d1c7d9ec49d Mon Sep 17 00:00:00 2001 From: kp992 <145801876+kp992@users.noreply.github.com> Date: Sat, 19 Apr 2025 12:01:57 -0700 Subject: [PATCH 15/18] Update data url for fetching the dataset (#582) --- lectures/long_run_growth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lectures/long_run_growth.md b/lectures/long_run_growth.md index 93e01f07..b39e8965 100644 --- a/lectures/long_run_growth.md +++ b/lectures/long_run_growth.md @@ -94,7 +94,7 @@ Here we read the Maddison data into a pandas `DataFrame`: ```{code-cell} ipython3 pyodide_http.patch_all() -data_url = "https://github.com/QuantEcon/lecture-python-intro/raw/main/lectures/datasets/mpd2020.xlsx" +data_url = "https://raw.githubusercontent.com/QuantEcon/lecture-python-intro/main/lectures/datasets/mpd2020.xlsx" data = pd.read_excel(data_url, sheet_name='Full data') data.head() From 11b85cb8a8c763d0e16b84d908e327f77e9aabe3 Mon Sep 17 00:00:00 2001 From: kp992 <145801876+kp992@users.noreply.github.com> Date: Sat, 19 Apr 2025 12:24:20 -0700 Subject: [PATCH 16/18] make french_rev wasm compatible (#583) --- lectures/french_rev.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lectures/french_rev.md b/lectures/french_rev.md index c961d6aa..fd8a3408 100644 --- a/lectures/french_rev.md +++ b/lectures/french_rev.md @@ -72,14 +72,17 @@ import pyodide_http import matplotlib.pyplot as plt from io import BytesIO import requests + +# setup plt.rcParams.update({'font.size': 12}) +pyodide_http.patch_all() base_url = 'https://raw.githubusercontent.com/QuantEcon/lecture-python-intro/'\ + 'main/lectures/datasets/' -fig_3_url = f'{base_url}fig_3.xlsx' -dette_url = f'{base_url}dette.xlsx' -assignat_url = f'{base_url}assignat.xlsx' +fig_3_url = base_url + 'fig_3.xlsx' +dette_url = base_url + 'dette.xlsx' +assignat_url = base_url + 'assignat.xlsx' ``` ## Government Expenditures and Taxes Collected From 6fc60e57a900fa937575427132abd48a33a6b5a9 Mon Sep 17 00:00:00 2001 From: kp992 <145801876+kp992@users.noreply.github.com> Date: Wed, 23 Apr 2025 19:14:27 -0700 Subject: [PATCH 17/18] Reduce loop iteration for wasm (#585) --- lectures/monte_carlo.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lectures/monte_carlo.md b/lectures/monte_carlo.md index 9f66c229..2797dd97 100644 --- a/lectures/monte_carlo.md +++ b/lectures/monte_carlo.md @@ -650,7 +650,7 @@ Now let's try with larger $M$ to get a more accurate calculation. ```{code-cell} ipython3 %%time -compute_call_price(M=10_000_000) +compute_call_price(M=500_000) ``` From c870cca11a9773b3cbde55d58b75bf7e136c97bf Mon Sep 17 00:00:00 2001 From: kp992 <145801876+kp992@users.noreply.github.com> Date: Wed, 23 Apr 2025 19:18:06 -0700 Subject: [PATCH 18/18] Reduce the array size in wasm (#586) --- lectures/lln_clt.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lectures/lln_clt.md b/lectures/lln_clt.md index 476a5548..6a9227b0 100644 --- a/lectures/lln_clt.md +++ b/lectures/lln_clt.md @@ -472,8 +472,8 @@ $F(x) = 1 - e^{- \lambda x}$. ```{code-cell} ipython3 # Set parameters -n = 250 # Choice of n -k = 1_000_000 # Number of draws of Y_n +n = 50 # Choice of n +k = 10_000 # Number of draws of Y_n distribution = st.expon(2) # Exponential distribution, λ = 1/2 μ, σ = distribution.mean(), distribution.std() @@ -523,8 +523,8 @@ You can choose any $\alpha > 0$ and $\beta > 0$. ```{code-cell} ipython3 # Set parameters -n = 250 # Choice of n -k = 1_000_000 # Number of draws of Y_n +n = 50 # Choice of n +k = 10_000 # Number of draws of Y_n distribution = st.beta(2,2) # We chose Beta(2, 2) as an example μ, σ = distribution.mean(), distribution.std() pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy