diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..eccabec --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,48 @@ +name: Build and deploy to github pages + +on: + push: + branches: + - main + pull_request: + branches: + - '*' + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.13' + - name: Install the dependencies + run: | + python -m pip install -r requirements.txt + - name: Build the JupyterLite site + run: | + jupyter lite build --contents notebooks --output-dir dist + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./dist + + deploy: + needs: build + #if: github.ref == 'refs/heads/main' + permissions: + pages: write + id-token: write + + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + runs-on: ubuntu-latest + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 1f565fd..c26e4c6 100644 --- a/.gitignore +++ b/.gitignore @@ -134,3 +134,7 @@ dmypy.json # Pyre type checker .pyre/ + +# JupyterLite deployment +.jupyterlite.doit.db +_output/ diff --git a/data/__init__.py b/.nojekyll similarity index 100% rename from data/__init__.py rename to .nojekyll diff --git a/README.md b/README.md index 37894bc..6ad075c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,22 @@ +# Work in progress to use pyodide kernel in JupyterLite for tutorial + +Deployed to github pages at https://bokeh.github.io/tutorial + +To try out locally, create a python virtual environment of your choice (`venv`, `pyenv`, +'mamba', `conda`, etc) and follow these steps: + +```bash +python -m pip install -r requirements.txt +jupyter lite build --contents notebooks +jupyter lite serve +``` + +and open a web browser at the URL specified. + +------------------------ + + + # Bokeh tutorial notebooks ## Setup and run the tutorials diff --git a/environment.yml b/environment.yml deleted file mode 100644 index 7c123f5..0000000 --- a/environment.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: bk-tutorial -channels: - - conda-forge -dependencies: - - python>=3.12 - - pip - - geojson - - geopandas - - jupyter_client<8 - - notebook - - pandas - - pyshp - - ipykernel - - pip: - - bokeh==3.5 - - bokeh_sampledata diff --git a/notebooks/01_introduction.ipynb b/notebooks/01_introduction.ipynb index 646473b..d13d6ef 100644 --- a/notebooks/01_introduction.ipynb +++ b/notebooks/01_introduction.ipynb @@ -127,7 +127,9 @@ "metadata": {}, "outputs": [], "source": [ - "# load and display tutorial dashboard\n", + "# Install geopandas into pyodide environment running in browser\n", + "%pip install -q geopandas\n", + "\n", "from tutorial_dashboard import dashboard_layout\n", "\n", "show(dashboard_layout)" @@ -245,7 +247,7 @@ "Python script.\n", "This tutorial will reference the data preparation script but will not go into detail\n", "about the data preparation itself.\n", - "You can find the data processing code in [`carriers_data.py`](../data/carriers_data.py).\n", + "You can find the data processing code in [`carriers_data.py`](./data/carriers_data.py).\n", "\n", "This tutorial is designed to run on [mybinder.org](https://mybinder.readthedocs.io/en/latest/).\n", "You can also run this tutorial locally on your computer.\n", @@ -286,7 +288,7 @@ "source": [ "# Next section\n", "\n", - "\n", + "\n", " \"Next\n", "\n", "\n", diff --git a/notebooks/02_installation_and_setup.ipynb b/notebooks/02_installation_and_setup.ipynb index 4c78c47..a1e2ee9 100644 --- a/notebooks/02_installation_and_setup.ipynb +++ b/notebooks/02_installation_and_setup.ipynb @@ -117,7 +117,7 @@ "source": [ "# Next section\n", "\n", - "\n", + "\n", " \"Next\n", "\n", "\n", diff --git a/notebooks/03_basic_concepts.ipynb b/notebooks/03_basic_concepts.ipynb index 6c8cb7d..865b451 100644 --- a/notebooks/03_basic_concepts.ipynb +++ b/notebooks/03_basic_concepts.ipynb @@ -256,7 +256,7 @@ "source": [ "# Next section\n", "\n", - "\n", + "\n", " \"Next\n", "\n", "\n", diff --git a/notebooks/04_basic_plots.ipynb b/notebooks/04_basic_plots.ipynb index db22639..16ae546 100644 --- a/notebooks/04_basic_plots.ipynb +++ b/notebooks/04_basic_plots.ipynb @@ -30,6 +30,7 @@ "outputs": [], "source": [ "# load tutorial data\n", + "%pip install -q pandas\n", "from tutorial_data import data" ] }, @@ -525,7 +526,7 @@ "This is an example of how you can customize the appearance of the different\n", "elements of your plot.\n", "\n", - "\n", + "\n", " \"Next\n", "\n", "\n", diff --git a/notebooks/05_styling.ipynb b/notebooks/05_styling.ipynb index 20905cc..d261cc5 100644 --- a/notebooks/05_styling.ipynb +++ b/notebooks/05_styling.ipynb @@ -30,6 +30,7 @@ "outputs": [], "source": [ "# load tutorial data\n", + "%pip install -q pandas\n", "from tutorial_data import data" ] }, @@ -749,7 +750,7 @@ "source": [ "# Next section\n", "\n", - "\n", + "\n", " \"Next\n", "\n", "\n", diff --git a/notebooks/06_data_sources.ipynb b/notebooks/06_data_sources.ipynb index 9b6de1f..55a2f58 100644 --- a/notebooks/06_data_sources.ipynb +++ b/notebooks/06_data_sources.ipynb @@ -30,6 +30,7 @@ "outputs": [], "source": [ "# load tutorial data\n", + "%pip install -q pandas\n", "from tutorial_data import data" ] }, @@ -456,7 +457,7 @@ "source": [ "# Next section\n", "\n", - "\n", + "\n", " \"Next\n", "\n", "\n", diff --git a/notebooks/07_annotations.ipynb b/notebooks/07_annotations.ipynb index df90c38..f0ac1ab 100644 --- a/notebooks/07_annotations.ipynb +++ b/notebooks/07_annotations.ipynb @@ -30,6 +30,7 @@ "outputs": [], "source": [ "# load tutorial data\n", + "%pip install -q pandas\n", "from tutorial_data import data" ] }, @@ -613,7 +614,7 @@ "source": [ "# Next section\n", "\n", - "\n", + "\n", " \"Next\n", "\n", "\n", diff --git a/notebooks/08_plot_tools.ipynb b/notebooks/08_plot_tools.ipynb index dd001d4..bd9b806 100644 --- a/notebooks/08_plot_tools.ipynb +++ b/notebooks/08_plot_tools.ipynb @@ -30,6 +30,7 @@ "outputs": [], "source": [ "# load tutorial data\n", + "%pip install -q pandas\n", "from tutorial_data import data" ] }, @@ -543,7 +544,7 @@ "source": [ "# Next section\n", "\n", - "\n", + "\n", " \"Next\n", "\n", "\n", diff --git a/notebooks/09_more_plot_types.ipynb b/notebooks/09_more_plot_types.ipynb index 0d6e293..97a65b1 100644 --- a/notebooks/09_more_plot_types.ipynb +++ b/notebooks/09_more_plot_types.ipynb @@ -30,6 +30,7 @@ "outputs": [], "source": [ "# load tutorial data\n", + "%pip install -q pandas\n", "from tutorial_data import data" ] }, @@ -173,6 +174,8 @@ "metadata": {}, "outputs": [], "source": [ + "%pip install -q geojson geopandas shapely\n", + "\n", "from shapely.geometry import Point\n", "from pyproj import CRS, Transformer\n", "import geojson\n", @@ -309,8 +312,8 @@ "metadata": {}, "outputs": [], "source": [ - "states_gdf = gpd.read_file(\"../data/us-states.geojson\")\n", - "states_gdf.plot() # use geopandas to plot the state shapes" + "states_gdf = gpd.read_file(\"./data/us-states.geojson\")\n", + "states_gdf.head()" ] }, { @@ -376,7 +379,7 @@ "from bokeh.transform import linear_cmap\n", "\n", "# read the GeoJSON file containing the state shapes\n", - "states_gdf = gpd.read_file(\"../data/us-states.geojson\")\n", + "states_gdf = gpd.read_file(\"./data/us-states.geojson\")\n", "# read the pre-processed data frame from the demo data set and join it to the state shapes\n", "states_gdf = states_gdf.join(data.get_states_routes_df(), on=states_gdf[\"Name\"])\n", "# create the GeoJSONDataSource\n", @@ -852,7 +855,7 @@ "source": [ "# Next section\n", "\n", - "\n", + "\n", " \"Next\n", "\n", "\n", diff --git a/notebooks/10_layouts.ipynb b/notebooks/10_layouts.ipynb index 3c2e0bd..8e6d6b9 100644 --- a/notebooks/10_layouts.ipynb +++ b/notebooks/10_layouts.ipynb @@ -30,6 +30,7 @@ "outputs": [], "source": [ "# load tutorial data\n", + "%pip install -q pandas\n", "from tutorial_data import data" ] }, @@ -405,7 +406,7 @@ "source": [ "# Next section\n", "\n", - "\n", + "\n", " \"Next\n", "\n", "\n", diff --git a/notebooks/11_widgets_interactivity.ipynb b/notebooks/11_widgets_interactivity.ipynb index 81f4db7..59a986b 100644 --- a/notebooks/11_widgets_interactivity.ipynb +++ b/notebooks/11_widgets_interactivity.ipynb @@ -30,6 +30,7 @@ "outputs": [], "source": [ "# load tutorial data\n", + "%pip install -q pandas\n", "from tutorial_data import data" ] }, @@ -287,6 +288,8 @@ "metadata": {}, "outputs": [], "source": [ + "%pip install -q bokeh-sampledata\n", + "\n", "import pandas as pd\n", "\n", "from bokeh.palettes import Spectral4\n", @@ -1206,7 +1209,7 @@ "source": [ "# Next section\n", "\n", - "\n", + "\n", " \"Next\n", "\n", "\n", diff --git a/notebooks/12_demo_dashboard.ipynb b/notebooks/12_demo_dashboard.ipynb index cb6f79e..549d376 100644 --- a/notebooks/12_demo_dashboard.ipynb +++ b/notebooks/12_demo_dashboard.ipynb @@ -30,6 +30,7 @@ "outputs": [], "source": [ "# load tutorial data\n", + "%pip install -q pandas\n", "from tutorial_data import data" ] }, @@ -1218,10 +1219,11 @@ "metadata": {}, "outputs": [], "source": [ + "%pip install -q geopandas\n", "import geopandas as gpd\n", "\n", - "states_gdf = gpd.read_file(\"../data/us-states.geojson\")\n", - "states_gdf.plot() # use geopandas to plot the state shapes" + "states_gdf = gpd.read_file(\"./data/us-states.geojson\")\n", + "states_gdf.head(2)" ] }, { @@ -1316,7 +1318,7 @@ "outputs": [], "source": [ "# read the geojson file containing the state shapes\n", - "states_gdf = gpd.read_file(\"../data/us-states.geojson\")\n", + "states_gdf = gpd.read_file(\"./data/us-states.geojson\")\n", "# read the pre-processed data frame from the demo data set and join it to the state shapes\n", "states_gdf = states_gdf.join(data.get_states_routes_df(), on=states_gdf[\"Name\"])\n", "# create the GeoJSONDataSource\n", @@ -1483,7 +1485,7 @@ "from bokeh.transform import linear_cmap\n", "\n", "# read the geojson file containing the state shapes\n", - "states_gdf = gpd.read_file(\"../data/us-states.geojson\")\n", + "states_gdf = gpd.read_file(\"./data/us-states.geojson\")\n", "# read the pre-processed data frame from the demo data set and join it to the state shapes\n", "states_gdf = states_gdf.join(data.get_states_routes_df(), on=states_gdf[\"Name\"])\n", "# create the GeoJSONDataSource\n", @@ -1578,7 +1580,7 @@ "For details about how to compute the angles, see the detailed example in the\n", "[Wedge plots section](09_more_plot_types.ipynb#Wedge-plots).\n", "For the specific code generating these DataFrames, see the function\n", - "``get_top_carriers_by_metrics`` in [carriers_data.py](../data/carriers_data.py)." + "``get_top_carriers_by_metrics`` in [carriers_data.py](./data/carriers_data.py)." ] }, { @@ -1898,7 +1900,7 @@ "source": [ "# Next section\n", "\n", - "\n", + "\n", " \"Next\n", "\n", "\n", diff --git a/notebooks/13_exporting_embedding.ipynb b/notebooks/13_exporting_embedding.ipynb index 3d3ceb0..10cd14b 100644 --- a/notebooks/13_exporting_embedding.ipynb +++ b/notebooks/13_exporting_embedding.ipynb @@ -91,15 +91,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "

\n", - " ✨ The HTML output file of the complete dashboard is hosted at: bokeh.github.io/tutorial ↗️\n", - "

" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ + "The HTML file is saved with the name `custom_filename.html` and appears in the file browser on the left.\n", + "Double-click it to open it; you may have to confirm that you trust the file contents depending on your browser and privacy settings.\n", + "\n", "Calling `output_file` **switches Bokeh to file output mode persistently**.\n", "This means that all subsequent calls to `show` will generate output to the specified file.\n", "\n", @@ -334,7 +328,7 @@ "source": [ "# Next section\n", "\n", - "\n", + "\n", " \"Next\n", "\n", "\n", diff --git a/data/T_T100D_MARKET_US_CARRIER_ONLY_20220506_205137.zip b/notebooks/data/T_T100D_MARKET_US_CARRIER_ONLY_20220506_205137.zip similarity index 100% rename from data/T_T100D_MARKET_US_CARRIER_ONLY_20220506_205137.zip rename to notebooks/data/T_T100D_MARKET_US_CARRIER_ONLY_20220506_205137.zip diff --git a/notebooks/data/__init__.py b/notebooks/data/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/data/carriers_data.py b/notebooks/data/carriers_data.py similarity index 100% rename from data/carriers_data.py rename to notebooks/data/carriers_data.py diff --git a/data/us-states.geojson b/notebooks/data/us-states.geojson similarity index 100% rename from data/us-states.geojson rename to notebooks/data/us-states.geojson diff --git a/notebooks/tutorial_dashboard.py b/notebooks/tutorial_dashboard.py index 2094daa..a9ad995 100644 --- a/notebooks/tutorial_dashboard.py +++ b/notebooks/tutorial_dashboard.py @@ -20,7 +20,7 @@ from bokeh.transform import cumsum, linear_cmap # Load data set object -sys.path.append("../data") +sys.path.append("./data") from carriers_data import CarrierDataSet data = CarrierDataSet() @@ -208,7 +208,7 @@ def distance_plot(): def departures_map(): # read the geojson file containing the state shapes - states_gdf = gpd.read_file("../data/us-states.geojson") + states_gdf = gpd.read_file("./data/us-states.geojson") # read the pre-processed data frame from the demo data set and join it to the state shapes states_gdf = states_gdf.join(data.get_states_routes_df(), on=states_gdf["Name"]) # create the GeoJSONDataSource diff --git a/notebooks/tutorial_data.py b/notebooks/tutorial_data.py index 7489cb4..d185d12 100644 --- a/notebooks/tutorial_data.py +++ b/notebooks/tutorial_data.py @@ -1,9 +1,9 @@ -""" Shortcut for loading data from the ../data folder """ +""" Shortcut for loading data from the ./data folder """ import sys # Load data set object -sys.path.append("../data") +sys.path.append("./data") from carriers_data import CarrierDataSet data = CarrierDataSet() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..92135b3 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +jupyterlite-core +jupyterlite-pyodide-kernel +jupyter-server