├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml └── workflows │ ├── deploy-docs.yml │ ├── pypi.yml │ ├── save_versions.yml │ ├── test_code.yml │ ├── test_geopandas.yml │ ├── test_latest_branca.yml │ ├── test_mypy.yml │ ├── test_selenium.yml │ ├── test_snapshots.yml │ └── test_streamlit_folium.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .streamlit └── config.toml ├── CHANGES.txt ├── CODE_OF_CONDUCT.md ├── LICENSE.txt ├── MANIFEST.in ├── README.rst ├── SECURITY.md ├── docs ├── Makefile ├── _static │ ├── custom.css │ ├── flask_example.py │ ├── folium_logo.png │ └── switcher.json ├── _templates │ └── version.html ├── advanced_guide.rst ├── advanced_guide │ ├── choropleth with Jenks natural breaks optimization.md │ ├── colormaps.md │ ├── custom_panes.md │ ├── custom_tiles.md │ ├── customize_javascript_and_css.md │ ├── flask.rst │ ├── geodedetic_image_overlay.md │ ├── piechart_icons.md │ ├── polygons_from_list_of_points.md │ ├── subplots.md │ └── world_copy.md ├── conf.py ├── getting_started.md ├── index.rst ├── reference.rst ├── update_switcher.py ├── user_guide.rst └── user_guide │ ├── features.rst │ ├── features │ ├── click_related_classes.md │ └── fit_overlays.md │ ├── geojson.rst │ ├── geojson │ ├── choropleth.md │ ├── geojson.md │ ├── geojson_marker.md │ ├── geojson_popup_and_tooltip.md │ ├── geopandas_and_geo_interface.md │ └── smoothing.md │ ├── map.md │ ├── plugins.rst │ ├── plugins │ ├── WmsTimeDimension.md │ ├── antpath.md │ ├── beautify_icon.md │ ├── boat_marker.md │ ├── draw.md │ ├── dual_map.md │ ├── featuregroup_subgroup.md │ ├── float_image.md │ ├── fullscreen.md │ ├── geocoder.md │ ├── grouped_layer_control.md │ ├── heatmap.md │ ├── heatmap_with_time.md │ ├── locate_control.md │ ├── marker_cluster.md │ ├── measure_control.md │ ├── mini_map.md │ ├── mouse_position.md │ ├── overlapping_marker_spiderfier.md │ ├── pattern.md │ ├── polygon_encoded.md │ ├── polyline_encoded.md │ ├── polyline_offset.md │ ├── polyline_textpath.md │ ├── realtime.md │ ├── scroll_zoom_toggler.md │ ├── search.md │ ├── semi_circle.md │ ├── side_by_side_layers.md │ ├── tag_filter_button.md │ ├── terminator.md │ ├── timeline.md │ ├── timeslider_choropleth.md │ ├── timestamped_geojson.md │ ├── treelayercontrol.md │ └── vector_tiles.md │ ├── raster_layers.rst │ ├── raster_layers │ ├── image_overlay.md │ ├── tiles.md │ ├── video_overlay.md │ └── wms_tile_layer.md │ ├── ui_elements.rst │ ├── ui_elements │ ├── icons.md │ ├── layer_control.md │ └── popups.md │ ├── vector_layers.rst │ └── vector_layers │ ├── circle_and_circle_marker.md │ ├── colorline.md │ ├── polygon.md │ ├── polyline.md │ └── rectangle.md ├── environment.yml ├── examples ├── CheckZorder.ipynb ├── Choropleth with Jenks natural breaks optimization.ipynb ├── ClickEvents.ipynb ├── Colormaps.ipynb ├── ContinuousWorld.ipynb ├── ControlScale.ipynb ├── CustomIcon.ipynb ├── CustomPanes.ipynb ├── FeatureGroup.ipynb ├── Features.ipynb ├── FitOverlays.ipynb ├── FloatImage.ipynb ├── GeoJSONMarker.ipynb ├── GeoJSONWithoutTitles.ipynb ├── GeoJSON_and_choropleth.ipynb ├── GeoJsonPopupAndTooltip.ipynb ├── GeodedeticImageOverlay.ipynb ├── Geopandas_and_geo_interface.ipynb ├── HeatMapWithTime.ipynb ├── Heatmap.ipynb ├── Highlight_Function.ipynb ├── ImageOverlay.ipynb ├── MarkerCluster.ipynb ├── MinMaxLimits.ipynb ├── MiniMap.ipynb ├── Minicharts.ipynb ├── Plugins.ipynb ├── PolyLineTextPath_AntPath.ipynb ├── Polygons_from_list_of_points.ipynb ├── Popups.ipynb ├── Quickstart.ipynb ├── Rotate_icon.ipynb ├── SmoothFactor.ipynb ├── TagFilterButton.ipynb ├── TilesExample.ipynb ├── TimeSliderChoropleth.ipynb ├── VectorLayers.ipynb ├── VideoOverlayLayer.ipynb ├── WMS_and_WMTS.ipynb ├── WidthHeight.ipynb ├── WmsTimeDimension.ipynb ├── data │ ├── 2014_08_05_farol.gpx │ ├── Mercator_projection_SW.jpg │ ├── Mercator_projection_SW.png │ ├── NOAA_46041.csv │ ├── NOAA_46050_WS.csv │ ├── NOAA_46243.csv │ ├── US_Unemployment_Oct2012.csv │ ├── antarctic_ice_edge.json │ ├── antarctic_ice_shelf_topo.json │ ├── consonants_vowels.csv │ ├── data.json │ ├── data1.json │ ├── data2.json │ ├── data3.json │ ├── highlight_flight_trajectories.csv │ ├── historical_country_borders.json │ ├── mercator_temperature.mat │ ├── nybb.zip │ ├── or_counties_topo.json │ ├── search_bars_rome.json │ ├── search_states.json │ ├── subwaystations.geojson │ ├── us-states.json │ ├── us_counties_20m_topo.json │ ├── us_county_data.csv │ ├── vis1.json │ ├── vis2.json │ ├── vis3.json │ └── world-countries.json ├── flask_example.py ├── plugin-Draw.ipynb ├── plugin-DualMap.ipynb ├── plugin-GroupedLayerControl.ipynb ├── plugin-MeasureControl.ipynb ├── plugin-MousePosition.ipynb ├── plugin-PolyLineOffset.ipynb ├── plugin-Search.ipynb ├── plugin-patterns.ipynb └── plugin-vector-tiles.ipynb ├── folium ├── __init__.py ├── elements.py ├── features.py ├── folium.py ├── map.py ├── plugins │ ├── __init__.py │ ├── antpath.py │ ├── beautify_icon.py │ ├── boat_marker.py │ ├── draw.py │ ├── dual_map.py │ ├── encoded.py │ ├── fast_marker_cluster.py │ ├── feature_group_sub_group.py │ ├── float_image.py │ ├── fullscreen.py │ ├── geocoder.py │ ├── geoman.py │ ├── groupedlayercontrol.py │ ├── heat_map.py │ ├── heat_map_withtime.py │ ├── locate_control.py │ ├── marker_cluster.py │ ├── measure_control.py │ ├── minimap.py │ ├── mouse_position.py │ ├── overlapping_marker_spiderfier.py │ ├── pattern.py │ ├── polyline_offset.py │ ├── polyline_text_path.py │ ├── realtime.py │ ├── scroll_zoom_toggler.py │ ├── search.py │ ├── semicircle.py │ ├── side_by_side.py │ ├── tag_filter_button.py │ ├── terminator.py │ ├── time_slider_choropleth.py │ ├── timeline.py │ ├── timestamped_geo_json.py │ ├── timestamped_wmstilelayer.py │ ├── treelayercontrol.py │ └── vectorgrid_protobuf.py ├── py.typed ├── raster_layers.py ├── template.py ├── templates │ ├── leaflet.awesome.rotate.css │ ├── leaflet_heat.min.js │ ├── pa7_hm.min.js │ └── pa7_leaflet_hm.min.js ├── utilities.py └── vector_layers.py ├── pyproject.toml ├── requirements-dev.txt ├── requirements.txt ├── setup.cfg ├── setup.py └── tests ├── geo_grid.json ├── kuntarajat.geojson ├── or_counties_topo.json ├── plugins ├── test_antpath.py ├── test_beautify_icon.py ├── test_boat_marker.py ├── test_dual_map.py ├── test_encoded.py ├── test_fast_marker_cluster.py ├── test_feature_group_sub_group.py ├── test_float_image.py ├── test_fullscreen.py ├── test_geoman.py ├── test_grouped_layer_control.py ├── test_heat_map.py ├── test_heat_map_withtime.py ├── test_marker_cluster.py ├── test_minimap.py ├── test_overlapping_marker_spiderfier.py ├── test_pattern.py ├── test_polyline_offset.py ├── test_polyline_text_path.py ├── test_realtime.py ├── test_scroll_zoom_toggler.py ├── test_semicircle.py ├── test_tag_filter_button.py ├── test_terminator.py ├── test_time_slider_choropleth.py ├── test_timeline.py ├── test_timestamped_geo_json.py └── test_vectorgrid_protobuf.py ├── selenium ├── conftest.py ├── test_geojson_selenium.py ├── test_heat_map_selenium.py ├── test_heat_map_selenium_screenshot.png └── test_selenium.py ├── snapshots ├── modules │ ├── issue_1885.py │ ├── issue_1885_add_child.py │ ├── issue_1885_add_to.py │ ├── issue_1885_set_icon.py │ ├── issue_1989.py │ └── issue_2109.py ├── screenshots │ ├── screenshot_issue_1885.png │ ├── screenshot_issue_1885_add_child.png │ ├── screenshot_issue_1885_add_to.png │ ├── screenshot_issue_1885_set_icon.png │ ├── screenshot_issue_1989.png │ └── screenshot_issue_2109.png └── test_snapshots.py ├── subwaystations.geojson ├── test_features.py ├── test_folium.py ├── test_jinja.py ├── test_map.py ├── test_raster_layers.py ├── test_repr.py ├── test_template.py ├── test_utilities.py ├── test_vector_layers.py ├── us-counties.json ├── us-states.json ├── us_county_data.csv └── vegalite_data ├── vegalite_v1.json └── vegalite_vlater.json /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | #### Please add a code sample or a nbviewer link, copy-pastable if possible 2 | 3 | ```python 4 | # Your code here 5 | 6 | ``` 7 | #### Problem description 8 | 9 | [this should explain **why** the current behavior is a problem and what is the expected output.] 10 | 11 | #### Expected Output 12 | 13 | #### Output of ``folium.__version__`` 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | 15 | ``` 16 | [ Include a code snippet that produces your bug. Make it standalone, we should be able to run it. ] 17 | 18 | [ Include a data sample or link to your data if necessary to run the code ] 19 | 20 | ``` 21 | 22 | **Expected behavior** 23 | A clear and concise description of what you expected to happen. 24 | 25 | **Environment (please complete the following information):** 26 | - Browser [e.g. chrome, firefox] 27 | - Jupyter Notebook or html files? 28 | - Python version (check it with `import sys; print(sys.version_info)`) 29 | - folium version (check it with `import folium; print(folium.__version__)`) 30 | - branca version (check it with `import branca; print(branca.__version__)`) 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | 35 | **Possible solutions** 36 | List any solutions you may have come up with. 37 | 38 | folium is maintained by volunteers. Can you help making a fix for this issue? 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | 22 | **Implementation** 23 | folium is maintained by volunteers. Can you help make a PR if we want to implement this feature? 24 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # See https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/keeping-your-actions-up-to-date-with-dependabot 2 | 3 | version: 2 4 | updates: 5 | 6 | - package-ecosystem: "github-actions" 7 | directory: "/" 8 | schedule: 9 | interval: "daily" 10 | labels: 11 | - "Bot" 12 | groups: 13 | github-actions: 14 | patterns: 15 | - '*' 16 | -------------------------------------------------------------------------------- /.github/workflows/pypi.yml: -------------------------------------------------------------------------------- 1 | name: Publish to PyPI 2 | 3 | on: 4 | schedule: 5 | - cron: "0 13 * * *" 6 | pull_request: 7 | push: 8 | branches: 9 | - main 10 | release: 11 | types: 12 | - published 13 | 14 | defaults: 15 | run: 16 | shell: bash 17 | 18 | jobs: 19 | packages: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | 24 | - name: Set up Python 25 | uses: actions/setup-python@v5 26 | with: 27 | python-version: "3.x" 28 | 29 | - name: Get tags 30 | run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* 31 | 32 | 33 | - name: Install build tools 34 | run: | 35 | python -m pip install --upgrade pip wheel build twine 36 | 37 | - name: Build binary wheel and sdist 38 | run: python -m build --sdist --wheel . --outdir dist 39 | 40 | - name: CheckFiles 41 | run: | 42 | ls dist 43 | 44 | - name: Test wheels 45 | run: | 46 | cd dist && python -m pip install folium*.whl 47 | python -m twine check * 48 | 49 | - name: Publish a Python distribution to PyPI 50 | if: success() && github.event_name == 'release' 51 | uses: pypa/gh-action-pypi-publish@v1.12.4 52 | with: 53 | user: __token__ 54 | password: ${{ secrets.PYPI_PASSWORD }} 55 | -------------------------------------------------------------------------------- /.github/workflows/save_versions.yml: -------------------------------------------------------------------------------- 1 | name: Save package versions 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | run: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Checkout Folium 15 | uses: actions/checkout@v4 16 | 17 | - name: Setup Micromamba env 18 | uses: mamba-org/setup-micromamba@v2 19 | with: 20 | environment-name: TEST 21 | create-args: >- 22 | python=3 23 | --file requirements.txt 24 | --file requirements-dev.txt 25 | 26 | - name: Install folium from source 27 | shell: bash -l {0} 28 | run: | 29 | python -m pip install -e . --no-deps --force-reinstall 30 | 31 | - name: Create versions.txt 32 | shell: bash -l {0} 33 | run: | 34 | conda list > /tmp/versions.txt 35 | chromium --version >> /tmp/versions.txt 36 | 37 | - name: Save versions.txt 38 | if: always() 39 | uses: actions/upload-artifact@v4 40 | with: 41 | name: versions.txt 42 | path: /tmp/versions.txt 43 | fail-on-empty: false 44 | -------------------------------------------------------------------------------- /.github/workflows/test_code.yml: -------------------------------------------------------------------------------- 1 | name: Code Tests 2 | 3 | on: 4 | schedule: 5 | - cron: "0 13 * * *" 6 | pull_request: 7 | push: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | run: 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | os: [ubuntu-latest, windows-latest] 17 | python-version: ["3.9", "3.13"] 18 | fail-fast: false 19 | defaults: 20 | run: 21 | shell: bash -l {0} 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | 26 | - name: Setup Micromamba env 27 | uses: mamba-org/setup-micromamba@v2 28 | with: 29 | environment-name: TEST 30 | create-args: >- 31 | python=${{ matrix.python-version }} 32 | --file requirements.txt 33 | --file requirements-dev.txt 34 | 35 | - name: Install folium from source 36 | run: python -m pip install -e . --no-deps --force-reinstall 37 | 38 | - name: Install pixelmatch 39 | shell: bash -l {0} 40 | run: | 41 | pip install pixelmatch 42 | 43 | - name: Code tests 44 | run: python -m pytest -vv --ignore=tests/selenium --ignore=tests/playwright --ignore=tests/snapshots 45 | -------------------------------------------------------------------------------- /.github/workflows/test_geopandas.yml: -------------------------------------------------------------------------------- 1 | name: Geopandas tests 2 | 3 | on: 4 | schedule: 5 | - cron: "0 13 * * *" 6 | pull_request: 7 | push: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | run: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout Folium 17 | uses: actions/checkout@v4 18 | with: 19 | # needed to get the correct version number for Folium 20 | fetch-depth: 0 21 | path: folium 22 | 23 | - name: Setup Micromamba env 24 | uses: mamba-org/setup-micromamba@v2 25 | with: 26 | environment-name: TEST 27 | create-args: >- 28 | python=3 29 | --file folium/requirements.txt 30 | 31 | - name: Checkout Geopandas 32 | uses: actions/checkout@v4 33 | with: 34 | repository: geopandas/geopandas 35 | path: geopandas 36 | 37 | - name: Install Geopandas dev dependencies 38 | run: | 39 | pip install -r geopandas/requirements-dev.txt 40 | 41 | - name: Install folium from source 42 | run: | 43 | cd folium 44 | python -m pip install -e . --no-deps --force-reinstall 45 | 46 | - name: Run Geopandas tests 47 | run: | 48 | cd geopandas 49 | pytest -r a geopandas/tests/test_explore.py 50 | -------------------------------------------------------------------------------- /.github/workflows/test_latest_branca.yml: -------------------------------------------------------------------------------- 1 | name: Code Tests with Latest branca 2 | 3 | on: 4 | schedule: 5 | - cron: "0 13 * * *" 6 | pull_request: 7 | push: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | run: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Setup Micromamba env 19 | uses: mamba-org/setup-micromamba@v2 20 | with: 21 | environment-name: TEST 22 | create-args: >- 23 | python=3 24 | --file requirements.txt 25 | --file requirements-dev.txt 26 | 27 | - name: Install folium from source 28 | shell: bash -l {0} 29 | run: python -m pip install -e . --no-deps --force-reinstall 30 | 31 | - name: Tests with latest branca 32 | shell: bash -l {0} 33 | run: | 34 | micromamba remove branca --yes --force 35 | python -m pip install git+https://github.com/python-visualization/branca.git 36 | python -m pytest -vv --ignore=tests/selenium --ignore=tests/playwright --ignore=tests/snapshots 37 | -------------------------------------------------------------------------------- /.github/workflows/test_mypy.yml: -------------------------------------------------------------------------------- 1 | name: Mypy type hint checks 2 | 3 | on: 4 | schedule: 5 | - cron: "0 13 * * *" 6 | pull_request: 7 | push: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | run: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Setup Micromamba env 19 | uses: mamba-org/setup-micromamba@v2 20 | with: 21 | environment-name: TEST 22 | create-args: >- 23 | python=3 24 | --file requirements.txt 25 | --file requirements-dev.txt 26 | 27 | - name: Install folium from source 28 | shell: bash -l {0} 29 | run: | 30 | python -m pip install -e . --no-deps --force-reinstall 31 | 32 | - name: Mypy test 33 | shell: bash -l {0} 34 | run: | 35 | mypy folium 36 | -------------------------------------------------------------------------------- /.github/workflows/test_selenium.yml: -------------------------------------------------------------------------------- 1 | name: Selenium Tests 2 | 3 | on: 4 | schedule: 5 | - cron: "0 13 * * *" 6 | pull_request: 7 | push: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | run: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | python-version: [ "3.9", "3.13" ] 17 | fail-fast: false 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | 22 | - name: Setup Micromamba env 23 | uses: mamba-org/setup-micromamba@v2 24 | with: 25 | environment-name: TEST 26 | create-args: >- 27 | python=3 28 | --file requirements.txt 29 | --file requirements-dev.txt 30 | 31 | - name: Install folium from source 32 | shell: bash -l {0} 33 | run: python -m pip install -e . --no-deps --force-reinstall 34 | 35 | - name: Selenium tests 36 | shell: bash -l {0} 37 | run: python -m pytest tests/selenium -vv 38 | -------------------------------------------------------------------------------- /.github/workflows/test_snapshots.yml: -------------------------------------------------------------------------------- 1 | name: Run Snapshot Tests 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | run: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Checkout Folium 15 | uses: actions/checkout@v4 16 | 17 | - name: Setup Micromamba env 18 | uses: mamba-org/setup-micromamba@v2 19 | with: 20 | environment-name: TEST 21 | create-args: >- 22 | python=3 23 | --file requirements.txt 24 | --file requirements-dev.txt 25 | 26 | - name: Install pytest plugins and pixelmatch 27 | shell: bash -l {0} 28 | run: | 29 | pip install pixelmatch pytest-github-actions-annotate-failures pytest-rerunfailures 30 | 31 | - name: Install folium from source 32 | shell: bash -l {0} 33 | run: | 34 | python -m pip install -e . --no-deps --force-reinstall 35 | 36 | - name: Test with pytest 37 | shell: bash -l {0} 38 | run: | 39 | python -m pytest tests/snapshots -s --junit-xml=test-results.xml 40 | 41 | - name: Surface failing tests 42 | if: always() 43 | uses: pmeier/pytest-results-action@main 44 | with: 45 | path: test-results.xml 46 | fail-on-empty: false 47 | 48 | - name: Upload screenshots 49 | if: failure() 50 | uses: actions/upload-artifact@v4 51 | with: 52 | name: screenshots 53 | path: | 54 | /tmp/screenshot_*_*.png 55 | /tmp/folium_map_*.html 56 | -------------------------------------------------------------------------------- /.github/workflows/test_streamlit_folium.yml: -------------------------------------------------------------------------------- 1 | name: Run Streamlit Folium Tests 2 | 3 | on: 4 | schedule: 5 | - cron: "0 13 * * *" 6 | pull_request: 7 | push: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | run: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout Folium 17 | uses: actions/checkout@v4 18 | 19 | - name: Setup Micromamba env 20 | uses: mamba-org/setup-micromamba@v2 21 | with: 22 | environment-name: TEST 23 | create-args: >- 24 | python=3 25 | --file requirements.txt 26 | 27 | - name: Checkout Streamlit Folium 28 | uses: actions/checkout@v4 29 | with: 30 | repository: randyzwitch/streamlit-folium 31 | ref: master 32 | path: streamlit_folium # Checkout into a subdirectory 33 | 34 | - name: Build streamlit_folium javascript 35 | shell: bash -l {0} 36 | run: | 37 | cd streamlit_folium/streamlit_folium/frontend/ 38 | npm install 39 | npm run build 40 | 41 | - name: Install streamlit_folium dev dependencies 42 | shell: bash -l {0} 43 | run: | 44 | conda install --file streamlit_folium/tests/requirements.txt 45 | 46 | - name: Install streamlit-folium 47 | shell: bash -l {0} 48 | run: | 49 | cd streamlit_folium 50 | pip install -e . 51 | 52 | - name: Install playwright dependencies 53 | shell: bash -l {0} 54 | run: | 55 | playwright install --with-deps 56 | 57 | - name: Install annotate-failures-plugin 58 | run: pip install pytest-github-actions-annotate-failures 59 | 60 | - name: Install folium from source 61 | shell: bash -l {0} 62 | run: | 63 | python -m pip install -e . --no-deps --force-reinstall 64 | 65 | - name: Test with pytest and retry flaky tests up to 3 times 66 | shell: bash -l {0} 67 | run: | 68 | cd streamlit_folium 69 | pytest tests/test_frontend.py --browser chromium -s --reruns 3 -k "not test_layer_control_dynamic_update" --junit-xml=test-results.xml 70 | 71 | - name: Surface failing tests 72 | if: always() 73 | uses: pmeier/pytest-results-action@main 74 | with: 75 | path: streamlit_folium/test-results.xml 76 | fail-on-empty: false 77 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.egg-info/ 2 | *.pyc 3 | .ipynb_checkpoints 4 | .pytest_cache 5 | build/ 6 | dist/ 7 | docs/index.html 8 | docs/_build/ 9 | docs/quickstart.ipynb 10 | docs/**/*.ipynb 11 | examples/results/* 12 | .cache/ 13 | .idea/ 14 | /*.xml 15 | /codestyles/*.xml 16 | /_mac/*.xml 17 | /inspection/*.xml 18 | geckodriver.log 19 | geckodriver.exe 20 | geckodriver.tar.gz 21 | geckodriver/ 22 | chromedriver.exe 23 | chromedriver/ 24 | miniconda.sh 25 | latest_logs/ 26 | *.nbconvert.ipynb 27 | folium/_version.py 28 | .vscode/ 29 | venv/ 30 | .venv 31 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | exclude: examples/data/|.*\.css|.*\.json|.*\.geojson|.*\.html 2 | 3 | repos: 4 | - repo: https://github.com/pre-commit/pre-commit-hooks 5 | rev: v5.0.0 6 | hooks: 7 | - id: trailing-whitespace 8 | - id: check-ast 9 | - id: debug-statements 10 | - id: end-of-file-fixer 11 | - id: check-docstring-first 12 | exclude: ^examples/streamlit 13 | - id: check-added-large-files 14 | args: ['--maxkb=1024'] 15 | - id: requirements-txt-fixer 16 | - id: file-contents-sorter 17 | files: requirements-dev.txt 18 | 19 | - repo: https://github.com/astral-sh/ruff-pre-commit 20 | rev: v0.11.8 21 | hooks: 22 | - id: ruff 23 | 24 | - repo: https://github.com/psf/black 25 | rev: 25.1.0 26 | hooks: 27 | - id: black 28 | language_version: python3 29 | 30 | - repo: https://github.com/keewis/blackdoc 31 | rev: v0.3.9 32 | hooks: 33 | - id: blackdoc 34 | 35 | - repo: https://github.com/codespell-project/codespell 36 | rev: v2.4.1 37 | hooks: 38 | - id: codespell 39 | args: 40 | - --ignore-words-list=thex,nd,fo,som,nam,tha,caf 41 | exclude: > 42 | (?x)^( 43 | .*\.csv | 44 | .*\.json | 45 | )$ 46 | 47 | ci: 48 | autofix_commit_msg: | 49 | [pre-commit.ci] auto fixes from pre-commit.com hooks 50 | 51 | for more information, see https://pre-commit.ci 52 | autofix_prs: false 53 | autoupdate_commit_msg: '[pre-commit.ci] pre-commit autoupdate' 54 | autoupdate_schedule: monthly 55 | skip: [] 56 | submodules: false 57 | -------------------------------------------------------------------------------- /.streamlit/config.toml: -------------------------------------------------------------------------------- 1 | [server] 2 | enableStaticServing = true 3 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2013-, Folium developers 2 | See https://github.com/python-visualization/folium/graphs/contributors for a 3 | full list of contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.txt 2 | include README.rst 3 | include pyproject.toml 4 | 5 | recursive-include folium *.py 6 | recursive-include folium *.js 7 | recursive-include folium/plugins * 8 | recursive-include folium/templates * 9 | 10 | prune examples 11 | prune tests 12 | prune docs 13 | prune *.egg-info 14 | 15 | exclude *.yml 16 | exclude .pre-commit-config.yaml 17 | exclude *.enc 18 | exclude .gitignore 19 | exclude .isort.cfg 20 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Folium only supports the most recent version of the package. We strive to maintain backwards compatibility in new versions, so we recommend users to always update to the latest version. Support for older versions is currently not provided. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | - Reporting Process: Please report any security issues by creating an Issue on our GitHub repository. Or better yet, open a PR with a fix. 10 | - Private Reporting: If you believe that publicly sharing an issue could lead to significant harm, you may opt for a private report at https://github.com/python-visualization/folium/security. 11 | - Response Time: We will strive to respond promptly to all reported issues, prioritizing them based on severity. However, please understand that as volunteers, our response times may vary. 12 | - No Guarantees: While we are committed to addressing security concerns to the best of our abilities, we do not provide any guarantees regarding resolution times or outcomes. 13 | -------------------------------------------------------------------------------- /docs/_static/custom.css: -------------------------------------------------------------------------------- 1 | .bd-content { 2 | flex-grow: 1; 3 | max-width: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /docs/_static/flask_example.py: -------------------------------------------------------------------------------- 1 | """flask_example.py 2 | 3 | Required packages: 4 | - flask 5 | - folium 6 | 7 | Usage: 8 | 9 | Start the flask server by running: 10 | 11 | $ python flask_example.py 12 | 13 | And then head to http://127.0.0.1:5000/ in your browser to see the map displayed 14 | 15 | """ 16 | 17 | from flask import Flask, render_template_string 18 | 19 | import folium 20 | 21 | app = Flask(__name__) 22 | 23 | 24 | @app.route("/") 25 | def fullscreen(): 26 | """Simple example of a fullscreen map.""" 27 | m = folium.Map() 28 | return m.get_root().render() 29 | 30 | 31 | @app.route("/iframe") 32 | def iframe(): 33 | """Embed a map as an iframe on a page.""" 34 | m = folium.Map() 35 | 36 | # set the iframe width and height 37 | m.get_root().width = "800px" 38 | m.get_root().height = "600px" 39 | iframe = m.get_root()._repr_html_() 40 | 41 | return render_template_string( 42 | """ 43 | 44 | 45 | 46 | 47 |

Using an iframe

48 | {{ iframe|safe }} 49 | 50 | 51 | """, 52 | iframe=iframe, 53 | ) 54 | 55 | 56 | @app.route("/components") 57 | def components(): 58 | """Extract map components and put those on a page.""" 59 | m = folium.Map( 60 | width=800, 61 | height=600, 62 | ) 63 | 64 | m.get_root().render() 65 | header = m.get_root().header.render() 66 | body_html = m.get_root().html.render() 67 | script = m.get_root().script.render() 68 | 69 | return render_template_string( 70 | """ 71 | 72 | 73 | 74 | {{ header|safe }} 75 | 76 | 77 |

Using components

78 | {{ body_html|safe }} 79 | 82 | 83 | 84 | """, 85 | header=header, 86 | body_html=body_html, 87 | script=script, 88 | ) 89 | 90 | 91 | if __name__ == "__main__": 92 | app.run(debug=True) 93 | -------------------------------------------------------------------------------- /docs/_static/folium_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/python-visualization/folium/8e09fb812887860518e7de0eb1e3d539f01a804c/docs/_static/folium_logo.png -------------------------------------------------------------------------------- /docs/_templates/version.html: -------------------------------------------------------------------------------- 1 | 2 | Folium version {{ version }} 3 | -------------------------------------------------------------------------------- /docs/advanced_guide.rst: -------------------------------------------------------------------------------- 1 | Advanced guide 2 | ============== 3 | 4 | .. toctree:: 5 | :maxdepth: 1 6 | 7 | advanced_guide/flask 8 | advanced_guide/choropleth with Jenks natural breaks optimization 9 | advanced_guide/subplots 10 | advanced_guide/colormaps 11 | advanced_guide/world_copy 12 | advanced_guide/custom_panes 13 | advanced_guide/geodedetic_image_overlay 14 | advanced_guide/custom_tiles 15 | advanced_guide/piechart_icons 16 | advanced_guide/polygons_from_list_of_points 17 | advanced_guide/customize_javascript_and_css 18 | -------------------------------------------------------------------------------- /docs/advanced_guide/custom_panes.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | ``` 7 | 8 | # Panes and CustomPane 9 | 10 | Panes are used to control the ordering of layers on the map. You can customise 11 | them using the `CustomPane` class. 12 | 13 | For more info on the panes Leaflet has, see https://leafletjs.com/reference.html#map-pane. 14 | 15 | First we'll load geojson data to use in the examples: 16 | 17 | ```{code-cell} ipython3 18 | import requests 19 | 20 | geo_json_data = requests.get( 21 | "https://raw.githubusercontent.com/python-visualization/folium-example-data/main/us_states.json" 22 | ).json() 23 | 24 | style_function = lambda x: {"fillOpacity": 0.8} 25 | ``` 26 | 27 | ## Map without custom pane 28 | 29 | We'll make an example to show how the GeoJson we add hides any labels 30 | underneath. 31 | 32 | ```{code-cell} ipython3 33 | m = folium.Map([43, -100], zoom_start=4) 34 | 35 | folium.GeoJson(geo_json_data, style_function=style_function).add_to(m) 36 | 37 | m 38 | ``` 39 | 40 | ## Map with custom pane 41 | 42 | Now we'll create a custom pane and add a tile layer that contains only labels. 43 | The labels will show on top off the geojson. 44 | 45 | ```{code-cell} ipython3 46 | m = folium.Map([43, -100], zoom_start=4, tiles="cartodbpositronnolabels") 47 | 48 | folium.GeoJson(geo_json_data, style_function=style_function).add_to(m) 49 | 50 | folium.map.CustomPane("labels").add_to(m) 51 | 52 | # Final layer associated to custom pane via the appropriate kwarg 53 | folium.TileLayer("cartodbpositrononlylabels", pane="labels").add_to(m) 54 | 55 | m 56 | ``` 57 | -------------------------------------------------------------------------------- /docs/advanced_guide/custom_tiles.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | ``` 7 | 8 | # Custom tiles 9 | 10 | ## No tiles 11 | 12 | ```{code-cell} ipython3 13 | import requests 14 | 15 | states = requests.get( 16 | "https://raw.githubusercontent.com/python-visualization/folium-example-data/main/us_states.json" 17 | ).json() 18 | 19 | kw = {"location": [48, -102], "zoom_start": 3} 20 | ``` 21 | 22 | ```{code-cell} ipython3 23 | m = folium.Map(tiles=None, **kw) 24 | 25 | folium.GeoJson(states).add_to(m) 26 | 27 | m 28 | ``` 29 | 30 | ## Use image as tiles 31 | 32 | ```{code-cell} ipython3 33 | import branca 34 | 35 | # Create a white image of 4 pixels, and embed it in a url. 36 | white_tile = branca.utilities.image_to_url([[1, 1], [1, 1]]) 37 | 38 | # Create a map using this url for each tile. 39 | m = folium.Map(tiles=white_tile, attr="white tile", **kw) 40 | 41 | folium.GeoJson(states).add_to(m) 42 | 43 | m 44 | ``` 45 | 46 | ## Create a larger pattern to use as tiles 47 | 48 | ```{code-cell} ipython3 49 | images = [[(-1) ** ((i + j) // 30) for i in range(300)] for j in range(300)] 50 | 51 | tiles = branca.utilities.image_to_url(images) 52 | 53 | m = folium.Map(tiles=tiles, attr="Just because we can", **kw) 54 | 55 | folium.GeoJson(states).add_to(m) 56 | 57 | m 58 | ``` 59 | 60 | ```{code-cell} ipython3 61 | images = [[(-1) ** ((i // 30 + j // 30)) for i in range(300)] for j in range(300)] 62 | 63 | tiles = branca.utilities.image_to_url(images) 64 | 65 | m = folium.Map(tiles=tiles, attr="Just because we can", **kw) 66 | 67 | folium.GeoJson(states).add_to(m) 68 | 69 | m 70 | ``` 71 | -------------------------------------------------------------------------------- /docs/advanced_guide/flask.rst: -------------------------------------------------------------------------------- 1 | Using folium with flask 2 | ======================= 3 | 4 | A common use case is to use folium in a flask app. There are multiple ways you 5 | can do that. The simplest is to return the maps html representation. If instead 6 | you want to embed a map on an existing page, you can either embed an iframe 7 | or extract the map components and use those. 8 | 9 | Below is a script containing examples for all three use cases: 10 | 11 | .. literalinclude:: /_static/flask_example.py 12 | -------------------------------------------------------------------------------- /docs/advanced_guide/subplots.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | import branca 7 | ``` 8 | 9 | ## Subplots 10 | 11 | ### Two maps in one figure 12 | 13 | A `Map` automatically creates a `Figure` to put itself in. You can also do this 14 | manually, or in this example, create subplots to have two maps in one figure. 15 | 16 | ```{code-cell} ipython3 17 | fig = branca.element.Figure() 18 | 19 | subplot1 = fig.add_subplot(1, 2, 1) 20 | subplot2 = fig.add_subplot(1, 2, 2) 21 | 22 | subplot1.add_child( 23 | folium.Map([0, 0], zoom_start=1) 24 | ) 25 | subplot2.add_child( 26 | folium.Map([46, 3], tiles="OpenStreetMap", zoom_start=5) 27 | ) 28 | 29 | fig 30 | ``` 31 | 32 | 33 | ### Vega div and a Map 34 | 35 | Here we create a single figure in which we'll embed two maps and two Vega charts. 36 | Note that this also works with `VegaLite`. 37 | 38 | ```{code-cell} ipython3 39 | import json 40 | 41 | import numpy as np 42 | import vincent 43 | 44 | 45 | multi_iter2 = { 46 | "x": np.random.uniform(size=(100,)), 47 | "y": np.random.uniform(size=(100,)), 48 | } 49 | scatter = vincent.Scatter(multi_iter2, iter_idx="x", height=250, width=420) 50 | data = json.loads(scatter.to_json()) 51 | 52 | f = branca.element.Figure() 53 | 54 | # Create two maps. 55 | m = folium.Map( 56 | location=[0, 0], 57 | zoom_start=1, 58 | position="absolute", 59 | left="0%", 60 | width="50%", 61 | height="50%", 62 | ) 63 | 64 | m2 = folium.Map( 65 | location=[46, 3], 66 | tiles="OpenStreetMap", 67 | zoom_start=4, 68 | position="absolute", 69 | left="50%", 70 | width="50%", 71 | height="50%", 72 | top="50%", 73 | ) 74 | 75 | # Create two Vega charts 76 | v = folium.Vega(data, position="absolute", left="50%", width="50%", height="50%") 77 | 78 | v2 = folium.Vega( 79 | data, position="absolute", left="0%", width="50%", height="50%", top="50%" 80 | ) 81 | 82 | f.add_child(m) 83 | f.add_child(m2) 84 | f.add_child(v) 85 | f.add_child(v2) 86 | 87 | f 88 | ``` 89 | -------------------------------------------------------------------------------- /docs/advanced_guide/world_copy.md: -------------------------------------------------------------------------------- 1 | # Scrolling beyond the world edge 2 | 3 | What happens if you scroll beyond the longitudinal edge of the world? Leaflet has a setting 4 | to determine the behavior, which we'll demonstrate here. 5 | 6 | ## Defaults 7 | 8 | ```{code-cell} ipython3 9 | import folium 10 | 11 | m = folium.Map(world_copy_jump=False) 12 | 13 | folium.Marker( 14 | location=[0, 0], popup="I will disappear when moved outside the map domain." 15 | ).add_to(m) 16 | 17 | m 18 | ``` 19 | 20 | ## World copy jump 21 | 22 | ```{code-cell} ipython3 23 | m = folium.Map(world_copy_jump=True) 24 | 25 | folium.Marker( 26 | location=[0, 0], 27 | popup="I will magically reappear when moved outside the map domain.", 28 | ).add_to(m) 29 | 30 | m 31 | ``` 32 | 33 | ## No wrap 34 | 35 | ```{code-cell} ipython3 36 | m = folium.Map( 37 | tiles=folium.TileLayer(no_wrap=True) 38 | ) 39 | 40 | folium.Marker(location=[0, 0], popup="The map domain here is not wrapped.").add_to(m) 41 | 42 | m 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. Folium documentation master file, created by 2 | 3 | Folium 4 | ###### 5 | 6 | .. image:: _static/folium_logo.png 7 | :height: 100px 8 | :class: dark-light 9 | 10 | 11 | Python data, leaflet.js maps 12 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 13 | 14 | Folium builds on the data wrangling strengths of the Python ecosystem and the 15 | mapping strengths of the `Leaflet.js `_ library. 16 | Manipulate your data in Python, then visualize it in a Leaflet map via Folium. 17 | 18 | Concepts 19 | ======== 20 | 21 | Folium makes it easy to visualize data that's been manipulated in Python on an interactive leaflet map. 22 | It enables both the binding of data to a map for choropleth visualizations 23 | as well as passing rich vector/raster/HTML visualizations as markers on the map. 24 | 25 | The library has a number of built-in tilesets from OpenStreetMap, 26 | Mapbox, etc, and supports custom tilesets. 27 | Folium supports both Image, Video, GeoJSON and TopoJSON overlays and has a 28 | number of vector layers built-in. 29 | 30 | 31 | Contents 32 | ======== 33 | 34 | .. toctree:: 35 | :maxdepth: 1 36 | 37 | Home 38 | getting_started 39 | user_guide 40 | advanced_guide 41 | reference 42 | 43 | 44 | 45 | Indices and tables 46 | ================== 47 | 48 | * :ref:`genindex` 49 | * :ref:`modindex` 50 | * :ref:`search` 51 | -------------------------------------------------------------------------------- /docs/reference.rst: -------------------------------------------------------------------------------- 1 | API reference 2 | ============= 3 | 4 | Map 5 | -------------------- 6 | 7 | .. automodule:: folium.folium 8 | 9 | 10 | UI elements 11 | -------------------- 12 | 13 | .. automodule:: folium.map 14 | 15 | 16 | Raster Layers 17 | -------------------- 18 | 19 | .. automodule:: folium.raster_layers 20 | 21 | 22 | Vector Layers 23 | -------------------- 24 | 25 | .. automodule:: folium.vector_layers 26 | 27 | 28 | Other map features 29 | --------------------- 30 | 31 | .. automodule:: folium.features 32 | 33 | 34 | Utilities 35 | --------------------- 36 | 37 | .. autoclass:: folium.utilities.JsCode 38 | .. autoclass:: folium.elements.EventHandler 39 | 40 | 41 | Plugins 42 | -------------------- 43 | .. automodule:: folium.plugins 44 | -------------------------------------------------------------------------------- /docs/update_switcher.py: -------------------------------------------------------------------------------- 1 | """ 2 | This script is used to update switcher.json on docs releases. It adds the new version to 3 | the list of versions and sets the latest version to the new version. 4 | """ 5 | 6 | import argparse 7 | import json 8 | import os 9 | 10 | 11 | def main(): 12 | # Define CLI arguments 13 | parser = argparse.ArgumentParser(description="Update switcher.json") 14 | parser.add_argument( 15 | "--version", "-v", required=True, type=str, help="The new version to add" 16 | ) 17 | args = parser.parse_args() 18 | # drop the "v" prefix 19 | new_version_without_prefix = args.version[1:] 20 | 21 | # Setup path to switcher.json (relative to this script) and load it 22 | switcher_path = os.path.join(os.path.dirname(__file__), "_static", "switcher.json") 23 | with open(switcher_path) as f: 24 | switcher = json.load(f) 25 | 26 | # first we get the version number of the previous version 27 | for i, version in enumerate(switcher): 28 | if version.get("name", "").startswith("latest"): 29 | latest_index = i 30 | previous_version = version["version"] 31 | if previous_version == new_version_without_prefix: 32 | print( 33 | f"Version {new_version_without_prefix} already is the latest version. Exiting." 34 | ) 35 | return 36 | 37 | # now replace the name and version of this one with the new version 38 | switcher[i]["name"] = f"latest ({new_version_without_prefix})" 39 | switcher[i]["version"] = new_version_without_prefix 40 | break 41 | else: 42 | raise ValueError("'latest' version not found in switcher.json") 43 | 44 | # Add the previous version to the list of versions (we always insert it after latest) 45 | if any(version["version"] == previous_version for version in switcher): 46 | print( 47 | f"Previous version {previous_version} already exists in switcher.json. Not adding it again." 48 | ) 49 | else: 50 | previous_version_entry = { 51 | "version": previous_version, 52 | "url": f"https://python-visualization.github.io/folium/v{previous_version}/", 53 | } 54 | switcher.insert(latest_index + 1, previous_version_entry) 55 | 56 | # Write the updated switcher.json 57 | with open(switcher_path, "w") as f: 58 | json.dump(switcher, f, indent=2) 59 | 60 | 61 | if __name__ == "__main__": 62 | main() 63 | -------------------------------------------------------------------------------- /docs/user_guide.rst: -------------------------------------------------------------------------------- 1 | User guide 2 | ========== 3 | 4 | The user guide covers different parts of basic usage of Folium. Each page focuses on a single topic and outlines how it is implemented in Folium, with reproducible examples. 5 | 6 | If you don't know anything about Folium, start with the :doc:`getting_started`. 7 | 8 | Advanced topics can be found in the :doc:`Advanced Guide ` and further specification in the :doc:`API Reference `. 9 | 10 | .. toctree:: 11 | :maxdepth: 2 12 | 13 | user_guide/map 14 | user_guide/ui_elements 15 | user_guide/raster_layers 16 | user_guide/vector_layers 17 | user_guide/geojson 18 | user_guide/features 19 | user_guide/plugins 20 | -------------------------------------------------------------------------------- /docs/user_guide/features.rst: -------------------------------------------------------------------------------- 1 | Features 2 | -------------------------- 3 | 4 | .. toctree:: 5 | :maxdepth: 1 6 | 7 | features/fit_overlays 8 | features/click_related_classes 9 | -------------------------------------------------------------------------------- /docs/user_guide/features/click_related_classes.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | ``` 7 | 8 | ### Click-related classes 9 | 10 | #### ClickForMarker 11 | 12 | `ClickForMarker` lets you create markers on each click. 13 | 14 | ```{code-cell} ipython3 15 | folium.Map().add_child( 16 | folium.ClickForMarker() 17 | ) 18 | ``` 19 | 20 | *Click on the map to see the effects* 21 | 22 | You can customize the popup by providing a string, an IFrame object or an Html object. You can include the latitude and longitude of the marker by using `${lat}` and `${lng}`. 23 | 24 | ```{code-cell} ipython3 25 | folium.Map().add_child( 26 | folium.ClickForMarker("Lat: ${lat}
Lon: ${lng}") 27 | ) 28 | ``` 29 | 30 | *Click on the map to see the effects* 31 | 32 | 33 | #### LatLngPopup 34 | 35 | `LatLngPopup` lets you create a simple popup at each click. 36 | 37 | ```{code-cell} ipython3 38 | folium.Map().add_child( 39 | folium.LatLngPopup() 40 | ) 41 | ``` 42 | 43 | *Click on the map to see the effects* 44 | 45 | +++ 46 | 47 | #### ClickForLatLng 48 | 49 | `ClickForLatLng` lets you copy coordinates to your browser clipboard. 50 | 51 | ```{code-cell} ipython3 52 | folium.Map().add_child( 53 | folium.ClickForLatLng(format_str='"[" + lat + "," + lng + "]"', alert=True) 54 | ) 55 | ``` 56 | 57 | *Click on the map to see the effects* 58 | 59 | If you want to collect back the information in python, you may (install and) import the [clipboard](https://github.com/terryyin/clipboard) library: 60 | 61 | ``` 62 | >>> import clipboard 63 | >>> clipboard.paste() 64 | [-43.580391,-123.824467] 65 | ``` 66 | -------------------------------------------------------------------------------- /docs/user_guide/features/fit_overlays.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | ``` 7 | 8 | ## FitOverlays 9 | 10 | When you add this class to your map, the map will pan and zoom to fit the enabled overlays. 11 | 12 | By default, the map won't necessarily show all elements that were added. You may have to pan or zoom out to find them. 13 | 14 | If we add the `FitOverlays` class, it will automatically pan and zoom to show the enabled overlays. 15 | In this example we show only the first marker by default. If you enable the second marker, the view changes to include it. 16 | 17 | ```{code-cell} ipython3 18 | m = folium.Map((52, 0), tiles='cartodbpositron', zoom_start=8) 19 | 20 | fg1 = folium.FeatureGroup().add_to(m) 21 | folium.Marker((52, 5)).add_to(fg1) 22 | 23 | fg2 = folium.FeatureGroup(show=False).add_to(m) 24 | folium.Marker((52, 5.1)).add_to(fg2) 25 | 26 | folium.FitOverlays().add_to(m) 27 | 28 | folium.LayerControl().add_to(m) 29 | 30 | m 31 | ``` 32 | 33 | `FitOverlays` has a couple options: 34 | 35 | - `padding` adds pixels around the bounds. 36 | - `max_zoom` can be used to prevent zooming in too far. 37 | - `fly` enables a smoother, longer animation, so you can see how the view changes. 38 | - `fit_on_map_load` can be used to disable the fitting that happens when the map loads. 39 | 40 | Note that `padding` and `max_zoom` can achieve the same effect. 41 | -------------------------------------------------------------------------------- /docs/user_guide/geojson.rst: -------------------------------------------------------------------------------- 1 | GeoJSON and choropleth 2 | -------------------------- 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | geojson/geojson 8 | geojson/choropleth 9 | geojson/geojson_marker 10 | geojson/geojson_popup_and_tooltip 11 | geojson/geopandas_and_geo_interface 12 | geojson/smoothing 13 | -------------------------------------------------------------------------------- /docs/user_guide/geojson/smoothing.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | ``` 7 | 8 | # Smoothing 9 | 10 | The level of smoothing of the geometry can be determined by passing `smooth_factor` as an argument when initialising GeoJson, TopoJson and Choropleth objects. There are no upper or lower bounds to the smoothing level; Leaflet's default is 1. 11 | 12 | ```{code-cell} ipython3 13 | import requests 14 | 15 | m = folium.Map(location=[-59.1759, -11.6016], tiles="cartodbpositron", zoom_start=2) 16 | 17 | topo = requests.get( 18 | "https://raw.githubusercontent.com/python-visualization/folium-example-data/main/antarctic_ice_shelf_topo.json" 19 | ).json() 20 | 21 | folium.TopoJson( 22 | data=topo, 23 | object_path="objects.antarctic_ice_shelf", 24 | name="default_smoothing", 25 | smooth_factor=1, 26 | style_function=lambda x: {"color": "#004c00", "opacity": "0.7"}, 27 | ).add_to(m) 28 | 29 | 30 | folium.TopoJson( 31 | data=topo, 32 | object_path="objects.antarctic_ice_shelf", 33 | name="heavier smoothing", 34 | smooth_factor=10, 35 | style_function=lambda x: {"color": "#1d3060", "opacity": "0.7"}, 36 | ).add_to(m) 37 | 38 | folium.LayerControl().add_to(m) 39 | 40 | m 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/user_guide/map.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | ``` 7 | 8 | # Map 9 | 10 | ## Scale 11 | 12 | Show a scale on the bottom of the map. 13 | 14 | ```{code-cell} ipython3 15 | folium.Map( 16 | location=(-38.625, -12.875), 17 | control_scale=True, 18 | ) 19 | ``` 20 | 21 | ## Zoom control 22 | 23 | The map shows zoom buttons by default, but you can disable them. 24 | 25 | ```{code-cell} ipython3 26 | folium.Map( 27 | location=(-38.625, -12.875), 28 | zoom_control=False, 29 | ) 30 | ``` 31 | 32 | ## Limits 33 | 34 | You can set limits, so the map won't scroll outside those limits. 35 | 36 | ```{code-cell} ipython3 37 | import folium 38 | 39 | min_lon, max_lon = -45, -35 40 | min_lat, max_lat = -25, -15 41 | 42 | m = folium.Map( 43 | max_bounds=True, 44 | location=[-20, -40], 45 | zoom_start=6, 46 | min_lat=min_lat, 47 | max_lat=max_lat, 48 | min_lon=min_lon, 49 | max_lon=max_lon, 50 | ) 51 | 52 | folium.CircleMarker([max_lat, min_lon], tooltip="Upper Left Corner").add_to(m) 53 | folium.CircleMarker([min_lat, min_lon], tooltip="Lower Left Corner").add_to(m) 54 | folium.CircleMarker([min_lat, max_lon], tooltip="Lower Right Corner").add_to(m) 55 | folium.CircleMarker([max_lat, max_lon], tooltip="Upper Right Corner").add_to(m) 56 | 57 | m 58 | ``` 59 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/WmsTimeDimension.md: -------------------------------------------------------------------------------- 1 | # TimestampedWmsTileLayers 2 | 3 | Add a time dimension to a WMS tile layer. 4 | 5 | ### Exploring the WMS with OWSLib 6 | 7 | ```{code-cell} ipython3 8 | from owslib.wms import WebMapService 9 | 10 | 11 | url = "https://pae-paha.pacioos.hawaii.edu/thredds/wms/dhw_5km?service=WMS" 12 | 13 | web_map_services = WebMapService(url) 14 | 15 | print("\n".join(web_map_services.contents.keys())) 16 | ``` 17 | 18 | ### Layer metadata 19 | 20 | ```{code-cell} ipython3 21 | layer = "CRW_SST" 22 | wms = web_map_services.contents[layer] 23 | 24 | name = wms.title 25 | 26 | lon = (wms.boundingBox[0] + wms.boundingBox[2]) / 2.0 27 | lat = (wms.boundingBox[1] + wms.boundingBox[3]) / 2.0 28 | center = lat, lon 29 | 30 | time_interval = "{0}/{1}".format( 31 | wms.timepositions[0].strip(), wms.timepositions[-1].strip() 32 | ) 33 | style = "boxfill/sst_36" 34 | 35 | if style not in wms.styles: 36 | style = None 37 | ``` 38 | 39 | ### Map with WmsTileLayer and TimestampedWmsTileLayers 40 | 41 | ```{code-cell} ipython3 42 | import folium 43 | import folium.plugins 44 | 45 | m = folium.Map(location=[-40, -50], zoom_start=5) 46 | 47 | wms_tile_layer = folium.WmsTileLayer( 48 | url=url, 49 | name=name, 50 | styles=style, 51 | fmt="image/png", 52 | transparent=True, 53 | layers=layer, 54 | overlay=True, 55 | COLORSCALERANGE="1.2,28", 56 | ).add_to(m) 57 | 58 | folium.plugins.TimestampedWmsTileLayers( 59 | wms_tile_layer, 60 | period="PT1H", 61 | time_interval=time_interval, 62 | ).add_to(m) 63 | 64 | folium.LayerControl().add_to(m) 65 | 66 | m 67 | ``` 68 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/antpath.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | import folium.plugins 7 | ``` 8 | 9 | 10 | ## Antpath 11 | 12 | ```{code-cell} ipython3 13 | m = folium.Map() 14 | 15 | wind_locations = [ 16 | [59.35560, -31.992190], 17 | [55.178870, -42.89062], 18 | [47.754100, -43.94531], 19 | [38.272690, -37.96875], 20 | [27.059130, -41.13281], 21 | [16.299050, -36.56250], 22 | [8.4071700, -30.23437], 23 | [1.0546300, -22.50000], 24 | [-8.754790, -18.28125], 25 | [-21.61658, -20.03906], 26 | [-31.35364, -24.25781], 27 | [-39.90974, -30.93750], 28 | [-43.83453, -41.13281], 29 | [-47.75410, -49.92187], 30 | [-50.95843, -54.14062], 31 | [-55.97380, -56.60156], 32 | ] 33 | 34 | folium.plugins.AntPath( 35 | locations=wind_locations, reverse="True", dash_array=[20, 30] 36 | ).add_to(m) 37 | 38 | m.fit_bounds(m.get_bounds()) 39 | 40 | m 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/beautify_icon.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | import folium.plugins 7 | ``` 8 | 9 | ## BeautifyIcon 10 | 11 | ```{code-cell} ipython3 12 | m = folium.Map([45.5, -122], zoom_start=3) 13 | 14 | icon_plane = folium.plugins.BeautifyIcon( 15 | icon="plane", border_color="#b3334f", text_color="#b3334f", icon_shape="triangle" 16 | ) 17 | 18 | icon_number = folium.plugins.BeautifyIcon( 19 | border_color="#00ABDC", 20 | text_color="#00ABDC", 21 | number=10, 22 | inner_icon_style="margin-top:0;", 23 | ) 24 | 25 | folium.Marker(location=[46, -122], popup="Portland, OR", icon=icon_plane).add_to(m) 26 | 27 | folium.Marker(location=[50, -122], popup="Portland, OR", icon=icon_number).add_to(m) 28 | 29 | m 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/boat_marker.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | import folium.plugins 7 | ``` 8 | 9 | ## BoatMarker 10 | 11 | ```{code-cell} ipython3 12 | m = folium.Map([30, 0], zoom_start=3) 13 | 14 | folium.plugins.BoatMarker( 15 | location=(34, -43), heading=45, wind_heading=150, wind_speed=45, color="#8f8" 16 | ).add_to(m) 17 | 18 | folium.plugins.BoatMarker( 19 | location=(46, -30), heading=-20, wind_heading=46, wind_speed=25, color="#88f" 20 | ).add_to(m) 21 | 22 | m 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/draw.md: -------------------------------------------------------------------------------- 1 | # Draw 2 | 3 | ```{code-cell} ipython3 4 | import folium 5 | from folium.plugins import Draw 6 | 7 | m = folium.Map() 8 | 9 | Draw(export=True).add_to(m) 10 | 11 | m 12 | ``` 13 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/dual_map.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | import folium.plugins 7 | ``` 8 | 9 | # DualMap plugin 10 | 11 | This plugin is using the Leaflet plugin Sync by Jieter: 12 | https://github.com/jieter/Leaflet.Sync 13 | 14 | The goal is to have two maps side by side. When you pan or zoom on one map, the other will move as well. 15 | 16 | The `DualMap` class accepts the same arguments as the normal `Map` class. Except for these: 'width', 'height', 'left', 'top', 'position'. 17 | 18 | In the following example we create a `DualMap`, add layer controls and then show the map. Try panning and zooming to check that both maps are synchronized. 19 | 20 | ```{code-cell} ipython3 21 | folium.plugins.DualMap(location=(52.1, 5.1), zoom_start=8) 22 | ``` 23 | 24 | You can access the two submaps with attributes `m1` and `m2`. You can add objects to each map specifically. 25 | 26 | Here we add different tile layers to each map. This way you can see two different tile sets at the same time. 27 | 28 | ```{code-cell} ipython3 29 | m = folium.plugins.DualMap(location=(52.1, 5.1), tiles=None, zoom_start=8) 30 | 31 | folium.TileLayer("openstreetmap").add_to(m.m1) 32 | folium.TileLayer("cartodbpositron").add_to(m.m2) 33 | 34 | folium.LayerControl(collapsed=False).add_to(m) 35 | m 36 | ``` 37 | 38 | Now we're going to add feature groups and markers to both maps and to each map individually. We'll color the shared icon red. 39 | 40 | ```{code-cell} ipython3 41 | m = folium.plugins.DualMap(location=(52.1, 5.1), tiles="cartodbpositron", zoom_start=8) 42 | 43 | fg_both = folium.FeatureGroup(name="markers_both").add_to(m) 44 | fg_1 = folium.FeatureGroup(name="markers_1").add_to(m.m1) 45 | fg_2 = folium.FeatureGroup(name="markers_2").add_to(m.m2) 46 | 47 | icon_red = folium.Icon(color="red") 48 | folium.Marker((52.0, 5.0), tooltip="both", icon=icon_red).add_to(fg_both) 49 | folium.Marker((52.4, 5.0), tooltip="1").add_to(fg_1) 50 | folium.Marker((52.0, 5.4), tooltip="2").add_to(fg_2) 51 | 52 | folium.LayerControl(collapsed=False).add_to(m) 53 | m 54 | ``` 55 | 56 | Finally, you can use the `layout` argument to change the layout to vertical: 57 | 58 | ```{code-cell} ipython3 59 | m = folium.plugins.DualMap(layout="vertical") 60 | m 61 | ``` 62 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/featuregroup_subgroup.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | import folium.plugins 7 | ``` 8 | 9 | ## FeatureGroupSubGroup 10 | 11 | ### Sub categories 12 | 13 | Disable all markers in the category, or just one of the subgroup. 14 | 15 | ```{code-cell} ipython3 16 | m = folium.Map(location=[0, 0], zoom_start=6) 17 | 18 | fg = folium.FeatureGroup(name="groups") 19 | m.add_child(fg) 20 | 21 | g1 = folium.plugins.FeatureGroupSubGroup(fg, "group1") 22 | m.add_child(g1) 23 | 24 | g2 = folium.plugins.FeatureGroupSubGroup(fg, "group2") 25 | m.add_child(g2) 26 | 27 | folium.Marker([-1, -1]).add_to(g1) 28 | folium.Marker([1, 1]).add_to(g1) 29 | 30 | folium.Marker([-1, 1]).add_to(g2) 31 | folium.Marker([1, -1]).add_to(g2) 32 | 33 | folium.LayerControl(collapsed=False).add_to(m) 34 | 35 | m 36 | ``` 37 | 38 | ### Marker clusters across groups 39 | 40 | Create two subgroups, but cluster markers together. 41 | 42 | ```{code-cell} ipython3 43 | m = folium.Map(location=[0, 0], zoom_start=6) 44 | 45 | mcg = folium.plugins.MarkerCluster(control=False) 46 | m.add_child(mcg) 47 | 48 | g1 = folium.plugins.FeatureGroupSubGroup(mcg, "group1") 49 | m.add_child(g1) 50 | 51 | g2 = folium.plugins.FeatureGroupSubGroup(mcg, "group2") 52 | m.add_child(g2) 53 | 54 | folium.Marker([-1, -1]).add_to(g1) 55 | folium.Marker([1, 1]).add_to(g1) 56 | 57 | folium.Marker([-1, 1]).add_to(g2) 58 | folium.Marker([1, -1]).add_to(g2) 59 | 60 | folium.LayerControl(collapsed=False).add_to(m) 61 | 62 | m 63 | ``` 64 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/float_image.md: -------------------------------------------------------------------------------- 1 | # FloatImage 2 | 3 | ```{code-cell} ipython3 4 | import folium 5 | from folium.plugins import FloatImage 6 | 7 | 8 | url = ( 9 | "https://raw.githubusercontent.com/ocefpaf/secoora_assets_map/" 10 | "a250729bbcf2ddd12f46912d36c33f7539131bec/secoora_icons/rose.png" 11 | ) 12 | 13 | m = folium.Map([-13, -38.15], zoom_start=10) 14 | 15 | FloatImage(url, bottom=40, left=65).add_to(m) 16 | 17 | m 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/fullscreen.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | import folium.plugins 7 | ``` 8 | 9 | ## Fullscreen 10 | 11 | Add a button to toggle a fullscreen view of the map. 12 | 13 | ```{code-cell} ipython3 14 | m = folium.Map(location=[41.9, -97.3], zoom_start=4) 15 | 16 | folium.plugins.Fullscreen( 17 | position="topright", 18 | title="Expand me", 19 | title_cancel="Exit me", 20 | force_separate_button=True, 21 | ).add_to(m) 22 | 23 | m 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/geocoder.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | import folium.plugins 7 | ``` 8 | 9 | ## Geocoder 10 | 11 | Add a search box to the map to search for geographic features like cities, countries, etc. You can search with names or addresses. 12 | 13 | Uses the Nomatim service from OpenStreetMap. Please respect their usage policy: https://operations.osmfoundation.org/policies/nominatim/ 14 | 15 | ```{code-cell} ipython3 16 | m = folium.Map() 17 | 18 | folium.plugins.Geocoder().add_to(m) 19 | 20 | m 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/grouped_layer_control.md: -------------------------------------------------------------------------------- 1 | # GroupedLayerControl 2 | 3 | We can create a GroupedLayerControl and define what layers we want to group together. Those layers won't show up in the regular layer control. 4 | 5 | `GroupedLayerControl` takes the same arguments as `LayerControl`. 6 | 7 | By default, groups are exclusive, meaning only one layer in a group can be active at a time. 8 | 9 | ```{code-cell} ipython3 10 | import folium 11 | from folium.plugins import GroupedLayerControl 12 | 13 | m = folium.Map([40., 70.], zoom_start=6) 14 | 15 | fg1 = folium.FeatureGroup(name='g1') 16 | fg2 = folium.FeatureGroup(name='g2') 17 | fg3 = folium.FeatureGroup(name='g3') 18 | folium.Marker([40, 74]).add_to(fg1) 19 | folium.Marker([38, 72]).add_to(fg2) 20 | folium.Marker([40, 72]).add_to(fg3) 21 | m.add_child(fg1) 22 | m.add_child(fg2) 23 | m.add_child(fg3) 24 | 25 | folium.LayerControl(collapsed=False).add_to(m) 26 | 27 | GroupedLayerControl( 28 | groups={'groups1': [fg1, fg2]}, 29 | collapsed=False, 30 | ).add_to(m) 31 | 32 | m 33 | ``` 34 | 35 | It's also possible to have check boxes instead of radio buttons, so multiple layers within a group can be active. 36 | 37 | In this example the layers are not shown by default, but can all be activated. 38 | 39 | ```{code-cell} ipython3 40 | m = folium.Map([40., 70.], zoom_start=6) 41 | 42 | fg1 = folium.FeatureGroup(name='g1', show=False) 43 | fg2 = folium.FeatureGroup(name='g2', show=False) 44 | fg3 = folium.FeatureGroup(name='g3') 45 | folium.Marker([40, 74]).add_to(fg1) 46 | folium.Marker([38, 72]).add_to(fg2) 47 | folium.Marker([40, 72]).add_to(fg3) 48 | m.add_child(fg1) 49 | m.add_child(fg2) 50 | m.add_child(fg3) 51 | 52 | folium.LayerControl(collapsed=False).add_to(m) 53 | 54 | GroupedLayerControl( 55 | groups={'groups1': [fg1, fg2]}, 56 | exclusive_groups=False, 57 | collapsed=False, 58 | ).add_to(m) 59 | 60 | m 61 | ``` 62 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/heatmap.md: -------------------------------------------------------------------------------- 1 | ## Heatmap 2 | 3 | ```{code-cell} ipython3 4 | import numpy as np 5 | 6 | data = ( 7 | np.random.normal(size=(100, 3)) * np.array([[1, 1, 1]]) + np.array([[48, 5, 1]]) 8 | ).tolist() 9 | ``` 10 | 11 | ```{code-cell} ipython3 12 | import folium 13 | from folium.plugins import HeatMap 14 | 15 | m = folium.Map([48.0, 5.0], zoom_start=6) 16 | 17 | HeatMap(data).add_to(m) 18 | 19 | m 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/heatmap_with_time.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | import folium.plugins 7 | ``` 8 | 9 | # HeatMapWithTime 10 | 11 | In this example we show the basic usage of the HeatMapWithTime plugin. 12 | 13 | ### Data 14 | 15 | We generate a random set of points with lat/lon coordinates to draw on the map, and then move these points slowly in a random direction to simulate a time dimension. The points are arranged into a list of sets of data to draw. 16 | 17 | ```{code-cell} ipython3 18 | import numpy as np 19 | 20 | np.random.seed(3141592) 21 | initial_data = np.random.normal(size=(100, 2)) * np.array([[1, 1]]) + np.array( 22 | [[48, 5]] 23 | ) 24 | 25 | move_data = np.random.normal(size=(100, 2)) * 0.01 26 | 27 | data = [(initial_data + move_data * i).tolist() for i in range(100)] 28 | ``` 29 | 30 | ### Weights 31 | 32 | In order to control intensity shown on the map, each data entry needs to have a `weight`. Which should be between 0 and 1. 33 | Below we generate weights randomly such that intensity increases over time. 34 | 35 | ```{code-cell} ipython3 36 | time_ = 0 37 | N = len(data) 38 | itensify_factor = 30 39 | for time_entry in data: 40 | time_ = time_+1 41 | for row in time_entry: 42 | weight = min(np.random.uniform()*(time_/(N))*itensify_factor, 1) 43 | row.append(weight) 44 | ``` 45 | 46 | ```{code-cell} ipython3 47 | m = folium.Map([48.0, 5.0], zoom_start=6) 48 | 49 | hm = folium.plugins.HeatMapWithTime(data) 50 | 51 | hm.add_to(m) 52 | 53 | m 54 | ``` 55 | 56 | ### Options 57 | 58 | Now we show that the time index can be specified, allowing a more meaningful representation of what the time steps mean. We also enable the 'auto_play' option and change the maximum opacity. See the documentation for a full list of options that can be used. 59 | 60 | ```{code-cell} ipython3 61 | from datetime import datetime, timedelta 62 | 63 | time_index = [ 64 | (datetime.now() + k * timedelta(1)).strftime("%Y-%m-%d") for k in range(len(data)) 65 | ] 66 | ``` 67 | 68 | ```{code-cell} ipython3 69 | m = folium.Map([48.0, 5.0], zoom_start=6) 70 | 71 | hm = folium.plugins.HeatMapWithTime(data, index=time_index, auto_play=True, max_opacity=0.3) 72 | 73 | hm.add_to(m) 74 | 75 | m 76 | ``` 77 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/locate_control.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | import folium.plugins 7 | ``` 8 | 9 | ## LocateControl 10 | 11 | Adds a control button that when clicked, the user device geolocation is displayed. 12 | For list of all possible keyword options see 'Possible options' on https://github.com/domoritz/leaflet-locatecontrol. 13 | 14 | To work properly in production, the connection needs to be encrypted (HTTPS), 15 | otherwise the browser will not allow users to share their location. 16 | 17 | ```{code-cell} ipython3 18 | m = folium.Map([41.97, 2.81]) 19 | 20 | folium.plugins.LocateControl().add_to(m) 21 | 22 | # If you want get the user device position after load the map, set auto_start=True 23 | folium.plugins.LocateControl(auto_start=False).add_to(m) 24 | 25 | m 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/measure_control.md: -------------------------------------------------------------------------------- 1 | # MeasureControl 2 | 3 | This plugin allows you to measure distances on the map. 4 | 5 | ```{code-cell} ipython3 6 | import folium 7 | from folium.plugins import MeasureControl 8 | 9 | m = folium.Map([-27.5717, -48.6256], zoom_start=10) 10 | 11 | m.add_child(MeasureControl()) 12 | 13 | m 14 | ``` 15 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/mini_map.md: -------------------------------------------------------------------------------- 1 | ## MiniMap 2 | 3 | ```{code-cell} ipython3 4 | import folium 5 | from folium.plugins import MiniMap 6 | 7 | m = folium.Map(location=(30, 20), zoom_start=4) 8 | 9 | MiniMap().add_to(m) 10 | 11 | m 12 | ``` 13 | 14 | ### Make the minimap collapsible 15 | 16 | ```{code-cell} ipython3 17 | m = folium.Map(location=(30, 20), zoom_start=4) 18 | MiniMap(toggle_display=True).add_to(m) 19 | m 20 | ``` 21 | 22 | ### Change the minimap tile layer 23 | 24 | ```{code-cell} ipython3 25 | m = folium.Map(location=(30, 20), zoom_start=4) 26 | MiniMap(tile_layer="Cartodb dark_matter").add_to(m) 27 | m 28 | ``` 29 | 30 | ### Change the minimap position 31 | 32 | ```{code-cell} ipython3 33 | m = folium.Map(location=(30, 20), zoom_start=4) 34 | MiniMap(position="topleft").add_to(m) 35 | m 36 | ``` 37 | 38 | ### Change the minimap size 39 | 40 | ```{code-cell} ipython3 41 | m = folium.Map(location=(30, 20), zoom_start=4) 42 | MiniMap(width=400, height=100).add_to(m) 43 | m 44 | ``` 45 | 46 | ### Change the zoom offset 47 | 48 | ```{code-cell} ipython3 49 | m = folium.Map(location=(30, 20), zoom_start=8) 50 | MiniMap(zoom_level_offset=-8).add_to(m) 51 | m 52 | ``` 53 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/mouse_position.md: -------------------------------------------------------------------------------- 1 | # MousePosition 2 | 3 | This plugin adds a small field to your map that shows the coordinates of your mouse position. 4 | By default it is in the bottom right corner. 5 | 6 | ```{code-cell} ipython3 7 | import folium 8 | from folium.plugins import MousePosition 9 | 10 | 11 | m = folium.Map() 12 | 13 | MousePosition().add_to(m) 14 | 15 | m 16 | ``` 17 | 18 | ## Options 19 | 20 | ```{code-cell} ipython3 21 | m = folium.Map() 22 | 23 | formatter = "function(num) {return L.Util.formatNum(num, 3) + ' ° ';};" 24 | 25 | MousePosition( 26 | position="topright", 27 | separator=" | ", 28 | empty_string="NaN", 29 | lng_first=True, 30 | num_digits=20, 31 | prefix="Coordinates:", 32 | lat_formatter=formatter, 33 | lng_formatter=formatter, 34 | ).add_to(m) 35 | 36 | m 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/pattern.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | import folium.plugins 7 | ``` 8 | 9 | # Pattern plugins 10 | 11 | We have two pattern plugin classes: `StripePattern` and `CirclePattern`. 12 | 13 | ```{code-cell} ipython3 14 | import requests 15 | 16 | m = folium.Map([40.0, -105.0], zoom_start=6) 17 | 18 | stripes = folium.plugins.pattern.StripePattern(angle=-45).add_to(m) 19 | 20 | circles = folium.plugins.pattern.CirclePattern( 21 | width=20, height=20, radius=5, fill_opacity=0.5, opacity=1 22 | ).add_to(m) 23 | 24 | 25 | def style_function(feature): 26 | default_style = { 27 | "opacity": 1.0, 28 | "fillColor": "#ffff00", 29 | "color": "black", 30 | "weight": 2, 31 | } 32 | 33 | if feature["properties"]["name"] == "Colorado": 34 | default_style["fillPattern"] = stripes 35 | default_style["fillOpacity"] = 1.0 36 | 37 | if feature["properties"]["name"] == "Utah": 38 | default_style["fillPattern"] = circles 39 | default_style["fillOpacity"] = 1.0 40 | 41 | return default_style 42 | 43 | us_states = requests.get( 44 | "https://raw.githubusercontent.com/python-visualization/folium-example-data/main/us_states.json" 45 | ).json() 46 | 47 | folium.GeoJson( 48 | us_states, 49 | smooth_factor=0.5, 50 | style_function=style_function, 51 | ).add_to(m) 52 | 53 | m 54 | ``` 55 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/polygon_encoded.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | from folium import plugins 7 | ``` 8 | 9 | # PolygonFromEncoded 10 | 11 | Create a Polygon directly from an encoded polyline string. To understand the encoding algorithm 12 | refer to [this](https://developers.google.com/maps/documentation/utilities/polylinealgorithm) link. 13 | 14 | ```{code-cell} ipython3 15 | 16 | m = folium.Map(location=[40, -80], zoom_start=5) 17 | 18 | encoded = r"w`j~FpxivO}jz@qnnCd}~Bsa{@~f`C`lkH" 19 | plugins.PolygonFromEncoded(encoded=encoded).add_to(m) 20 | 21 | m 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/polyline_encoded.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | from folium import plugins 7 | ``` 8 | 9 | # PolyLineFromEncoded 10 | 11 | Create a PolyLine directly from an encoded polyline string. To understand the encoding algorithm 12 | refer to [this](https://developers.google.com/maps/documentation/utilities/polylinealgorithm) link. 13 | 14 | ```{code-cell} ipython3 15 | 16 | m = folium.Map(location=[40, -120], zoom_start=5) 17 | 18 | encoded = r"_p~iF~cn~U_ulLn{vA_mqNvxq`@" 19 | plugins.PolyLineFromEncoded(encoded=encoded).add_to(m) 20 | 21 | m 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/polyline_textpath.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | import folium.plugins 7 | ``` 8 | 9 | ## PolyLineTextPath 10 | 11 | ```{code-cell} ipython3 12 | m = folium.Map([30, 0], zoom_start=3) 13 | 14 | wind_locations = [ 15 | [59.35560, -31.992190], 16 | [55.178870, -42.89062], 17 | [47.754100, -43.94531], 18 | [38.272690, -37.96875], 19 | [27.059130, -41.13281], 20 | [16.299050, -36.56250], 21 | [8.4071700, -30.23437], 22 | [1.0546300, -22.50000], 23 | [-8.754790, -18.28125], 24 | [-21.61658, -20.03906], 25 | [-31.35364, -24.25781], 26 | [-39.90974, -30.93750], 27 | [-43.83453, -41.13281], 28 | [-47.75410, -49.92187], 29 | [-50.95843, -54.14062], 30 | [-55.97380, -56.60156], 31 | ] 32 | 33 | wind_line = folium.PolyLine(wind_locations, weight=15, color="#8EE9FF").add_to(m) 34 | 35 | attr = {"fill": "#007DEF", "font-weight": "bold", "font-size": "24"} 36 | 37 | folium.plugins.PolyLineTextPath( 38 | wind_line, ") ", repeat=True, offset=7, attributes=attr 39 | ).add_to(m) 40 | 41 | danger_line = folium.PolyLine( 42 | [[-40.311, -31.952], [-12.086, -18.727]], weight=10, color="orange", opacity=0.8 43 | ).add_to(m) 44 | 45 | attr = {"fill": "red"} 46 | 47 | folium.plugins.PolyLineTextPath( 48 | danger_line, "\u25BA", repeat=True, offset=6, attributes=attr 49 | ).add_to(m) 50 | 51 | plane_line = folium.PolyLine( 52 | [[-49.38237, -37.26562], [-1.75754, -14.41406], [51.61802, -23.20312]], 53 | weight=1, 54 | color="black", 55 | ).add_to(m) 56 | 57 | attr = {"font-weight": "bold", "font-size": "24"} 58 | 59 | folium.plugins.PolyLineTextPath( 60 | plane_line, "\u2708 ", repeat=True, offset=8, attributes=attr 61 | ).add_to(m) 62 | 63 | 64 | line_to_new_delhi = folium.PolyLine( 65 | [ 66 | [46.67959447, 3.33984375], 67 | [46.5588603, 29.53125], 68 | [42.29356419, 51.328125], 69 | [35.74651226, 68.5546875], 70 | [28.65203063, 76.81640625], 71 | ] 72 | ).add_to(m) 73 | 74 | 75 | line_to_hanoi = folium.PolyLine( 76 | [ 77 | [28.76765911, 77.60742188], 78 | [27.83907609, 88.72558594], 79 | [25.68113734, 97.3828125], 80 | [21.24842224, 105.77636719], 81 | ] 82 | ).add_to(m) 83 | 84 | 85 | folium.plugins.PolyLineTextPath(line_to_new_delhi, "To New Delhi", offset=-5).add_to(m) 86 | 87 | 88 | folium.plugins.PolyLineTextPath(line_to_hanoi, "To Hanoi", offset=-5).add_to(m) 89 | 90 | m 91 | ``` 92 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/scroll_zoom_toggler.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | import folium.plugins 7 | ``` 8 | 9 | ## ScrollZoomToggler 10 | 11 | Add a button to enable/disable zoom scrolling. 12 | 13 | ```{code-cell} ipython3 14 | m = folium.Map([45, 3], zoom_start=4) 15 | 16 | folium.plugins.ScrollZoomToggler().add_to(m) 17 | 18 | m 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/semi_circle.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | import folium.plugins 7 | ``` 8 | 9 | ## SemiCircle 10 | 11 | This can be used to display a semicircle or sector on a map. Whilst called SemiCircle it is not limited to 180 degree angles and can be used to display a sector of any angle. 12 | 13 | The semicircle is defined with a location (the central point, if it was a full circle), a radius and will either have a direction and an arc **or** a start angle and a stop angle. 14 | 15 | ```{code-cell} ipython3 16 | m = folium.Map([45, 3], zoom_start=5) 17 | 18 | folium.plugins.SemiCircle( 19 | (45, 3), 20 | radius=400000, 21 | start_angle=50, 22 | stop_angle=200, 23 | color="green", 24 | fill_color="green", 25 | opacity=0, 26 | popup="start angle - 50 degrees, stop angle - 200 degrees", 27 | ).add_to(m) 28 | 29 | folium.plugins.SemiCircle( 30 | (46.5, 9.5), 31 | radius=200000, 32 | direction=360, 33 | arc=90, 34 | color="red", 35 | fill_color="red", 36 | opacity=0, 37 | popup="Direction - 0 degrees, arc 90 degrees", 38 | ).add_to(m) 39 | 40 | m 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/side_by_side_layers.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | import folium.plugins 7 | ``` 8 | 9 | ## SideBySideLayers 10 | 11 | This plugin can be used to compare two layers on the same map using a vertical separator managed by the user. 12 | 13 | The SideBySideLayers class must be instantiated with left and right layers, then added to the map along with layers. 14 | 15 | If you want to add a layer control to your map, you can permanently enable the tile layers used for this plugin with `control=False`. 16 | 17 | ```{code-cell} ipython3 18 | m = folium.Map(location=(30, 20), zoom_start=4) 19 | 20 | layer_right = folium.TileLayer('openstreetmap') 21 | layer_left = folium.TileLayer('cartodbpositron') 22 | 23 | sbs = folium.plugins.SideBySideLayers(layer_left=layer_left, layer_right=layer_right) 24 | 25 | layer_left.add_to(m) 26 | layer_right.add_to(m) 27 | sbs.add_to(m) 28 | 29 | m 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/tag_filter_button.md: -------------------------------------------------------------------------------- 1 | # TagFilterButton 2 | 3 | ```{code-cell} ipython3 4 | import os 5 | import folium 6 | ``` 7 | 8 | ```{code-cell} ipython3 9 | import numpy as np 10 | import random 11 | 12 | # Generate base data 13 | data = (np.random.normal(size=(100, 2)) * np.array([[1, 1]]) + 14 | np.array([[48, 5]])) 15 | # Generate the data to segment by (levels of another pandas column in practical usage) 16 | categories = ['category{}'.format(i+1) for i in range(5)] 17 | category_column = [random.choice(categories) for i in range(len(data))] 18 | ``` 19 | 20 | Create markers, and add tags to each marker. There can be multiple tags per marker, but in this example we add just one. 21 | 22 | Then, create the `TagFilterButton` object and let it know which tags you want to filter on. 23 | 24 | ```{code-cell} ipython3 25 | from folium.plugins import TagFilterButton 26 | 27 | # Create map and add the data with additional parameter tags as the segmentation 28 | m = folium.Map([48., 5.], zoom_start=7) 29 | for i, latlng in enumerate(data): 30 | category = category_column[i] 31 | folium.Marker( 32 | tuple(latlng), 33 | tags=[category] 34 | ).add_to(m) 35 | 36 | TagFilterButton(categories).add_to(m) 37 | 38 | m 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/user_guide/plugins/terminator.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | import folium.plugins 7 | ``` 8 | 9 | ## Terminator 10 | 11 | This plugin overlays the current day and night regions on the map. It updates 12 | continuously. Zoom in in the example below to see the regions move. 13 | 14 | ```{code-cell} ipython3 15 | m = folium.Map([45, 3], zoom_start=1) 16 | 17 | folium.plugins.Terminator().add_to(m) 18 | 19 | m 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/user_guide/raster_layers.rst: -------------------------------------------------------------------------------- 1 | Raster layers 2 | -------------- 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | raster_layers/tiles 8 | raster_layers/image_overlay 9 | raster_layers/video_overlay 10 | raster_layers/wms_tile_layer 11 | -------------------------------------------------------------------------------- /docs/user_guide/raster_layers/tiles.md: -------------------------------------------------------------------------------- 1 | ## Tiles 2 | 3 | ### Built-in tilesets 4 | 5 | ```{code-cell} ipython3 6 | import folium 7 | 8 | 9 | lon, lat = -38.625, -12.875 10 | 11 | zoom_start = 8 12 | ``` 13 | 14 | ```{code-cell} ipython3 15 | folium.Map(location=[lat, lon], tiles="OpenStreetMap", zoom_start=zoom_start) 16 | ``` 17 | 18 | ```{code-cell} ipython3 19 | folium.Map(location=[lat, lon], tiles="Cartodb Positron", zoom_start=zoom_start) 20 | ``` 21 | 22 | ```{code-cell} ipython3 23 | folium.Map(location=[lat, lon], tiles="Cartodb dark_matter", zoom_start=zoom_start) 24 | ``` 25 | 26 | 27 | ### Custom tiles 28 | 29 | You can also provide a url template to load tiles from, for example if you use a paid API. 30 | You also have to provide an attribution in that case. For information how that 31 | url template should look like see the Leaflet documentation: 32 | https://leafletjs.com/reference.html#tilelayer. 33 | 34 | Below is an example, note the literal `{z}`, `{x}` and `{y}` in the url template. 35 | 36 | ```{code-cell} ipython3 37 | attr = ( 38 | '© OpenStreetMap ' 39 | 'contributors, © CartoDB' 40 | ) 41 | tiles = "https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png" 42 | 43 | folium.Map(location=[lat, lon], tiles=tiles, attr=attr, zoom_start=zoom_start) 44 | ``` 45 | 46 | ### Other tilesets 47 | 48 | For a list of many more tile providers go to https://leaflet-extras.github.io/leaflet-providers/preview/. 49 | 50 | You can also use the xyzservices package: https://github.com/geopandas/xyzservices. 51 | -------------------------------------------------------------------------------- /docs/user_guide/raster_layers/video_overlay.md: -------------------------------------------------------------------------------- 1 | # VideoOverlay 2 | 3 | ```{code-cell} ipython3 4 | import folium 5 | 6 | 7 | m = folium.Map(location=[22.5, -115], zoom_start=4) 8 | 9 | video = folium.raster_layers.VideoOverlay( 10 | video_url="https://www.mapbox.com/bites/00188/patricia_nasa.webm", 11 | bounds=[[32, -130], [13, -100]], 12 | opacity=0.65, 13 | attr="Video from patricia_nasa", 14 | autoplay=True, 15 | loop=False, 16 | ) 17 | 18 | video.add_to(m) 19 | 20 | m 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/user_guide/raster_layers/wms_tile_layer.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | ``` 7 | 8 | # WmsTileLayer 9 | 10 | ```{code-cell} ipython3 11 | m = folium.Map(location=[41, -70], zoom_start=5, tiles="cartodb positron") 12 | 13 | folium.WmsTileLayer( 14 | url="https://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi", 15 | name="test", 16 | fmt="image/png", 17 | layers="nexrad-n0r-900913", 18 | attr=u"Weather data © 2012 IEM Nexrad", 19 | transparent=True, 20 | overlay=True, 21 | control=True, 22 | ).add_to(m) 23 | 24 | folium.LayerControl().add_to(m) 25 | 26 | m 27 | ``` 28 | -------------------------------------------------------------------------------- /docs/user_guide/ui_elements.rst: -------------------------------------------------------------------------------- 1 | UI elements 2 | -------------- 3 | 4 | .. toctree:: 5 | :maxdepth: 1 6 | 7 | 8 | ui_elements/layer_control 9 | ui_elements/popups 10 | ui_elements/icons 11 | -------------------------------------------------------------------------------- /docs/user_guide/ui_elements/icons.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | ``` 7 | 8 | # Icons 9 | 10 | ## Rotate icons 11 | 12 | ```{code-cell} ipython3 13 | m = folium.Map(location=[41, -71], zoom_start=4) 14 | 15 | kw = {"prefix": "fa", "color": "green", "icon": "arrow-up"} 16 | 17 | angle = 180 18 | icon = folium.Icon(angle=angle, **kw) 19 | folium.Marker(location=[41, -72], icon=icon, tooltip=str(angle)).add_to(m) 20 | 21 | angle = 45 22 | icon = folium.Icon(angle=angle, **kw) 23 | folium.Marker(location=[41, -75], icon=icon, tooltip=str(angle)).add_to(m) 24 | 25 | angle = 90 26 | icon = folium.Icon(angle=angle, **kw) 27 | folium.Marker([41, -78], icon=icon, tooltip=str(angle)).add_to(m) 28 | 29 | m 30 | ``` 31 | 32 | ## Custom icon 33 | 34 | ```{code-cell} ipython3 35 | m = folium.Map(location=[45.3288, -121.6625], zoom_start=12) 36 | 37 | url = "https://leafletjs.com/examples/custom-icons/{}".format 38 | icon_image = url("leaf-red.png") 39 | shadow_image = url("leaf-shadow.png") 40 | 41 | icon = folium.CustomIcon( 42 | icon_image, 43 | icon_size=(38, 95), 44 | icon_anchor=(22, 94), 45 | shadow_image=shadow_image, 46 | shadow_size=(50, 64), 47 | shadow_anchor=(4, 62), 48 | popup_anchor=(-3, -76), 49 | ) 50 | 51 | folium.Marker( 52 | location=[45.3288, -121.6625], icon=icon, popup="Mt. Hood Meadows" 53 | ).add_to(m) 54 | 55 | m 56 | ``` 57 | -------------------------------------------------------------------------------- /docs/user_guide/ui_elements/layer_control.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | ``` 7 | 8 | ## LayerControl 9 | 10 | Add a control to the map to show or hide layers. 11 | 12 | ```{code-cell} ipython3 13 | m = folium.Map(tiles=None) 14 | 15 | folium.TileLayer("OpenStreetMap", overlay=True).add_to(m) 16 | 17 | folium.LayerControl().add_to(m) 18 | 19 | m 20 | ``` 21 | 22 | ### Common layer arguments 23 | 24 | Every layer element in Folium has a couple common arguments: 25 | 26 | - `name`: how the layer will be named in the layer control. 27 | - `overlay`: True if the layer is an overlay, False if the layer is a base layer. 28 | - base layer: only one can be active at a time. Tile layers are base layers by default. 29 | - overlay: multiple can be active at the same time. `FeatureGroup`s and most non-tile layers are overlays by default. 30 | - `control`: Whether the layer can be controlled in the layer control. 31 | - `show`: Whether the layer will be shown when opening the map. 32 | 33 | Next we'll give some examples using a `FeatureGroup`. 34 | 35 | ### Remove from control 36 | 37 | ```{code-cell} ipython3 38 | m = folium.Map() 39 | 40 | fg = folium.FeatureGroup(name="Icon collection", control=False).add_to(m) 41 | folium.Marker(location=(0, 0)).add_to(fg) 42 | 43 | folium.LayerControl().add_to(m) 44 | 45 | m 46 | ``` 47 | 48 | ### Show manually 49 | 50 | ```{code-cell} ipython3 51 | m = folium.Map() 52 | 53 | fg = folium.FeatureGroup(name="Icon collection", show=False).add_to(m) 54 | folium.Marker(location=(0, 0)).add_to(fg) 55 | 56 | folium.LayerControl().add_to(m) 57 | 58 | m 59 | ``` 60 | -------------------------------------------------------------------------------- /docs/user_guide/vector_layers.rst: -------------------------------------------------------------------------------- 1 | Vector layers 2 | -------------- 3 | 4 | .. toctree:: 5 | :maxdepth: 1 6 | 7 | vector_layers/circle_and_circle_marker 8 | vector_layers/polyline 9 | vector_layers/rectangle 10 | vector_layers/polygon 11 | vector_layers/colorline 12 | -------------------------------------------------------------------------------- /docs/user_guide/vector_layers/circle_and_circle_marker.md: -------------------------------------------------------------------------------- 1 | ## Circle and CircleMarker 2 | 3 | `CircleMarker` has a radius specified in pixels, while `Circle` is specified in meters. 4 | That means a `CircleMarker` will not change size on your screen when you zoom, 5 | while `Circle` will have a fixed position on the map. 6 | 7 | ```{code-cell} ipython3 8 | import folium 9 | 10 | m = folium.Map(location=[-27.5717, -48.6256], zoom_start=9) 11 | 12 | radius = 50 13 | folium.CircleMarker( 14 | location=[-27.55, -48.8], 15 | radius=radius, 16 | color="cornflowerblue", 17 | stroke=False, 18 | fill=True, 19 | fill_opacity=0.6, 20 | opacity=1, 21 | popup="{} pixels".format(radius), 22 | tooltip="I am in pixels", 23 | ).add_to(m) 24 | 25 | radius = 25 26 | folium.CircleMarker( 27 | location=[-27.35, -48.8], 28 | radius=radius, 29 | color="black", 30 | weight=3, 31 | fill=False, 32 | fill_opacity=0.6, 33 | opacity=1, 34 | ).add_to(m) 35 | 36 | radius = 10000 37 | folium.Circle( 38 | location=[-27.551667, -48.478889], 39 | radius=radius, 40 | color="black", 41 | weight=1, 42 | fill_opacity=0.6, 43 | opacity=1, 44 | fill_color="green", 45 | fill=False, # gets overridden by fill_color 46 | popup="{} meters".format(radius), 47 | tooltip="I am in meters", 48 | ).add_to(m) 49 | 50 | m 51 | ``` 52 | -------------------------------------------------------------------------------- /docs/user_guide/vector_layers/colorline.md: -------------------------------------------------------------------------------- 1 | ### ColorLine 2 | 3 | ```{code-cell} ipython3 4 | import numpy as np 5 | 6 | x = np.linspace(0, 2 * np.pi, 300) 7 | 8 | lats = 20 * np.cos(x) 9 | lons = 20 * np.sin(x) 10 | colors = np.sin(5 * x) 11 | ``` 12 | 13 | ```{code-cell} ipython3 14 | import folium 15 | 16 | m = folium.Map([0, 0], zoom_start=3) 17 | 18 | color_line = folium.ColorLine( 19 | positions=list(zip(lats, lons)), 20 | colors=colors, 21 | colormap=["y", "orange", "r"], 22 | weight=10, 23 | ).add_to(m) 24 | 25 | m 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/user_guide/vector_layers/polygon.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | ``` 7 | 8 | ## Polygon 9 | 10 | ```{code-cell} ipython3 11 | m = folium.Map(location=[35.67, 139.78], zoom_start=13) 12 | 13 | locations = [ 14 | [35.6762, 139.7795], 15 | [35.6718, 139.7831], 16 | [35.6767, 139.7868], 17 | [35.6795, 139.7824], 18 | [35.6787, 139.7791], 19 | ] 20 | 21 | folium.Polygon( 22 | locations=locations, 23 | color="blue", 24 | weight=6, 25 | fill_color="red", 26 | fill_opacity=0.5, 27 | fill=True, 28 | popup="Tokyo, Japan", 29 | tooltip="Click me!", 30 | ).add_to(m) 31 | 32 | m 33 | ``` 34 | 35 | ```{code-cell} ipython3 36 | locations = [ 37 | [ 38 | [7.577794326946673, 8.998503901433935], 39 | [7.577851434795945, 8.998572430673164], 40 | [7.577988491475764, 8.998652380403087], 41 | [7.578105560723088, 8.998426807051544], 42 | [7.577891409660878, 8.998289750371725], 43 | [7.577794326946673, 8.998503901433935], 44 | ], 45 | [ 46 | [7.578139824893071, 8.999291979141560], 47 | [7.578359687549607, 8.999414759083890], 48 | [7.578456769364435, 8.999266281014116], 49 | [7.578471046101925, 8.999197181604700], 50 | [7.578247331649095, 8.999094883721964], 51 | [7.578139824893071, 8.99929197914156], 52 | ], 53 | [ 54 | [7.577851730672876, 8.997811268775080], 55 | [7.578012579816743, 8.997460464828633], 56 | [7.577798113991832, 8.997311104523930], 57 | [7.577667902951418, 8.997663440915119], 58 | [7.577851730672876, 8.997811268775080], 59 | ], 60 | [ 61 | [7.578562417221803, 8.999551816663029], 62 | [7.578688052511666, 8.999654609172921], 63 | [7.578813688700849, 8.999443313458185], 64 | [7.578670920426703, 8.999369073523950], 65 | [7.578562417221803, 8.999551816663029], 66 | ], 67 | [ 68 | [7.577865711533433, 8.998252059784761], 69 | [7.577989601239152, 8.998002756022402], 70 | [7.577648754586391, 8.997784460884190], 71 | [7.577545911714481, 8.998069316645683], 72 | [7.577865711533433, 8.998252059784761], 73 | ], 74 | ] 75 | 76 | m = folium.Map(location=[7.577798113991832, 8.997311104523930], zoom_start=16) 77 | 78 | folium.Polygon( 79 | locations=locations, 80 | smooth_factor=2, 81 | color="crimson", 82 | no_clip=True, 83 | tooltip="Hi there!", 84 | ).add_to(m) 85 | 86 | m 87 | ``` 88 | -------------------------------------------------------------------------------- /docs/user_guide/vector_layers/rectangle.md: -------------------------------------------------------------------------------- 1 | ```{code-cell} ipython3 2 | --- 3 | nbsphinx: hidden 4 | --- 5 | import folium 6 | ``` 7 | 8 | ## Rectangle 9 | 10 | ```{code-cell} ipython3 11 | m = folium.Map(location=[35.685, 139.76], zoom_start=15) 12 | 13 | kw = { 14 | "color": "blue", 15 | "line_cap": "round", 16 | "fill": True, 17 | "fill_color": "red", 18 | "weight": 5, 19 | "popup": "Tokyo, Japan", 20 | "tooltip": "Click me!", 21 | } 22 | 23 | folium.Rectangle( 24 | bounds=[[35.681, 139.766], [35.691, 139.776]], 25 | line_join="round", 26 | dash_array="5, 5", 27 | **kw, 28 | ).add_to(m) 29 | 30 | dx = 0.012 31 | folium.Rectangle( 32 | bounds=[[35.681, 139.766 - dx], [35.691, 139.776 - dx]], 33 | line_join="mitter", 34 | dash_array="5, 10", 35 | **kw, 36 | ).add_to(m) 37 | 38 | folium.Rectangle( 39 | bounds=[[35.681, 139.766 - 2 * dx], [35.691, 139.7762 - 2 * dx]], 40 | line_join="bevel", 41 | dash_array="15, 10, 5, 10, 15", 42 | **kw, 43 | ).add_to(m) 44 | 45 | m 46 | ``` 47 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: examples 2 | channels: 3 | - conda-forge 4 | - defaults 5 | dependencies: 6 | - altair 7 | - branca 8 | - cartopy 9 | - fiona 10 | - folium 11 | - geographiclib 12 | - geopandas 13 | - gpxpy 14 | - ipython 15 | - matplotlib 16 | - mplleaflet 17 | - numpy 18 | - owslib 19 | - pandas 20 | - scipy 21 | - shapely 22 | - vincent 23 | -------------------------------------------------------------------------------- /examples/CheckZorder.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "We've updated our documentation and removed this notebook.\n", 7 | "You can find the current documentation at https://python-visualization.github.io/folium/latest/." 8 | ], 9 | "metadata": { 10 | "collapsed": false, 11 | "pycharm": { 12 | "name": "#%% md\n" 13 | } 14 | } 15 | } 16 | ], 17 | "metadata": { 18 | "kernelspec": { 19 | "display_name": "Python 3 (ipykernel)", 20 | "language": "python", 21 | "name": "python3" 22 | }, 23 | "language_info": { 24 | "codemirror_mode": { 25 | "name": "ipython", 26 | "version": 3 27 | }, 28 | "file_extension": ".py", 29 | "mimetype": "text/x-python", 30 | "name": "python", 31 | "nbconvert_exporter": "python", 32 | "pygments_lexer": "ipython3", 33 | "version": "3.9.7" 34 | } 35 | }, 36 | "nbformat": 4, 37 | "nbformat_minor": 1 38 | } 39 | -------------------------------------------------------------------------------- /examples/Choropleth with Jenks natural breaks optimization.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "We've updated our documentation. You can find the new version of this notebook here:\n", 7 | "https://python-visualization.github.io/folium/latest/advanced_guide/choropleth%20with%20Jenks%20natural%20breaks%20optimization.html" 8 | ], 9 | "metadata": { 10 | "collapsed": false 11 | } 12 | } 13 | ], 14 | "metadata": { 15 | "kernelspec": { 16 | "display_name": "Python 3 (ipykernel)", 17 | "language": "python", 18 | "name": "python3" 19 | }, 20 | "language_info": { 21 | "codemirror_mode": { 22 | "name": "ipython", 23 | "version": 3 24 | }, 25 | "file_extension": ".py", 26 | "mimetype": "text/x-python", 27 | "name": "python", 28 | "nbconvert_exporter": "python", 29 | "pygments_lexer": "ipython3", 30 | "version": "3.9.13" 31 | } 32 | }, 33 | "nbformat": 4, 34 | "nbformat_minor": 5 35 | } 36 | -------------------------------------------------------------------------------- /examples/ClickEvents.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "6b3009b4", 6 | "metadata": { 7 | "pycharm": { 8 | "name": "#%% md\n" 9 | } 10 | }, 11 | "source": [ 12 | "We've updated our documentation. You can find the new version of this notebook here:\n", 13 | "https://python-visualization.github.io/folium/latest/user_guide/features/click_related_classes.html" 14 | ] 15 | } 16 | ], 17 | "metadata": { 18 | "kernelspec": { 19 | "display_name": "Python 3 (ipykernel)", 20 | "language": "python", 21 | "name": "python3" 22 | }, 23 | "language_info": { 24 | "codemirror_mode": { 25 | "name": "ipython", 26 | "version": 3 27 | }, 28 | "file_extension": ".py", 29 | "mimetype": "text/x-python", 30 | "name": "python", 31 | "nbconvert_exporter": "python", 32 | "pygments_lexer": "ipython3", 33 | "version": "3.9.13" 34 | } 35 | }, 36 | "nbformat": 4, 37 | "nbformat_minor": 5 38 | } 39 | -------------------------------------------------------------------------------- /examples/Colormaps.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "We've updated our documentation. You can find the new version of this notebook here:\n", 7 | "https://python-visualization.github.io/folium/latest/advanced_guide/colormaps.html" 8 | ], 9 | "metadata": { 10 | "collapsed": false 11 | } 12 | } 13 | ], 14 | "metadata": { 15 | "kernelspec": { 16 | "display_name": "Python 3 (ipykernel)", 17 | "language": "python", 18 | "name": "python3" 19 | }, 20 | "language_info": { 21 | "codemirror_mode": { 22 | "name": "ipython", 23 | "version": 3 24 | }, 25 | "file_extension": ".py", 26 | "mimetype": "text/x-python", 27 | "name": "python", 28 | "nbconvert_exporter": "python", 29 | "pygments_lexer": "ipython3", 30 | "version": "3.9.7" 31 | } 32 | }, 33 | "nbformat": 4, 34 | "nbformat_minor": 4 35 | } 36 | -------------------------------------------------------------------------------- /examples/ContinuousWorld.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "We've updated our documentation. You can find the new version of this notebook here:\n", 7 | "https://python-visualization.github.io/folium/latest/advanced_guide/world_copy.html" 8 | ], 9 | "metadata": { 10 | "collapsed": false 11 | } 12 | } 13 | ], 14 | "metadata": { 15 | "kernelspec": { 16 | "display_name": "Python 3", 17 | "language": "python", 18 | "name": "python3" 19 | }, 20 | "language_info": { 21 | "codemirror_mode": { 22 | "name": "ipython", 23 | "version": 3 24 | }, 25 | "file_extension": ".py", 26 | "mimetype": "text/x-python", 27 | "name": "python", 28 | "nbconvert_exporter": "python", 29 | "pygments_lexer": "ipython3", 30 | "version": "3.9.0" 31 | } 32 | }, 33 | "nbformat": 4, 34 | "nbformat_minor": 1 35 | } 36 | -------------------------------------------------------------------------------- /examples/ControlScale.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "We've updated our documentation. You can find the new version of this notebook here:\n", 7 | "https://python-visualization.github.io/folium/latest/user_guide/map.html#Scale" 8 | ], 9 | "metadata": { 10 | "collapsed": false 11 | } 12 | } 13 | ], 14 | "metadata": { 15 | "kernelspec": { 16 | "display_name": "Python 3", 17 | "language": "python", 18 | "name": "python3" 19 | }, 20 | "language_info": { 21 | "codemirror_mode": { 22 | "name": "ipython", 23 | "version": 3 24 | }, 25 | "file_extension": ".py", 26 | "mimetype": "text/x-python", 27 | "name": "python", 28 | "nbconvert_exporter": "python", 29 | "pygments_lexer": "ipython3", 30 | "version": "3.9.0" 31 | } 32 | }, 33 | "nbformat": 4, 34 | "nbformat_minor": 1 35 | } 36 | -------------------------------------------------------------------------------- /examples/CustomIcon.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/ui_elements/icons.html#Custom-icon" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.0" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 1 37 | } 38 | -------------------------------------------------------------------------------- /examples/CustomPanes.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "We've updated our documentation. You can find the new version of this notebook here:\n", 7 | "https://python-visualization.github.io/folium/latest/advanced_guide/custom_panes.html" 8 | ], 9 | "metadata": { 10 | "collapsed": false 11 | } 12 | } 13 | ], 14 | "metadata": { 15 | "kernelspec": { 16 | "display_name": "Python 3 (ipykernel)", 17 | "language": "python", 18 | "name": "python3" 19 | }, 20 | "language_info": { 21 | "codemirror_mode": { 22 | "name": "ipython", 23 | "version": 3 24 | }, 25 | "file_extension": ".py", 26 | "mimetype": "text/x-python", 27 | "name": "python", 28 | "nbconvert_exporter": "python", 29 | "pygments_lexer": "ipython3", 30 | "version": "3.9.7" 31 | } 32 | }, 33 | "nbformat": 4, 34 | "nbformat_minor": 2 35 | } 36 | -------------------------------------------------------------------------------- /examples/FeatureGroup.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "We've updated our documentation. You can find the new version of this notebook here:\n", 7 | "https://python-visualization.github.io/folium/latest/getting_started.html#Grouping-and-controlling" 8 | ], 9 | "metadata": { 10 | "collapsed": false 11 | } 12 | } 13 | ], 14 | "metadata": { 15 | "kernelspec": { 16 | "display_name": "Python 3", 17 | "language": "python", 18 | "name": "python3" 19 | }, 20 | "language_info": { 21 | "codemirror_mode": { 22 | "name": "ipython", 23 | "version": 3 24 | }, 25 | "file_extension": ".py", 26 | "mimetype": "text/x-python", 27 | "name": "python", 28 | "nbconvert_exporter": "python", 29 | "pygments_lexer": "ipython3", 30 | "version": "3.9.0" 31 | } 32 | }, 33 | "nbformat": 4, 34 | "nbformat_minor": 1 35 | } 36 | -------------------------------------------------------------------------------- /examples/Features.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3 (ipykernel)", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.16" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 1 37 | } 38 | -------------------------------------------------------------------------------- /examples/FitOverlays.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "14a617e3", 6 | "metadata": { 7 | "pycharm": { 8 | "name": "#%% md\n" 9 | } 10 | }, 11 | "source": [ 12 | "We've updated our documentation. You can find the new version of this notebook here:\n", 13 | "https://python-visualization.github.io/folium/latest/user_guide/features/fit_overlays.html" 14 | ] 15 | } 16 | ], 17 | "metadata": { 18 | "kernelspec": { 19 | "display_name": "Python 3 (ipykernel)", 20 | "language": "python", 21 | "name": "python3" 22 | }, 23 | "language_info": { 24 | "codemirror_mode": { 25 | "name": "ipython", 26 | "version": 3 27 | }, 28 | "file_extension": ".py", 29 | "mimetype": "text/x-python", 30 | "name": "python", 31 | "nbconvert_exporter": "python", 32 | "pygments_lexer": "ipython3", 33 | "version": "3.9.13" 34 | } 35 | }, 36 | "nbformat": 4, 37 | "nbformat_minor": 5 38 | } 39 | -------------------------------------------------------------------------------- /examples/FloatImage.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "We've updated our documentation. You can find the new version of this notebook here:\n", 7 | "https://python-visualization.github.io/folium/latest/user_guide/plugins/float_image.html" 8 | ], 9 | "metadata": { 10 | "collapsed": false 11 | } 12 | } 13 | ], 14 | "metadata": { 15 | "kernelspec": { 16 | "display_name": "Python 3 (ipykernel)", 17 | "language": "python", 18 | "name": "python3" 19 | }, 20 | "language_info": { 21 | "codemirror_mode": { 22 | "name": "ipython", 23 | "version": 3 24 | }, 25 | "file_extension": ".py", 26 | "mimetype": "text/x-python", 27 | "name": "python", 28 | "nbconvert_exporter": "python", 29 | "pygments_lexer": "ipython3", 30 | "version": "3.10.1" 31 | } 32 | }, 33 | "nbformat": 4, 34 | "nbformat_minor": 1 35 | } 36 | -------------------------------------------------------------------------------- /examples/GeoJSONMarker.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/geojson/geojson_marker.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.7.2" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 4 37 | } 38 | -------------------------------------------------------------------------------- /examples/GeoJSONWithoutTitles.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/advanced_guide/custom_tiles.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.0" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 1 37 | } 38 | -------------------------------------------------------------------------------- /examples/GeoJSON_and_choropleth.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "We've updated our documentation. You can find the new version of this notebook here:\n", 7 | "https://python-visualization.github.io/folium/latest/user_guide/geojson.html" 8 | ], 9 | "metadata": { 10 | "collapsed": false 11 | } 12 | } 13 | ], 14 | "metadata": { 15 | "kernelspec": { 16 | "display_name": "Python 3 (ipykernel)", 17 | "language": "python", 18 | "name": "python3" 19 | }, 20 | "language_info": { 21 | "codemirror_mode": { 22 | "name": "ipython", 23 | "version": 3 24 | }, 25 | "file_extension": ".py", 26 | "mimetype": "text/x-python", 27 | "name": "python", 28 | "nbconvert_exporter": "python", 29 | "pygments_lexer": "ipython3", 30 | "version": "3.9.7" 31 | }, 32 | "toc": { 33 | "base_numbering": 1, 34 | "nav_menu": {}, 35 | "number_sections": true, 36 | "sideBar": true, 37 | "skip_h1_title": false, 38 | "title_cell": "Table of Contents", 39 | "title_sidebar": "Contents", 40 | "toc_cell": false, 41 | "toc_position": {}, 42 | "toc_section_display": true, 43 | "toc_window_display": false 44 | } 45 | }, 46 | "nbformat": 4, 47 | "nbformat_minor": 1 48 | } 49 | -------------------------------------------------------------------------------- /examples/GeoJsonPopupAndTooltip.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/geojson/geojson_popup_and_tooltip.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3 (ipykernel)", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.13" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 4 37 | } 38 | -------------------------------------------------------------------------------- /examples/GeodedeticImageOverlay.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "We've updated our documentation. You can find the new version of this notebook here:\n", 7 | "https://python-visualization.github.io/folium/latest/advanced_guide/geodedetic_image_overlay.html" 8 | ], 9 | "metadata": { 10 | "collapsed": false 11 | } 12 | } 13 | ], 14 | "metadata": { 15 | "kernelspec": { 16 | "display_name": "Python 3", 17 | "language": "python", 18 | "name": "python3" 19 | }, 20 | "language_info": { 21 | "codemirror_mode": { 22 | "name": "ipython", 23 | "version": 3 24 | }, 25 | "file_extension": ".py", 26 | "mimetype": "text/x-python", 27 | "name": "python", 28 | "nbconvert_exporter": "python", 29 | "pygments_lexer": "ipython3", 30 | "version": "3.9.0" 31 | } 32 | }, 33 | "nbformat": 4, 34 | "nbformat_minor": 1 35 | } 36 | -------------------------------------------------------------------------------- /examples/Geopandas_and_geo_interface.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/geojson/geopandas_and_geo_interface.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3 (ipykernel)", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.7" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 1 37 | } 38 | -------------------------------------------------------------------------------- /examples/HeatMapWithTime.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "We’ve updated our documentation and removed this notebook. \n", 7 | "You can find the current documentation at https://python-visualization.github.io/folium/latest/user_guide/plugins/heatmap_with_time.html." 8 | ], 9 | "metadata": { 10 | "collapsed": false 11 | } 12 | } 13 | ], 14 | "metadata": { 15 | "anaconda-cloud": {}, 16 | "kernelspec": { 17 | "display_name": "Python 3 (ipykernel)", 18 | "language": "python", 19 | "name": "python3" 20 | }, 21 | "language_info": { 22 | "codemirror_mode": { 23 | "name": "ipython", 24 | "version": 3 25 | }, 26 | "file_extension": ".py", 27 | "mimetype": "text/x-python", 28 | "name": "python", 29 | "nbconvert_exporter": "python", 30 | "pygments_lexer": "ipython3", 31 | "version": "3.11.6" 32 | } 33 | }, 34 | "nbformat": 4, 35 | "nbformat_minor": 1 36 | } 37 | -------------------------------------------------------------------------------- /examples/Heatmap.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/plugins/heatmap.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.0" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 1 37 | } 38 | -------------------------------------------------------------------------------- /examples/Highlight_Function.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "We've updated our documentation. You can find the new version of this notebook here:\n", 7 | "https://python-visualization.github.io/folium/latest/user_guide/geojson/geojson.html#Highlight-function" 8 | ], 9 | "metadata": { 10 | "collapsed": false 11 | } 12 | } 13 | ], 14 | "metadata": { 15 | "kernelspec": { 16 | "display_name": "Python 3", 17 | "language": "python", 18 | "name": "python3" 19 | }, 20 | "language_info": { 21 | "codemirror_mode": { 22 | "name": "ipython", 23 | "version": 3 24 | }, 25 | "file_extension": ".py", 26 | "mimetype": "text/x-python", 27 | "name": "python", 28 | "nbconvert_exporter": "python", 29 | "pygments_lexer": "ipython3", 30 | "version": "3.9.0" 31 | } 32 | }, 33 | "nbformat": 4, 34 | "nbformat_minor": 2 35 | } 36 | -------------------------------------------------------------------------------- /examples/ImageOverlay.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/raster_layers/image_overlay.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.0" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 1 37 | } 38 | -------------------------------------------------------------------------------- /examples/MarkerCluster.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/plugins/marker_cluster.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.0" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 1 37 | } 38 | -------------------------------------------------------------------------------- /examples/MinMaxLimits.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "We've updated our documentation. You can find the new version of this notebook here:\n", 7 | "https://python-visualization.github.io/folium/latest/user_guide/map.html#Limits" 8 | ], 9 | "metadata": { 10 | "collapsed": false 11 | } 12 | } 13 | ], 14 | "metadata": { 15 | "kernelspec": { 16 | "display_name": "Python 3", 17 | "language": "python", 18 | "name": "python3" 19 | }, 20 | "language_info": { 21 | "codemirror_mode": { 22 | "name": "ipython", 23 | "version": 3 24 | }, 25 | "file_extension": ".py", 26 | "mimetype": "text/x-python", 27 | "name": "python", 28 | "nbconvert_exporter": "python", 29 | "pygments_lexer": "ipython3", 30 | "version": "3.9.0" 31 | } 32 | }, 33 | "nbformat": 4, 34 | "nbformat_minor": 1 35 | } 36 | -------------------------------------------------------------------------------- /examples/MiniMap.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/plugins/mini_map.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.0" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 2 37 | } 38 | -------------------------------------------------------------------------------- /examples/Minicharts.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/advanced_guide/piechart_icons.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.0" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 2 37 | } 38 | -------------------------------------------------------------------------------- /examples/Plugins.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "We've updated our documentation. You can find the new version of this notebook here:\n", 7 | "https://python-visualization.github.io/folium/latest/user_guide/plugins.html" 8 | ], 9 | "metadata": { 10 | "collapsed": false 11 | } 12 | } 13 | ], 14 | "metadata": { 15 | "kernelspec": { 16 | "display_name": "Python 3 (ipykernel)", 17 | "language": "python", 18 | "name": "python3" 19 | }, 20 | "language_info": { 21 | "codemirror_mode": { 22 | "name": "ipython", 23 | "version": 3 24 | }, 25 | "file_extension": ".py", 26 | "mimetype": "text/x-python", 27 | "name": "python", 28 | "nbconvert_exporter": "python", 29 | "pygments_lexer": "ipython3", 30 | "version": "3.9.13" 31 | } 32 | }, 33 | "nbformat": 4, 34 | "nbformat_minor": 2 35 | } 36 | -------------------------------------------------------------------------------- /examples/PolyLineTextPath_AntPath.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/plugins/polyline_textpath_and_antpath.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.0" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 1 37 | } 38 | -------------------------------------------------------------------------------- /examples/Polygons_from_list_of_points.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "We've updated our documentation. You can find the new version of this notebook here:\n", 7 | "https://python-visualization.github.io/folium/latest/advanced_guide/polygons_from_list_of_points.html" 8 | ], 9 | "metadata": { 10 | "collapsed": false, 11 | "pycharm": { 12 | "name": "#%% md\n" 13 | } 14 | } 15 | } 16 | ], 17 | "metadata": { 18 | "kernelspec": { 19 | "display_name": "Python 3", 20 | "language": "python", 21 | "name": "python3" 22 | }, 23 | "language_info": { 24 | "codemirror_mode": { 25 | "name": "ipython", 26 | "version": 3 27 | }, 28 | "file_extension": ".py", 29 | "mimetype": "text/x-python", 30 | "name": "python", 31 | "nbconvert_exporter": "python", 32 | "pygments_lexer": "ipython3", 33 | "version": "3.9.0" 34 | } 35 | }, 36 | "nbformat": 4, 37 | "nbformat_minor": 2 38 | } 39 | -------------------------------------------------------------------------------- /examples/Popups.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/ui_elements/popups.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.7.10" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 1 37 | } 38 | -------------------------------------------------------------------------------- /examples/Quickstart.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "We've updated our documentation. You can find the new version of this notebook here:\n", 7 | "https://python-visualization.github.io/folium/latest/getting_started.html" 8 | ], 9 | "metadata": { 10 | "collapsed": false 11 | } 12 | } 13 | ], 14 | "metadata": { 15 | "kernelspec": { 16 | "display_name": "Python 3 (ipykernel)", 17 | "language": "python", 18 | "name": "python3" 19 | }, 20 | "language_info": { 21 | "codemirror_mode": { 22 | "name": "ipython", 23 | "version": 3 24 | }, 25 | "file_extension": ".py", 26 | "mimetype": "text/x-python", 27 | "name": "python", 28 | "nbconvert_exporter": "python", 29 | "pygments_lexer": "ipython3", 30 | "version": "3.9.13" 31 | }, 32 | "toc": { 33 | "base_numbering": 1, 34 | "nav_menu": {}, 35 | "number_sections": true, 36 | "sideBar": true, 37 | "skip_h1_title": false, 38 | "title_cell": "Table of Contents", 39 | "title_sidebar": "Contents", 40 | "toc_cell": false, 41 | "toc_position": {}, 42 | "toc_section_display": true, 43 | "toc_window_display": false 44 | } 45 | }, 46 | "nbformat": 4, 47 | "nbformat_minor": 1 48 | } 49 | -------------------------------------------------------------------------------- /examples/Rotate_icon.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/ui_elements/icons.html#Rotate-icons" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.0" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 1 37 | } 38 | -------------------------------------------------------------------------------- /examples/SmoothFactor.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/geojson/smoothing.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3 (ipykernel)", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.7" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 1 37 | } 38 | -------------------------------------------------------------------------------- /examples/TagFilterButton.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/plugins/tag_filter_button.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3 (ipykernel)", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.13" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 2 37 | } 38 | -------------------------------------------------------------------------------- /examples/TilesExample.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/raster_layers/tiles.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "anaconda-cloud": {}, 18 | "kernelspec": { 19 | "display_name": "Python 3", 20 | "language": "python", 21 | "name": "python3" 22 | }, 23 | "language_info": { 24 | "codemirror_mode": { 25 | "name": "ipython", 26 | "version": 3 27 | }, 28 | "file_extension": ".py", 29 | "mimetype": "text/x-python", 30 | "name": "python", 31 | "nbconvert_exporter": "python", 32 | "pygments_lexer": "ipython3", 33 | "version": "3.9.0" 34 | } 35 | }, 36 | "nbformat": 4, 37 | "nbformat_minor": 1 38 | } 39 | -------------------------------------------------------------------------------- /examples/TimeSliderChoropleth.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "We've updated our documentation. You can find the new version of this notebook here:\n", 7 | "https://python-visualization.github.io/folium/latest/user_guide/plugins/timeslider_choropleth.html" 8 | ], 9 | "metadata": { 10 | "collapsed": false 11 | } 12 | } 13 | ], 14 | "metadata": { 15 | "kernelspec": { 16 | "display_name": "Python 3 (ipykernel)", 17 | "language": "python", 18 | "name": "python3" 19 | }, 20 | "language_info": { 21 | "codemirror_mode": { 22 | "name": "ipython", 23 | "version": 3 24 | }, 25 | "file_extension": ".py", 26 | "mimetype": "text/x-python", 27 | "name": "python", 28 | "nbconvert_exporter": "python", 29 | "pygments_lexer": "ipython3", 30 | "version": "3.9.13" 31 | } 32 | }, 33 | "nbformat": 4, 34 | "nbformat_minor": 2 35 | } 36 | -------------------------------------------------------------------------------- /examples/VectorLayers.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/vector_layers.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.0" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 1 37 | } 38 | -------------------------------------------------------------------------------- /examples/VideoOverlayLayer.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/raster_layers/video_overlay.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "_draft": { 18 | "nbviewer_url": "https://gist.github.com/629da6f621481ed4d513258d2ec64589" 19 | }, 20 | "gist": { 21 | "data": { 22 | "description": "folium video test", 23 | "public": true 24 | }, 25 | "id": "629da6f621481ed4d513258d2ec64589" 26 | }, 27 | "kernelspec": { 28 | "display_name": "Python 3", 29 | "language": "python", 30 | "name": "python3" 31 | }, 32 | "language_info": { 33 | "codemirror_mode": { 34 | "name": "ipython", 35 | "version": 3 36 | }, 37 | "file_extension": ".py", 38 | "mimetype": "text/x-python", 39 | "name": "python", 40 | "nbconvert_exporter": "python", 41 | "pygments_lexer": "ipython3", 42 | "version": "3.9.0" 43 | } 44 | }, 45 | "nbformat": 4, 46 | "nbformat_minor": 2 47 | } 48 | -------------------------------------------------------------------------------- /examples/WMS_and_WMTS.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/raster_layers/wms_tile_layer.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.0" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 1 37 | } 38 | -------------------------------------------------------------------------------- /examples/WidthHeight.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation and removed this notebook.\n", 12 | "You can find the current documentation at https://python-visualization.github.io/folium/latest/." 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.0" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 1 37 | } 38 | -------------------------------------------------------------------------------- /examples/WmsTimeDimension.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/plugins/WmsTimeDimension.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.0" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 2 37 | } 38 | -------------------------------------------------------------------------------- /examples/data/Mercator_projection_SW.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/python-visualization/folium/8e09fb812887860518e7de0eb1e3d539f01a804c/examples/data/Mercator_projection_SW.jpg -------------------------------------------------------------------------------- /examples/data/Mercator_projection_SW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/python-visualization/folium/8e09fb812887860518e7de0eb1e3d539f01a804c/examples/data/Mercator_projection_SW.png -------------------------------------------------------------------------------- /examples/data/US_Unemployment_Oct2012.csv: -------------------------------------------------------------------------------- 1 | State,Unemployment 2 | AL,7.1 3 | AK,6.8 4 | AZ,8.1 5 | AR,7.2 6 | CA,10.1 7 | CO,7.7 8 | CT,8.4 9 | DE,7.1 10 | FL,8.2 11 | GA,8.8 12 | HI,5.4 13 | ID,6.6 14 | IL,8.8 15 | IN,8.4 16 | IA,5.1 17 | KS,5.6 18 | KY,8.1 19 | LA,5.9 20 | ME,7.2 21 | MD,6.8 22 | MA,6.7 23 | MI,9.1 24 | MN,5.6 25 | MS,9.1 26 | MO,6.7 27 | MT,5.8 28 | NE,3.9 29 | NV,10.3 30 | NH,5.7 31 | NJ,9.6 32 | NM,6.8 33 | NY,8.4 34 | NC,9.4 35 | ND,3.2 36 | OH,6.9 37 | OK,5.2 38 | OR,8.5 39 | PA,8 40 | RI,10.1 41 | SC,8.8 42 | SD,4.4 43 | TN,7.8 44 | TX,6.4 45 | UT,5.5 46 | VT,5 47 | VA,5.8 48 | WA,7.8 49 | WV,7.5 50 | WI,6.8 51 | WY,5.1 -------------------------------------------------------------------------------- /examples/data/consonants_vowels.csv: -------------------------------------------------------------------------------- 1 | language,coordinates,consonants,vowels 2 | Turkish,"(39.8667, 32.8667)",25,8 3 | Korean,"(37.5, 128.0)",21,11 4 | Tiwi,"(-11.6308, 130.94899999999998)",22,4 5 | Liberia Kpelle,"(6.92048, -9.96128)",22,12 6 | Tulu,"(12.8114, 75.2651)",24,13 7 | Mapudungun,"(-38.7392, -71.277)",20,6 8 | Kiowa,"(34.9403, -98.9042)",22,20 9 | Japanese,"(35.0, 135.0)",15,5 10 | Yoruba,"(7.15345, 3.67225)",18,11 11 | Finnish,"(64.7628, 25.5577)",17,8 12 | Hawaiian,"(19.6297, -155.43)",8,5 13 | Hungarian,"(46.9068585714, 19.6555271429)",26,14 14 | Georgian,"(41.850396999999994, 43.78613)",28,6 15 | Amharic,"(11.708182, 39.543456)",30,7 16 | Sandawe,"(-5.26918, 35.4808)",47,7 17 | Tlingit,"(59.4447, -135.29)",43,5 18 | Lakota,"(46.3699, -103.95)",28,8 19 | Yucatec Maya,"(18.7757, -88.9567)",20,10 20 | -------------------------------------------------------------------------------- /examples/data/data.json: -------------------------------------------------------------------------------- 1 | [{"WA": 7.8, "DE": 7.1, "WI": 6.8, "WV": 7.5, "HI": 5.4, "FL": 8.2, "WY": 5.1, "NH": 5.7, "NJ": 9.6, "NM": 6.8, "TX": 6.4, "LA": 5.9, "NC": 9.4, "ND": 3.2, "NE": 3.9, "TN": 7.8, "NY": 8.4, "PA": 8.0, "CA": 10.1, "NV": 10.3, "VA": 5.8, "CO": 7.7, "AK": 6.8, "AL": 7.1, "AR": 7.2, "VT": 5.0, "IL": 8.8, "GA": 8.8, "IN": 8.4, "IA": 5.1, "OK": 5.2, "AZ": 8.1, "ID": 6.6, "CT": 8.4, "ME": 7.2, "MD": 6.8, "MA": 6.7, "OH": 6.9, "UT": 5.5, "MO": 6.7, "MN": 5.6, "MI": 9.1, "RI": 10.1, "KS": 5.6, "MT": 5.8, "MS": 9.1, "SC": 8.8, "KY": 8.1, "OR": 8.5, "SD": 4.4}] -------------------------------------------------------------------------------- /examples/data/mercator_temperature.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/python-visualization/folium/8e09fb812887860518e7de0eb1e3d539f01a804c/examples/data/mercator_temperature.mat -------------------------------------------------------------------------------- /examples/data/nybb.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/python-visualization/folium/8e09fb812887860518e7de0eb1e3d539f01a804c/examples/data/nybb.zip -------------------------------------------------------------------------------- /examples/flask_example.py: -------------------------------------------------------------------------------- 1 | """ 2 | We've updated our documentation. You can find the new version of this example here: 3 | https://python-visualization.github.io/folium/latest/advanced_guide/flask.html 4 | """ 5 | -------------------------------------------------------------------------------- /examples/plugin-Draw.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/plugins/draw.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.0" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 2 37 | } 38 | -------------------------------------------------------------------------------- /examples/plugin-DualMap.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/plugins/dual_map.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.0" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 2 37 | } 38 | -------------------------------------------------------------------------------- /examples/plugin-GroupedLayerControl.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/plugins/grouped_layer_control.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "interpreter": { 18 | "hash": "fe5dd214bcd3c7acb291c354b42a251cd956bb0540c24510fdecda31bd920a27" 19 | }, 20 | "kernelspec": { 21 | "display_name": "Python 3 (ipykernel)", 22 | "language": "python", 23 | "name": "python3" 24 | }, 25 | "language_info": { 26 | "codemirror_mode": { 27 | "name": "ipython", 28 | "version": 3 29 | }, 30 | "file_extension": ".py", 31 | "mimetype": "text/x-python", 32 | "name": "python", 33 | "nbconvert_exporter": "python", 34 | "pygments_lexer": "ipython3", 35 | "version": "3.9.13" 36 | } 37 | }, 38 | "nbformat": 4, 39 | "nbformat_minor": 2 40 | } 41 | -------------------------------------------------------------------------------- /examples/plugin-MeasureControl.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/plugins/measure_control.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "_draft": { 18 | "nbviewer_url": "https://gist.github.com/e7f6b078c47babcbc944e4486267d415" 19 | }, 20 | "gist": { 21 | "data": { 22 | "description": "Untitled.ipynb", 23 | "public": true 24 | }, 25 | "id": "e7f6b078c47babcbc944e4486267d415" 26 | }, 27 | "kernelspec": { 28 | "display_name": "Python 3", 29 | "language": "python", 30 | "name": "python3" 31 | }, 32 | "language_info": { 33 | "codemirror_mode": { 34 | "name": "ipython", 35 | "version": 3 36 | }, 37 | "file_extension": ".py", 38 | "mimetype": "text/x-python", 39 | "name": "python", 40 | "nbconvert_exporter": "python", 41 | "pygments_lexer": "ipython3", 42 | "version": "3.9.0" 43 | } 44 | }, 45 | "nbformat": 4, 46 | "nbformat_minor": 2 47 | } 48 | -------------------------------------------------------------------------------- /examples/plugin-MousePosition.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/plugins/mouse_position.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.0" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 1 37 | } 38 | -------------------------------------------------------------------------------- /examples/plugin-PolyLineOffset.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/plugins/polyline_offset.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.0" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 1 37 | } 38 | -------------------------------------------------------------------------------- /examples/plugin-Search.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/plugins/search.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3 (ipykernel)", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.16" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 2 37 | } 38 | -------------------------------------------------------------------------------- /examples/plugin-patterns.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "pycharm": { 7 | "name": "#%% md\n" 8 | } 9 | }, 10 | "source": [ 11 | "We've updated our documentation. You can find the new version of this notebook here:\n", 12 | "https://python-visualization.github.io/folium/latest/user_guide/plugins/pattern.html" 13 | ] 14 | } 15 | ], 16 | "metadata": { 17 | "kernelspec": { 18 | "display_name": "Python 3 (ipykernel)", 19 | "language": "python", 20 | "name": "python3" 21 | }, 22 | "language_info": { 23 | "codemirror_mode": { 24 | "name": "ipython", 25 | "version": 3 26 | }, 27 | "file_extension": ".py", 28 | "mimetype": "text/x-python", 29 | "name": "python", 30 | "nbconvert_exporter": "python", 31 | "pygments_lexer": "ipython3", 32 | "version": "3.9.7" 33 | } 34 | }, 35 | "nbformat": 4, 36 | "nbformat_minor": 2 37 | } 38 | -------------------------------------------------------------------------------- /examples/plugin-vector-tiles.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "09534296", 6 | "metadata": { 7 | "pycharm": { 8 | "name": "#%% md\n" 9 | } 10 | }, 11 | "source": [ 12 | "We've updated our documentation. You can find the new version of this notebook here:\n", 13 | "https://python-visualization.github.io/folium/latest/user_guide/plugins/vector_tiles.html" 14 | ] 15 | } 16 | ], 17 | "metadata": { 18 | "kernelspec": { 19 | "display_name": "Python 3", 20 | "language": "python", 21 | "name": "python3" 22 | }, 23 | "language_info": { 24 | "codemirror_mode": { 25 | "name": "ipython", 26 | "version": 3 27 | }, 28 | "file_extension": ".py", 29 | "mimetype": "text/x-python", 30 | "name": "python", 31 | "nbconvert_exporter": "python", 32 | "pygments_lexer": "ipython3", 33 | "version": "3.7.10" 34 | } 35 | }, 36 | "nbformat": 4, 37 | "nbformat_minor": 5 38 | } 39 | -------------------------------------------------------------------------------- /folium/plugins/antpath.py: -------------------------------------------------------------------------------- 1 | from folium.elements import JSCSSMixin 2 | from folium.template import Template 3 | from folium.vector_layers import BaseMultiLocation, path_options 4 | 5 | 6 | class AntPath(JSCSSMixin, BaseMultiLocation): 7 | """ 8 | Class for drawing AntPath polyline overlays on a map. 9 | 10 | See :func:`folium.vector_layers.path_options` for the `Path` options. 11 | 12 | Parameters 13 | ---------- 14 | locations: list of points (latitude, longitude) 15 | Latitude and Longitude of line (Northing, Easting) 16 | popup: str or folium.Popup, default None 17 | Input text or visualization for object displayed when clicking. 18 | tooltip: str or folium.Tooltip, optional 19 | Display a text when hovering over the object. 20 | **kwargs: 21 | Polyline and AntPath options. See their Github page for the 22 | available parameters. 23 | 24 | https://github.com/rubenspgcavalcante/leaflet-ant-path/ 25 | 26 | """ 27 | 28 | _template = Template( 29 | """ 30 | {% macro script(this, kwargs) %} 31 | {{ this.get_name() }} = L.polyline.antPath( 32 | {{ this.locations|tojson }}, 33 | {{ this.options|tojavascript }} 34 | ).addTo({{this._parent.get_name()}}); 35 | {% endmacro %} 36 | """ 37 | ) 38 | 39 | default_js = [ 40 | ( 41 | "antpath", 42 | "https://cdn.jsdelivr.net/npm/leaflet-ant-path@1.1.2/dist/leaflet-ant-path.min.js", 43 | ) 44 | ] 45 | 46 | def __init__(self, locations, popup=None, tooltip=None, **kwargs): 47 | super().__init__( 48 | locations, 49 | popup=popup, 50 | tooltip=tooltip, 51 | ) 52 | 53 | self._name = "AntPath" 54 | # Polyline + AntPath defaults. 55 | self.options = path_options(line=True, **kwargs) 56 | self.options.update( 57 | { 58 | "paused": kwargs.pop("paused", False), 59 | "reverse": kwargs.pop("reverse", False), 60 | "hardwareAcceleration": kwargs.pop("hardware_acceleration", False), 61 | "delay": kwargs.pop("delay", 400), 62 | "dashArray": kwargs.pop("dash_array", [10, 20]), 63 | "weight": kwargs.pop("weight", 5), 64 | "opacity": kwargs.pop("opacity", 0.5), 65 | "color": kwargs.pop("color", "#0000FF"), 66 | "pulseColor": kwargs.pop("pulse_color", "#FFFFFF"), 67 | } 68 | ) 69 | -------------------------------------------------------------------------------- /folium/plugins/boat_marker.py: -------------------------------------------------------------------------------- 1 | from folium.elements import JSCSSMixin 2 | from folium.map import Marker 3 | from folium.template import Template 4 | from folium.utilities import remove_empty 5 | 6 | 7 | class BoatMarker(JSCSSMixin, Marker): 8 | """Add a Marker in the shape of a boat. 9 | 10 | Parameters 11 | ---------- 12 | location: tuple of length 2, default None 13 | The latitude and longitude of the marker. 14 | If None, then the middle of the map is used. 15 | heading: int, default 0 16 | Heading of the boat to an angle value between 0 and 360 degrees 17 | wind_heading: int, default None 18 | Heading of the wind to an angle value between 0 and 360 degrees 19 | If None, then no wind is represented. 20 | wind_speed: int, default 0 21 | Speed of the wind in knots. 22 | 23 | https://github.com/thomasbrueggemann/leaflet.boatmarker 24 | 25 | """ 26 | 27 | _template = Template( 28 | """ 29 | {% macro script(this, kwargs) %} 30 | var {{ this.get_name() }} = L.boatMarker( 31 | {{ this.location|tojson }}, 32 | {{ this.options|tojavascript }} 33 | ).addTo({{ this._parent.get_name() }}); 34 | {% if this.wind_heading is not none -%} 35 | {{ this.get_name() }}.setHeadingWind( 36 | {{ this.heading }}, 37 | {{ this.wind_speed }}, 38 | {{ this.wind_heading }} 39 | ); 40 | {% else -%} 41 | {{this.get_name()}}.setHeading({{this.heading}}); 42 | {% endif -%} 43 | {% endmacro %} 44 | """ 45 | ) 46 | 47 | default_js = [ 48 | ( 49 | "markerclusterjs", 50 | "https://unpkg.com/leaflet.boatmarker/leaflet.boatmarker.min.js", 51 | ), 52 | ] 53 | 54 | def __init__( 55 | self, 56 | location, 57 | popup=None, 58 | icon=None, 59 | heading=0, 60 | wind_heading=None, 61 | wind_speed=0, 62 | **kwargs 63 | ): 64 | super().__init__(location, popup=popup, icon=icon) 65 | self._name = "BoatMarker" 66 | self.heading = heading 67 | self.wind_heading = wind_heading 68 | self.wind_speed = wind_speed 69 | self.options = remove_empty(**kwargs) 70 | -------------------------------------------------------------------------------- /folium/plugins/float_image.py: -------------------------------------------------------------------------------- 1 | from branca.element import MacroElement 2 | 3 | from folium.template import Template 4 | 5 | 6 | class FloatImage(MacroElement): 7 | """Adds a floating image in HTML canvas on top of the map. 8 | 9 | Parameters 10 | ---------- 11 | image: str 12 | Url to image location. Can also be an inline image using a data URI 13 | or a local file using `file://`. 14 | bottom: int, default 75 15 | Vertical position from the bottom, as a percentage of screen height. 16 | left: int, default 75 17 | Horizontal position from the left, as a percentage of screen width. 18 | **kwargs 19 | Additional keyword arguments are applied as CSS properties. 20 | For example: `width='300px'`. 21 | 22 | """ 23 | 24 | _template = Template( 25 | """ 26 | {% macro header(this,kwargs) %} 27 | 37 | {% endmacro %} 38 | 39 | {% macro html(this,kwargs) %} 40 | float_image 43 | 44 | {% endmacro %} 45 | """ 46 | ) 47 | 48 | def __init__(self, image, bottom=75, left=75, **kwargs): 49 | super().__init__() 50 | self._name = "FloatImage" 51 | self.image = image 52 | self.bottom = bottom 53 | self.left = left 54 | self.css = kwargs 55 | -------------------------------------------------------------------------------- /folium/plugins/fullscreen.py: -------------------------------------------------------------------------------- 1 | from branca.element import MacroElement 2 | 3 | from folium.elements import JSCSSMixin 4 | from folium.template import Template 5 | from folium.utilities import remove_empty 6 | 7 | 8 | class Fullscreen(JSCSSMixin, MacroElement): 9 | """ 10 | Adds a fullscreen button to your map. 11 | 12 | Parameters 13 | ---------- 14 | position : str 15 | change the position of the button can be: 16 | 'topleft', 'topright', 'bottomright' or 'bottomleft' 17 | default: 'topleft' 18 | title : str 19 | change the title of the button, 20 | default: 'Full Screen' 21 | title_cancel : str 22 | change the title of the button when fullscreen is on, 23 | default: 'Exit Full Screen' 24 | force_separate_button : bool, default False 25 | force separate button to detach from zoom buttons, 26 | 27 | See https://github.com/brunob/leaflet.fullscreen for more information. 28 | """ 29 | 30 | _template = Template( 31 | """ 32 | {% macro script(this, kwargs) %} 33 | L.control.fullscreen( 34 | {{ this.options|tojavascript }} 35 | ).addTo({{this._parent.get_name()}}); 36 | {% endmacro %} 37 | """ 38 | ) # noqa 39 | 40 | default_js = [ 41 | ( 42 | "Control.Fullscreen.js", 43 | "https://cdn.jsdelivr.net/npm/leaflet.fullscreen@3.0.0/Control.FullScreen.min.js", 44 | ) 45 | ] 46 | default_css = [ 47 | ( 48 | "Control.FullScreen.css", 49 | "https://cdn.jsdelivr.net/npm/leaflet.fullscreen@3.0.0/Control.FullScreen.css", 50 | ) 51 | ] 52 | 53 | def __init__( 54 | self, 55 | position="topleft", 56 | title="Full Screen", 57 | title_cancel="Exit Full Screen", 58 | force_separate_button=False, 59 | **kwargs 60 | ): 61 | super().__init__() 62 | self._name = "Fullscreen" 63 | self.options = remove_empty( 64 | position=position, 65 | title=title, 66 | title_cancel=title_cancel, 67 | force_separate_button=force_separate_button, 68 | **kwargs 69 | ) 70 | -------------------------------------------------------------------------------- /folium/plugins/polyline_offset.py: -------------------------------------------------------------------------------- 1 | from folium.elements import JSCSSMixin 2 | from folium.vector_layers import PolyLine 3 | 4 | 5 | class PolyLineOffset(JSCSSMixin, PolyLine): 6 | """ 7 | Add offset capabilities to the PolyLine class. 8 | 9 | This plugin adds to folium Polylines the ability to be drawn with a 10 | relative pixel offset, without modifying their actual coordinates. The offset 11 | value can be either negative or positive, for left- or right-side offset, 12 | and remains constant across zoom levels. 13 | 14 | See :func:`folium.vector_layers.path_options` for the `Path` options. 15 | 16 | Parameters 17 | ---------- 18 | locations: list of points (latitude, longitude) 19 | Latitude and Longitude of line (Northing, Easting) 20 | popup: str or folium.Popup, default None 21 | Input text or visualization for object displayed when clicking. 22 | tooltip: str or folium.Tooltip, optional 23 | Display a text when hovering over the object. 24 | offset: int, default 0 25 | Relative pixel offset to draw a line parallel to an existent one, 26 | at a fixed distance. 27 | **kwargs: 28 | Polyline options. See their Github page for the 29 | available parameters. 30 | 31 | See https://github.com/bbecquet/Leaflet.PolylineOffset 32 | 33 | Examples 34 | -------- 35 | >>> plugins.PolyLineOffset( 36 | ... [[58, -28], [53, -23]], color="#f00", opacity=1, offset=-5 37 | ... ).add_to(m) 38 | >>> plugins.PolyLineOffset( 39 | ... [[58, -28], [53, -23]], color="#080", opacity=1, offset=10 40 | ... ).add_to(m) 41 | 42 | """ 43 | 44 | default_js = [ 45 | ( 46 | "polylineoffset", 47 | "https://cdn.jsdelivr.net/npm/leaflet-polylineoffset@1.1.1/leaflet.polylineoffset.min.js", 48 | ) 49 | ] 50 | 51 | def __init__(self, locations, popup=None, tooltip=None, offset=0, **kwargs): 52 | super().__init__(locations=locations, popup=popup, tooltip=tooltip, **kwargs) 53 | self._name = "PolyLineOffset" 54 | # Add PolyLineOffset offset. 55 | self.options.update({"offset": offset}) 56 | -------------------------------------------------------------------------------- /folium/plugins/scroll_zoom_toggler.py: -------------------------------------------------------------------------------- 1 | from branca.element import MacroElement 2 | 3 | from folium.template import Template 4 | 5 | 6 | class ScrollZoomToggler(MacroElement): 7 | """Creates a button for enabling/disabling scroll on the Map.""" 8 | 9 | _template = Template( 10 | """ 11 | {% macro header(this,kwargs) %} 12 | 25 | {% endmacro %} 26 | 27 | {% macro html(this,kwargs) %} 28 | scroll 33 | 34 | {% endmacro %} 35 | 36 | {% macro script(this,kwargs) %} 37 | {{ this._parent.get_name() }}.scrollEnabled = true; 38 | 39 | {{ this._parent.get_name() }}.toggleScroll = function() { 40 | if (this.scrollEnabled) { 41 | this.scrollEnabled = false; 42 | this.scrollWheelZoom.disable(); 43 | } else { 44 | this.scrollEnabled = true; 45 | this.scrollWheelZoom.enable(); 46 | } 47 | }; 48 | {{ this._parent.get_name() }}.toggleScroll(); 49 | {% endmacro %} 50 | """ 51 | ) 52 | 53 | def __init__(self): 54 | super().__init__() 55 | self._name = "ScrollZoomToggler" 56 | -------------------------------------------------------------------------------- /folium/plugins/side_by_side.py: -------------------------------------------------------------------------------- 1 | from branca.element import MacroElement 2 | 3 | from folium.elements import JSCSSMixin 4 | from folium.template import Template 5 | 6 | 7 | class SideBySideLayers(JSCSSMixin, MacroElement): 8 | """ 9 | Creates a SideBySideLayers that takes two Layers and adds a sliding 10 | control with the leaflet-side-by-side plugin. 11 | 12 | Uses the Leaflet leaflet-side-by-side plugin https://github.com/digidem/leaflet-side-by-side 13 | 14 | Parameters 15 | ---------- 16 | layer_left: Layer. 17 | The left Layer within the side by side control. 18 | Must be created and added to the map before being passed to this class. 19 | layer_right: Layer. 20 | The right Layer within the side by side control. 21 | Must be created and added to the map before being passed to this class. 22 | 23 | Examples 24 | -------- 25 | >>> sidebyside = SideBySideLayers(layer_left, layer_right) 26 | >>> sidebyside.add_to(m) 27 | """ 28 | 29 | _template = Template( 30 | """ 31 | {% macro script(this, kwargs) %} 32 | var {{ this.get_name() }} = L.control.sideBySide( 33 | {{ this.layer_left.get_name() }}, {{ this.layer_right.get_name() }} 34 | ).addTo({{ this._parent.get_name() }}); 35 | {% endmacro %} 36 | """ 37 | ) 38 | 39 | default_js = [ 40 | ( 41 | "leaflet.sidebyside", 42 | "https://cdn.jsdelivr.net/gh/digidem/leaflet-side-by-side@2.0.0/leaflet-side-by-side.min.js", 43 | ), 44 | ] 45 | 46 | def __init__(self, layer_left, layer_right): 47 | super().__init__() 48 | self._name = "SideBySideLayers" 49 | self.layer_left = layer_left 50 | self.layer_right = layer_right 51 | -------------------------------------------------------------------------------- /folium/plugins/terminator.py: -------------------------------------------------------------------------------- 1 | from branca.element import MacroElement 2 | 3 | from folium.elements import JSCSSMixin 4 | from folium.template import Template 5 | 6 | 7 | class Terminator(JSCSSMixin, MacroElement): 8 | """ 9 | Leaflet.Terminator is a simple plug-in to the Leaflet library to 10 | overlay day and night regions on maps. 11 | 12 | """ 13 | 14 | _template = Template( 15 | """ 16 | {% macro script(this, kwargs) %} 17 | L.terminator().addTo({{this._parent.get_name()}}); 18 | {% endmacro %} 19 | """ 20 | ) 21 | 22 | default_js = [("terminator", "https://unpkg.com/@joergdietrich/leaflet.terminator")] 23 | 24 | def __init__(self): 25 | super().__init__() 26 | self._name = "Terminator" 27 | -------------------------------------------------------------------------------- /folium/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/python-visualization/folium/8e09fb812887860518e7de0eb1e3d539f01a804c/folium/py.typed -------------------------------------------------------------------------------- /folium/template.py: -------------------------------------------------------------------------------- 1 | import json 2 | from typing import Union 3 | 4 | import jinja2 5 | from branca.element import Element 6 | 7 | from folium.utilities import JsCode, TypeJsonValue, camelize 8 | 9 | 10 | def tojavascript(obj: Union[str, JsCode, dict, list, Element]) -> str: 11 | if isinstance(obj, JsCode): 12 | return obj.js_code 13 | elif isinstance(obj, Element): 14 | return obj.get_name() 15 | elif isinstance(obj, dict): 16 | out = ["{\n"] 17 | for key, value in obj.items(): 18 | if isinstance(key, str): 19 | out.append(f' "{camelize(key)}": ') 20 | else: 21 | out.append(f" {key}: ") 22 | out.append(tojavascript(value)) 23 | out.append(",\n") 24 | out.append("}") 25 | return "".join(out) 26 | elif isinstance(obj, list): 27 | out = ["[\n"] 28 | for value in obj: 29 | out.append(tojavascript(value)) 30 | out.append(",\n") 31 | out.append("]") 32 | return "".join(out) 33 | else: 34 | return _to_escaped_json(obj) 35 | 36 | 37 | def _to_escaped_json(obj: TypeJsonValue) -> str: 38 | return ( 39 | json.dumps(obj) 40 | .replace("<", "\\u003c") 41 | .replace(">", "\\u003e") 42 | .replace("&", "\\u0026") 43 | .replace("'", "\\u0027") 44 | ) 45 | 46 | 47 | class Environment(jinja2.Environment): 48 | def __init__(self, *args, **kwargs): 49 | super().__init__(*args, **kwargs) 50 | self.filters["tojavascript"] = tojavascript 51 | 52 | 53 | class Template(jinja2.Template): 54 | environment_class = Environment 55 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=41.2", "setuptools_scm", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [tool.interrogate] 6 | ignore-init-method = true 7 | ignore-init-module = false 8 | ignore-magic = false 9 | ignore-semiprivate = false 10 | ignore-private = false 11 | ignore-module = false 12 | fail-under = 85 13 | exclude = ["setup.py", "docs", "tests"] 14 | verbose = 1 15 | quiet = false 16 | color = true 17 | 18 | [tool.mypy] 19 | ignore_missing_imports = true 20 | 21 | [tool.ruff] 22 | lint.select = [ 23 | "F", # flakes 24 | "I", # import sorting 25 | "U", # upgrade 26 | ] 27 | target-version = "py37" 28 | line-length = 120 29 | 30 | [lint.per-file-ignores] 31 | "docs/conf.py" = ["E402"] 32 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | altair>=5.0.0 2 | cartopy 3 | check-manifest 4 | descartes 5 | fiona 6 | flake8 7 | flake8-builtins 8 | flake8-comprehensions 9 | flake8-import-order 10 | flake8-mutable 11 | flake8-nb>=0.2.5 12 | geodatasets 13 | geographiclib 14 | geopandas>=1 15 | gpxpy 16 | ipykernel 17 | jenkspy 18 | jupyter 19 | jupytext==1.16.* # Due to selenium test failures in 1.17.0. 20 | matplotlib 21 | mypy 22 | nbconvert 23 | nbsphinx 24 | nbval 25 | owslib 26 | pandas >=2 27 | pillow 28 | pre-commit 29 | pycodestyle 30 | pydata-sphinx-theme 31 | pytest 32 | scipy 33 | selenium 34 | setuptools_scm 35 | sphinx 36 | types-requests 37 | vega_datasets 38 | vincent 39 | wheel 40 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | branca>=0.6.0 2 | jinja2>=2.9 3 | numpy 4 | requests 5 | xyzservices 6 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | license_file = LICENSE.txt 4 | 5 | [bdist_wheel] 6 | universal = 1 7 | 8 | [check-manifest] 9 | ignore = 10 | *.yml 11 | docs 12 | docs/* 13 | *.enc 14 | tests 15 | tests/* 16 | -------------------------------------------------------------------------------- /tests/geo_grid.json: -------------------------------------------------------------------------------- 1 | {"type": "FeatureCollection", "features": [ 2 | {"id": "0", "type": "Feature", "properties": {"idx": 0, "value": 78.0}, "geometry": {"type": "Polygon", "coordinates": [[[479978.6866107661, 6676603.690234357], [491978.6866107661, 6676603.690234357], [491978.6866107661, 6664603.690234357], [479978.6866107661, 6664603.690234357], [479978.6866107661, 6676603.690234357]]]}}, 3 | {"id": "1", "type": "Feature", "properties": {"idx": 1, "value": 39.0}, "geometry": {"type": "Polygon", "coordinates": [[[479978.6866107661, 6664603.690234357], [491978.6866107661, 6664603.690234357], [491978.6866107661, 6652603.690234357], [479978.6866107661, 6652603.690234357], [479978.6866107661, 6664603.690234357]]]}}, 4 | {"id": "2", "type": "Feature", "properties": {"idx": 2, "value": 0.0}, "geometry": {"type": "Polygon", "coordinates": [[[479978.6866107661, 6652603.690234357], [491978.6866107661, 6652603.690234357], [491978.6866107661, 6640603.690234357], [479978.6866107661, 6640603.690234357], [479978.6866107661, 6652603.690234357]]]}}, 5 | {"id": "3", "type": "Feature", "properties": {"idx": 3, "value": 81.0}, "geometry": {"type": "Polygon", "coordinates": [[[491978.6866107661, 6676603.690234357], [503978.6866107661, 6676603.690234357], [503978.6866107661, 6664603.690234357], [491978.6866107661, 6664603.690234357], [491978.6866107661, 6676603.690234357]]]}}, 6 | {"id": "4", "type": "Feature", "properties": {"idx": 4, "value": 42.0}, "geometry": {"type": "Polygon", "coordinates": [[[491978.6866107661, 6664603.690234357], [503978.6866107661, 6664603.690234357], [503978.6866107661, 6652603.690234357], [491978.6866107661, 6652603.690234357], [491978.6866107661, 6664603.690234357]]]}}, 7 | {"id": "5", "type": "Feature", "properties": {"idx": 5, "value": 68.0}, "geometry": {"type": "Polygon", "coordinates": [[[491978.6866107661, 6652603.690234357], [503978.6866107661, 6652603.690234357], [503978.6866107661, 6640603.690234357], [491978.6866107661, 6640603.690234357], [491978.6866107661, 6652603.690234357]]]}} 8 | ]} -------------------------------------------------------------------------------- /tests/plugins/test_antpath.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test AntPath 3 | ------------- 4 | """ 5 | 6 | import folium 7 | from folium import plugins 8 | from folium.template import Template 9 | from folium.utilities import normalize 10 | 11 | 12 | def test_antpath(): 13 | m = folium.Map([20.0, 0.0], zoom_start=3) 14 | 15 | locations = [ 16 | [59.355600, -31.99219], 17 | [55.178870, -42.89062], 18 | [47.754100, -43.94531], 19 | [38.272690, -37.96875], 20 | [27.059130, -41.13281], 21 | [16.299050, -36.56250], 22 | [8.4071700, -30.23437], 23 | [1.0546300, -22.50000], 24 | [-8.754790, -18.28125], 25 | [-21.61658, -20.03906], 26 | [-31.35364, -24.25781], 27 | [-39.90974, -30.93750], 28 | [-43.83453, -41.13281], 29 | [-47.75410, -49.92187], 30 | [-50.95843, -54.14062], 31 | [-55.97380, -56.60156], 32 | ] 33 | 34 | antpath = plugins.AntPath(locations=locations) 35 | antpath.add_to(m) 36 | 37 | out = m._parent.render() 38 | 39 | # We verify that the script import is present. 40 | script = '' # noqa 41 | assert script in out 42 | 43 | # We verify that the script part is correct. 44 | tmpl = Template( 45 | """ 46 | {{this.get_name()}} = L.polyline.antPath( 47 | {{ this.locations|tojson }}, 48 | {{ this.options|tojavascript }} 49 | ) 50 | .addTo({{this._parent.get_name()}}); 51 | """ 52 | ) # noqa 53 | 54 | expected_rendered = tmpl.render(this=antpath) 55 | rendered = antpath._template.module.script(antpath) 56 | assert normalize(expected_rendered) == normalize(rendered) 57 | -------------------------------------------------------------------------------- /tests/plugins/test_beautify_icon.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test BeautifyIcon 3 | --------------- 4 | 5 | """ 6 | 7 | import folium 8 | from folium import plugins 9 | from folium.template import Template 10 | from folium.utilities import normalize 11 | 12 | 13 | def test_beautify_icon(): 14 | m = folium.Map([30.0, 0.0], zoom_start=3) 15 | # BeautifyIcons 16 | ic1 = plugins.BeautifyIcon( 17 | icon="plane", border_color="#b3334f", text_color="#b3334f" 18 | ) 19 | ic2 = plugins.BeautifyIcon( 20 | border_color="#00ABDC", 21 | text_color="#00ABDC", 22 | number=10, 23 | inner_icon_style="margin-top:0;", 24 | ) 25 | 26 | # Markers, add icons as keyword argument 27 | bm1 = folium.Marker(location=[46, -122], popup="Portland, OR", icon=ic1).add_to(m) 28 | 29 | bm2 = folium.Marker(location=[50, -121], icon=ic2).add_to(m) 30 | 31 | m.add_child(bm1) 32 | m.add_child(bm2) 33 | m._repr_html_() 34 | 35 | out = normalize(m._parent.render()) 36 | 37 | # We verify that the script import is present. 38 | script = '' # noqa 39 | assert script in out 40 | 41 | # We verify that the css import is present. 42 | css = '' # noqa 43 | assert css in out 44 | 45 | # We verify that the Beautiful Icons are rendered correctly. 46 | tmpl = Template( 47 | """ 48 | var {{this.get_name()}} = new L.BeautifyIcon.icon({{ this.options|tojavascript }}) 49 | {{this._parent.get_name()}}.setIcon({{this.get_name()}}); 50 | """ 51 | ) # noqa 52 | 53 | assert normalize(tmpl.render(this=ic1)) in out 54 | assert normalize(tmpl.render(this=ic2)) in out 55 | -------------------------------------------------------------------------------- /tests/plugins/test_boat_marker.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test BoatMarker 3 | --------------- 4 | 5 | """ 6 | 7 | import folium 8 | from folium import plugins 9 | from folium.template import Template 10 | from folium.utilities import normalize 11 | 12 | 13 | def test_boat_marker(): 14 | m = folium.Map([30.0, 0.0], zoom_start=3) 15 | bm1 = plugins.BoatMarker( 16 | (34, -43), heading=45, wind_heading=150, wind_speed=45, color="#8f8" 17 | ) 18 | bm2 = plugins.BoatMarker( 19 | (46, -30), heading=-20, wind_heading=46, wind_speed=25, color="#88f" 20 | ) 21 | 22 | m.add_child(bm1) 23 | m.add_child(bm2) 24 | m._repr_html_() 25 | 26 | out = normalize(m._parent.render()) 27 | 28 | # We verify that the script import is present. 29 | script = '' # noqa 30 | assert script in out 31 | 32 | # We verify that the script part is correct. 33 | tmpl = Template( 34 | """ 35 | var {{ this.get_name() }} = L.boatMarker( 36 | {{ this.location|tojson }}, 37 | {{ this.options|tojavascript }} 38 | ).addTo({{ this._parent.get_name() }}); 39 | {{ this.get_name() }}.setHeadingWind( 40 | {{ this.heading }}, 41 | {{ this.wind_speed }}, 42 | {{ this.wind_heading }} 43 | ); 44 | """ 45 | ) 46 | 47 | assert normalize(tmpl.render(this=bm1)) in out 48 | assert normalize(tmpl.render(this=bm2)) in out 49 | 50 | bounds = m.get_bounds() 51 | assert bounds == [[34, -43], [46, -30]], bounds 52 | 53 | 54 | def test_boat_marker_with_no_wind_speed_or_heading(): 55 | m = folium.Map([30.0, 0.0], zoom_start=3) 56 | bm1 = plugins.BoatMarker((34, -43), heading=45, color="#8f8") 57 | m.add_child(bm1) 58 | 59 | out = normalize(m._parent.render()) 60 | 61 | # We verify that the script part is correct. 62 | tmpl = Template( 63 | """ 64 | var {{ this.get_name() }} = L.boatMarker( 65 | {{ this.location|tojson }}, 66 | {{ this.options|tojavascript }} 67 | ).addTo({{ this._parent.get_name() }}); 68 | {{ this.get_name() }}.setHeading({{ this.heading }}); 69 | """ 70 | ) 71 | 72 | assert normalize(tmpl.render(this=bm1)) in out 73 | -------------------------------------------------------------------------------- /tests/plugins/test_dual_map.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test DualMap 3 | ------------ 4 | """ 5 | 6 | import folium 7 | import folium.plugins 8 | from folium.template import Template 9 | from folium.utilities import normalize 10 | 11 | 12 | def test_dual_map(): 13 | m = folium.plugins.DualMap((0, 0)) 14 | 15 | folium.FeatureGroup(name="both").add_to(m) 16 | folium.FeatureGroup(name="left").add_to(m.m1) 17 | folium.FeatureGroup(name="right").add_to(m.m2) 18 | 19 | figure = m.get_root() 20 | assert isinstance(figure, folium.Figure) 21 | out = normalize(figure.render()) 22 | 23 | script = '' # noqa 24 | assert script in out 25 | 26 | tmpl = Template( 27 | """ 28 | {{ this.m1.get_name() }}.sync({{ this.m2.get_name() }}); 29 | {{ this.m2.get_name() }}.sync({{ this.m1.get_name() }}); 30 | """ 31 | ) 32 | 33 | assert normalize(tmpl.render(this=m)) in out 34 | -------------------------------------------------------------------------------- /tests/plugins/test_feature_group_sub_group.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test MarkerCluster 3 | ------------------ 4 | """ 5 | 6 | import folium 7 | from folium import plugins 8 | from folium.template import Template 9 | from folium.utilities import normalize 10 | 11 | 12 | def test_feature_group_sub_group(): 13 | m = folium.Map([0.0, 0.0], zoom_start=6) 14 | fg = folium.FeatureGroup() 15 | m.add_child(fg) 16 | g1 = plugins.FeatureGroupSubGroup(fg, "g1") 17 | m.add_child(g1) 18 | folium.Marker([1, 1]).add_to(g1) 19 | folium.Marker([-1, -1]).add_to(g1) 20 | g2 = plugins.FeatureGroupSubGroup(fg, "g2") 21 | folium.Marker([-1, 1]).add_to(g2) 22 | folium.Marker([1, -1]).add_to(g2) 23 | m.add_child(g2) 24 | folium.LayerControl().add_to(m) 25 | 26 | out = normalize(m._parent.render()) 27 | 28 | # We verify that imports 29 | assert ( 30 | '' # noqa 31 | in out 32 | ) # noqa 33 | 34 | # Verify the script part is okay. 35 | tmpl = Template( 36 | """ 37 | var {{ this.get_name() }} = L.featureGroup.subGroup( 38 | {{ this._group.get_name() }} 39 | ); 40 | """ 41 | ) 42 | assert normalize(tmpl.render(this=g1)) in out 43 | assert normalize(tmpl.render(this=g2)) in out 44 | 45 | tmpl = Template("{{ this.get_name() }}.addTo({{ this._parent.get_name() }});") 46 | assert normalize(tmpl.render(this=g1)) in out 47 | assert normalize(tmpl.render(this=g2)) in out 48 | -------------------------------------------------------------------------------- /tests/plugins/test_float_image.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test FloatImage 3 | --------------- 4 | """ 5 | 6 | import folium 7 | from folium import plugins 8 | from folium.template import Template 9 | from folium.utilities import normalize 10 | 11 | 12 | def test_float_image(): 13 | m = folium.Map([45.0, 3.0], zoom_start=4) 14 | url = "https://raw.githubusercontent.com/SECOORA/static_assets/master/maps/img/rose.png" 15 | szt = plugins.FloatImage(url, bottom=60, left=70, width="20%") 16 | m.add_child(szt) 17 | m._repr_html_() 18 | 19 | out = normalize(m._parent.render()) 20 | 21 | # Verify that the div has been created. 22 | tmpl = Template( 23 | """ 24 | float_image 27 | 28 | """ 29 | ) 30 | assert normalize(tmpl.render(this=szt)) in out 31 | 32 | # Verify that the style has been created. 33 | tmpl = Template( 34 | """ 35 | 43 | """ 44 | ) 45 | assert normalize(tmpl.render(this=szt)) in out 46 | 47 | bounds = m.get_bounds() 48 | assert bounds == [[None, None], [None, None]], bounds 49 | -------------------------------------------------------------------------------- /tests/plugins/test_fullscreen.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test Fullscreen 3 | ---------------- 4 | 5 | """ 6 | 7 | import folium 8 | from folium import plugins 9 | from folium.template import Template 10 | from folium.utilities import normalize 11 | 12 | 13 | def test_fullscreen(): 14 | m = folium.Map([47, 3], zoom_start=1) 15 | fs = plugins.Fullscreen().add_to(m) 16 | 17 | out = normalize(m._parent.render()) 18 | 19 | # verify that the fullscreen control was rendered 20 | tmpl = Template( 21 | """ 22 | L.control.fullscreen( 23 | {{ this.options|tojavascript }} 24 | ).addTo({{this._parent.get_name()}}); 25 | """ 26 | ) 27 | 28 | assert normalize(tmpl.render(this=fs)) in out 29 | -------------------------------------------------------------------------------- /tests/plugins/test_geoman.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test GeoMan 3 | ---------------- 4 | 5 | """ 6 | 7 | import folium 8 | from folium import plugins 9 | from folium.template import Template 10 | from folium.utilities import normalize 11 | 12 | 13 | def test_geoman(): 14 | m = folium.Map([47, 3], zoom_start=1) 15 | fs = plugins.GeoMan().add_to(m) 16 | 17 | out = normalize(m._parent.render()) 18 | 19 | # verify that the GeoMan plugin was added to 20 | # the map 21 | tmpl = Template( 22 | """ 23 | {{this._parent.get_name()}}.pm.addControls( 24 | {{this.options|tojavascript}} 25 | ) 26 | """ 27 | ) 28 | 29 | assert normalize(tmpl.render(this=fs)) in out 30 | -------------------------------------------------------------------------------- /tests/plugins/test_grouped_layer_control.py: -------------------------------------------------------------------------------- 1 | import folium 2 | from folium.plugins import groupedlayercontrol 3 | from folium.utilities import normalize 4 | 5 | 6 | def test_grouped_layer_control(): 7 | m = folium.Map([40.0, 70.0], zoom_start=6) 8 | fg1 = folium.FeatureGroup(name="g1") 9 | fg2 = folium.FeatureGroup(name="g2") 10 | fg3 = folium.FeatureGroup(name="g3") 11 | folium.Marker([40, 74]).add_to(fg1) 12 | folium.Marker([38, 72]).add_to(fg2) 13 | folium.Marker([40, 72]).add_to(fg3) 14 | m.add_child(fg1) 15 | m.add_child(fg2) 16 | m.add_child(fg3) 17 | lc = groupedlayercontrol.GroupedLayerControl(groups={"groups1": [fg1, fg2]}) 18 | lc.add_to(m) 19 | out = m._parent.render() 20 | print(out) 21 | out = normalize(out) 22 | 23 | assert ( 24 | "https://cdnjs.cloudflare.com/ajax/libs/leaflet-groupedlayercontrol/0.6.1/leaflet.groupedlayercontrol.min.js" 25 | in out 26 | ) 27 | 28 | expected = normalize( 29 | f""" 30 | L.control.groupedLayers( 31 | null, 32 | {{ 33 | "groups1" : {{ 34 | "g1" : {fg1.get_name()}, 35 | "g2" : {fg2.get_name()}, 36 | }}, 37 | }}, 38 | {{"exclusiveGroups": ["groups1",],}}, 39 | ).addTo({m.get_name()}); 40 | {fg2.get_name()}.remove(); 41 | """ 42 | ) 43 | assert expected in out 44 | -------------------------------------------------------------------------------- /tests/plugins/test_heat_map.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test HeatMap 3 | ------------ 4 | """ 5 | 6 | import numpy as np 7 | import pytest 8 | 9 | import folium 10 | from folium.plugins import HeatMap 11 | from folium.template import Template 12 | from folium.utilities import normalize 13 | 14 | 15 | def test_heat_map(): 16 | np.random.seed(3141592) 17 | data = np.random.normal(size=(100, 2)) * np.array([[1, 1]]) + np.array([[48, 5]]) 18 | m = folium.Map([48.0, 5.0], zoom_start=6) 19 | hm = HeatMap(data) 20 | m.add_child(hm) 21 | m._repr_html_() 22 | 23 | out = normalize(m._parent.render()) 24 | 25 | # We verify that the script import is present. 26 | script = '' # noqa 27 | assert script in out 28 | 29 | # We verify that the script part is correct. 30 | tmpl = Template( 31 | """ 32 | var {{this.get_name()}} = L.heatLayer( 33 | {{this.data}}, 34 | { 35 | minOpacity: {{this.min_opacity}}, 36 | maxZoom: {{this.max_zoom}}, 37 | radius: {{this.radius}}, 38 | blur: {{this.blur}}, 39 | gradient: {{this.gradient}} 40 | }) 41 | .addTo({{this._parent.get_name()}}); 42 | """ 43 | ) 44 | 45 | assert tmpl.render(this=hm) 46 | 47 | bounds = m.get_bounds() 48 | np.testing.assert_allclose( 49 | bounds, 50 | [ 51 | [46.218566840847025, 3.0302801394447734], 52 | [50.75345011431167, 7.132453997672826], 53 | ], 54 | ) 55 | 56 | 57 | def test_heatmap_data(): 58 | data = HeatMap(np.array([[3, 4, 1], [5, 6, 1], [7, 8, 0.5]])).data 59 | assert isinstance(data, list) 60 | assert len(data) == 3 61 | for i in range(len(data)): 62 | assert isinstance(data[i], list) 63 | assert len(data[i]) == 3 64 | 65 | 66 | def test_heat_map_exception(): 67 | with pytest.raises(ValueError): 68 | HeatMap(np.array([[4, 5, 1], [3, 6, np.nan]])) 69 | with pytest.raises(Exception): 70 | HeatMap(np.array([3, 4, 5])) 71 | -------------------------------------------------------------------------------- /tests/plugins/test_marker_cluster.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test MarkerCluster 3 | ------------------ 4 | """ 5 | 6 | import numpy as np 7 | 8 | import folium 9 | from folium import plugins 10 | from folium.template import Template 11 | from folium.utilities import normalize 12 | 13 | 14 | def test_marker_cluster(): 15 | N = 100 16 | np.random.seed(seed=26082009) 17 | data = np.array( 18 | [ 19 | np.random.uniform(low=35, high=60, size=N), # Random latitudes. 20 | np.random.uniform(low=-12, high=30, size=N), # Random longitudes. 21 | ] 22 | ).T 23 | m = folium.Map([45.0, 3.0], zoom_start=4) 24 | mc = plugins.MarkerCluster(data).add_to(m) 25 | 26 | tmpl_for_expected = Template( 27 | """ 28 | var {{this.get_name()}} = L.markerClusterGroup( 29 | {{ this.options|tojavascript }} 30 | ); 31 | {%- if this.icon_create_function is not none %} 32 | {{ this.get_name() }}.options.iconCreateFunction = 33 | {{ this.icon_create_function.strip() }}; 34 | {%- endif %} 35 | 36 | {% for marker in this._children.values() %} 37 | var {{marker.get_name()}} = L.marker( 38 | {{ marker.location|tojson }}, {} 39 | ).addTo({{this.get_name()}}); 40 | {% endfor %} 41 | 42 | {{ this.get_name() }}.addTo({{ this._parent.get_name() }}); 43 | """ 44 | ) 45 | expected = normalize(tmpl_for_expected.render(this=mc)) 46 | 47 | out = normalize(m._parent.render()) 48 | 49 | # We verify that imports 50 | assert ( 51 | '' # noqa 52 | in out 53 | ) # noqa 54 | assert ( 55 | '' # noqa 56 | in out 57 | ) # noqa 58 | assert ( 59 | '' # noqa 60 | in out 61 | ) # noqa 62 | 63 | assert expected in out 64 | 65 | bounds = m.get_bounds() 66 | np.testing.assert_allclose( 67 | bounds, 68 | [ 69 | [35.147332572663785, -11.520684337300109], 70 | [59.839718052359274, 29.94931046497927], 71 | ], 72 | ) 73 | -------------------------------------------------------------------------------- /tests/plugins/test_minimap.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test MiniMap 3 | --------------- 4 | """ 5 | 6 | import folium 7 | from folium import plugins 8 | from folium.utilities import normalize 9 | 10 | 11 | def test_minimap(): 12 | m = folium.Map(location=(30, 20), zoom_start=4) 13 | 14 | minimap = plugins.MiniMap() 15 | m.add_child(minimap) 16 | 17 | out = normalize(m._parent.render()) 18 | 19 | # Verify that a new minimap is getting created. 20 | assert "new L.Control.MiniMap" in out 21 | 22 | m = folium.Map(tiles=None, location=(30, 20), zoom_start=4) 23 | minimap = plugins.MiniMap() 24 | minimap.add_to(m) 25 | 26 | out = normalize(m._parent.render()) 27 | # verify that tiles are being used 28 | assert r"https://tile.openstreetmap.org" in out 29 | -------------------------------------------------------------------------------- /tests/plugins/test_pattern.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test pattern 3 | --------------- 4 | 5 | """ 6 | 7 | import os 8 | 9 | import folium 10 | from folium import plugins 11 | from folium.utilities import normalize 12 | 13 | 14 | def test_pattern(): 15 | m = folium.Map([40.0, -105.0], zoom_start=6) 16 | 17 | stripes = plugins.pattern.StripePattern(angle=-45) 18 | stripes.add_to(m) 19 | circles = plugins.pattern.CirclePattern( 20 | width=20, height=20, radius=5, fill_opacity=0.5, opacity=1 21 | ) 22 | 23 | def style_function(feature): 24 | default_style = { 25 | "opacity": 1.0, 26 | "fillColor": "#ffff00", 27 | "color": "black", 28 | "weight": 2, 29 | } 30 | 31 | if feature["properties"]["name"] == "Colorado": 32 | default_style["fillPattern"] = stripes 33 | default_style["fillOpacity"] = 1.0 34 | 35 | if feature["properties"]["name"] == "Utah": 36 | default_style["fillPattern"] = circles 37 | default_style["fillOpacity"] = 1.0 38 | 39 | return default_style 40 | 41 | data = os.path.join(os.path.dirname(__file__), os.pardir, "us-states.json") 42 | folium.GeoJson(data, style_function=style_function).add_to(m) 43 | 44 | out = normalize(m._parent.render()) 45 | 46 | # We verify that the script import is present. 47 | script = '' # noqa 48 | assert script in out 49 | -------------------------------------------------------------------------------- /tests/plugins/test_polyline_text_path.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test PolyLineTextPath 3 | --------------- 4 | """ 5 | 6 | import folium 7 | from folium import plugins 8 | from folium.template import Template 9 | from folium.utilities import normalize 10 | 11 | 12 | def test_polyline_text_path(): 13 | m = folium.Map([20.0, 0.0], zoom_start=3) 14 | 15 | wind_locations = [ 16 | [59.355600, -31.99219], 17 | [55.178870, -42.89062], 18 | [47.754100, -43.94531], 19 | [38.272690, -37.96875], 20 | [27.059130, -41.13281], 21 | [16.299050, -36.56250], 22 | [8.4071700, -30.23437], 23 | [1.0546300, -22.50000], 24 | [-8.754790, -18.28125], 25 | [-21.61658, -20.03906], 26 | [-31.35364, -24.25781], 27 | [-39.90974, -30.93750], 28 | [-43.83453, -41.13281], 29 | [-47.75410, -49.92187], 30 | [-50.95843, -54.14062], 31 | [-55.97380, -56.60156], 32 | ] 33 | 34 | wind_line = folium.PolyLine(wind_locations, weight=15, color="#8EE9FF") 35 | attr = {"fill": "#007DEF", "font-weight": "bold", "font-size": "24"} 36 | wind_textpath = plugins.PolyLineTextPath( 37 | wind_line, ") ", repeat=True, offset=7, attributes=attr 38 | ) 39 | 40 | m.add_child(wind_line) 41 | m.add_child(wind_textpath) 42 | 43 | out = normalize(m._parent.render()) 44 | 45 | # We verify that the script import is present. 46 | script = '' # noqa 47 | assert script in out 48 | 49 | # We verify that the script part is correct. 50 | tmpl = Template( 51 | """ 52 | {{ this.polyline.get_name() }}.setText( 53 | "{{this.text}}", 54 | {{ this.options|tojavascript }} 55 | ); 56 | """ 57 | ) 58 | 59 | expected = normalize(tmpl.render(this=wind_textpath)) 60 | assert expected in out 61 | -------------------------------------------------------------------------------- /tests/plugins/test_realtime.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test Realtime 3 | ------------------ 4 | """ 5 | 6 | import folium 7 | from folium.plugins import MarkerCluster, Realtime 8 | from folium.template import Template 9 | from folium.utilities import JsCode, normalize 10 | 11 | 12 | def test_realtime(): 13 | m = folium.Map(location=[40.73, -73.94], zoom_start=12) 14 | source = "https://raw.githubusercontent.com/python-visualization/folium-example-data/main/subway_stations.geojson" 15 | 16 | container = MarkerCluster().add_to(m) 17 | 18 | rt = Realtime( 19 | source, 20 | get_feature_id=JsCode("(f) => { return f.properties.objectid }"), 21 | point_to_layer=JsCode( 22 | "(f, latlng) => { return L.circleMarker(latlng, {radius: 8, fillOpacity: 0.2})}" 23 | ), 24 | container=container, 25 | interval=10000, 26 | ) 27 | rt.add_to(m) 28 | 29 | tmpl_for_expected = Template( 30 | """ 31 | {% macro script(this, kwargs) %} 32 | var {{ this.get_name() }}_options = {{ this.options|tojavascript }}; 33 | {% for key, value in this.functions.items() %} 34 | {{ this.get_name() }}_options["{{key}}"] = {{ value }}; 35 | {% endfor %} 36 | 37 | {% if this.container -%} 38 | {{ this.get_name() }}_options["container"] 39 | = {{ this.container.get_name() }}; 40 | {% endif -%} 41 | 42 | var {{ this.get_name() }} = new L.realtime( 43 | {% if this.src is string or this.src is mapping -%} 44 | {{ this.src|tojson }}, 45 | {% else -%} 46 | {{ this.src.js_code }}, 47 | {% endif -%} 48 | {{ this.get_name() }}_options 49 | ); 50 | {{ this._parent.get_name() }}.addLayer( 51 | {{ this.get_name() }}._container); 52 | {% endmacro %} 53 | """ 54 | ) 55 | expected = normalize(tmpl_for_expected.render(this=rt)) 56 | 57 | out = normalize(m._parent.render()) 58 | 59 | # We verify that imports 60 | assert ( 61 | '' # noqa 62 | in out 63 | ) # noqa 64 | 65 | assert expected in out 66 | -------------------------------------------------------------------------------- /tests/plugins/test_scroll_zoom_toggler.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test ScrollZoomToggler 3 | ---------------------- 4 | """ 5 | 6 | import folium 7 | from folium import plugins 8 | from folium.template import Template 9 | from folium.utilities import normalize 10 | 11 | 12 | def test_scroll_zoom_toggler(): 13 | m = folium.Map([45.0, 3.0], zoom_start=4) 14 | szt = plugins.ScrollZoomToggler() 15 | m.add_child(szt) 16 | 17 | out = normalize(m._parent.render()) 18 | 19 | # Verify that the div has been created. 20 | tmpl = Template( 21 | """ 22 | scroll 26 | """ 27 | ) 28 | assert "".join(tmpl.render(this=szt).split()) in "".join(out.split()) 29 | 30 | # Verify that the style has been created 31 | tmpl = Template( 32 | """ 33 | 46 | """ 47 | ) 48 | expected = normalize(tmpl.render(this=szt)) 49 | assert expected in out 50 | 51 | # Verify that the script is okay. 52 | tmpl = Template( 53 | """ 54 | {{this._parent.get_name()}}.scrollEnabled = true; 55 | 56 | {{this._parent.get_name()}}.toggleScroll = function() { 57 | if (this.scrollEnabled) { 58 | this.scrollEnabled = false; 59 | this.scrollWheelZoom.disable(); 60 | } else { 61 | this.scrollEnabled = true; 62 | this.scrollWheelZoom.enable(); 63 | } 64 | }; 65 | 66 | {{this._parent.get_name()}}.toggleScroll(); 67 | """ 68 | ) 69 | expected = normalize(tmpl.render(this=szt)) 70 | assert expected in out 71 | 72 | bounds = m.get_bounds() 73 | assert bounds == [[None, None], [None, None]], bounds 74 | -------------------------------------------------------------------------------- /tests/plugins/test_semicircle.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test SemiCircle 3 | --------------- 4 | 5 | """ 6 | 7 | import folium 8 | from folium import plugins 9 | from folium.template import Template 10 | from folium.utilities import normalize 11 | 12 | 13 | def test_semicircle(): 14 | m = folium.Map([30.0, 0.0], zoom_start=3) 15 | sc1 = plugins.SemiCircle( 16 | (34, -43), 17 | radius=400000, 18 | arc=300, 19 | direction=20, 20 | color="red", 21 | fill_color="red", 22 | opacity=0, 23 | popup="Direction - 20 degrees, arc 300 degrees", 24 | ) 25 | sc2 = plugins.SemiCircle( 26 | (46, -30), 27 | radius=400000, 28 | start_angle=10, 29 | stop_angle=50, 30 | color="red", 31 | fill_color="red", 32 | opacity=0, 33 | popup="Start angle - 10 degrees, Stop angle - 50 degrees", 34 | ) 35 | 36 | m.add_child(sc1) 37 | m.add_child(sc2) 38 | m._repr_html_() 39 | 40 | out = normalize(m._parent.render()) 41 | 42 | # We verify that the script import is present. 43 | script = '' # noqa 44 | assert script in out 45 | 46 | # We verify that the script part is correct. 47 | tmpl_sc1 = Template( 48 | """ 49 | var {{ this.get_name() }} = L.semiCircle( 50 | {{ this.location|tojson }}, 51 | {{ this.options|tojavascript }} 52 | ) 53 | .setDirection{{ this.direction }} 54 | .addTo({{ this._parent.get_name() }}); 55 | """ 56 | ) 57 | 58 | tmpl_sc2 = Template( 59 | """ 60 | var {{ this.get_name() }} = L.semiCircle( 61 | {{ this.location|tojson }}, 62 | {{ this.options|tojavascript }} 63 | ) 64 | .addTo({{ this._parent.get_name() }}); 65 | """ 66 | ) 67 | assert normalize(tmpl_sc1.render(this=sc1)) in out 68 | assert normalize(tmpl_sc2.render(this=sc2)) in out 69 | 70 | bounds = m.get_bounds() 71 | assert bounds == [[34, -43], [46, -30]], bounds 72 | -------------------------------------------------------------------------------- /tests/plugins/test_terminator.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test Terminator 3 | --------------- 4 | """ 5 | 6 | import folium 7 | from folium import plugins 8 | from folium.template import Template 9 | from folium.utilities import normalize 10 | 11 | 12 | def test_terminator(): 13 | m = folium.Map([45.0, 3.0], zoom_start=1) 14 | t = plugins.Terminator().add_to(m) 15 | 16 | out = normalize(m._parent.render()) 17 | 18 | # Verify that the script is okay. 19 | tmpl = Template("L.terminator().addTo({{this._parent.get_name()}});") 20 | expected = normalize(tmpl.render(this=t)) 21 | assert expected in out 22 | 23 | bounds = m.get_bounds() 24 | assert bounds == [[None, None], [None, None]], bounds 25 | -------------------------------------------------------------------------------- /tests/selenium/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from selenium.webdriver import Chrome, ChromeOptions 3 | from selenium.webdriver.common.by import By 4 | from selenium.webdriver.support.expected_conditions import visibility_of_element_located 5 | from selenium.webdriver.support.ui import WebDriverWait 6 | 7 | 8 | @pytest.fixture(scope="session") 9 | def driver(): 10 | """Pytest fixture that yields a Selenium WebDriver instance""" 11 | driver = DriverFolium() 12 | try: 13 | yield driver 14 | finally: 15 | driver.quit() 16 | 17 | 18 | class DriverFolium(Chrome): 19 | """Selenium WebDriver wrapper that adds folium test specific features.""" 20 | 21 | def __init__(self): 22 | options = ChromeOptions() 23 | options.add_argument("--no-sandbox") 24 | options.add_argument("--disable-dev-shm-usage") 25 | options.add_argument("--disable-gpu") 26 | options.add_argument("--headless") 27 | options.add_argument("--window-size=1024,768") 28 | super().__init__(options=options) 29 | 30 | def get_file(self, filepath): 31 | self.clean_window() 32 | super().get("file://" + filepath) 33 | 34 | def clean_window(self): 35 | """Make sure we have a fresh window (without restarting the browser).""" 36 | # open new tab 37 | self.execute_script("window.open();") 38 | # close old tab 39 | self.close() 40 | # switch to new tab 41 | self.switch_to.window(self.window_handles[0]) 42 | 43 | def verify_js_logs(self): 44 | """Raise an error if there are errors in the browser JS console.""" 45 | logs = self.get_log("browser") 46 | for log in logs: 47 | if log["level"] == "SEVERE": 48 | msg = " ".join(log["message"].split()[2:]) 49 | raise RuntimeError(f'Javascript error: "{msg}".') 50 | 51 | def wait_until(self, css_selector, timeout=10): 52 | """Wait for and return the element(s) selected by css_selector.""" 53 | wait = WebDriverWait(self, timeout=timeout) 54 | is_visible = visibility_of_element_located((By.CSS_SELECTOR, css_selector)) 55 | return wait.until(is_visible) 56 | -------------------------------------------------------------------------------- /tests/selenium/test_geojson_selenium.py: -------------------------------------------------------------------------------- 1 | from selenium.webdriver.common.by import By 2 | 3 | import folium 4 | import folium.plugins 5 | from folium.utilities import temp_html_filepath 6 | 7 | 8 | def test_geojson(driver): 9 | """Verify that loading data in GeoJson works well for different use cases. 10 | 11 | Prevent two regressions: 12 | - https://github.com/python-visualization/folium/pull/1190 13 | - https://github.com/python-visualization/folium/pull/1289 14 | 15 | """ 16 | data_url = "https://cdn.jsdelivr.net/gh/python-visualization/folium@main/examples/data/search_bars_rome.json" 17 | 18 | m = folium.Map((41.9, 12.5), zoom_start=10, tiles="cartodbpositron") 19 | marker_cluster = folium.plugins.MarkerCluster(name="cluster").add_to(m) 20 | folium.GeoJson(data_url, embed=False).add_to(marker_cluster) 21 | folium.GeoJson(data_url, embed=False, show=False, name="geojson").add_to(m) 22 | folium.LayerControl(collapsed=False).add_to(m) 23 | 24 | html = m.get_root().render() 25 | with temp_html_filepath(html) as filepath: 26 | driver.get_file(filepath) 27 | assert driver.wait_until(".folium-map") 28 | driver.verify_js_logs() 29 | # Verify the marker cluster is shown, it's a yellow icon with '18' in it. 30 | icon = driver.wait_until(".leaflet-marker-icon.marker-cluster > div > span") 31 | assert icon.text == "18" 32 | # Verify the second GeoJson layer is not shown, because we used show=False. 33 | control_label = driver.wait_until( 34 | ".leaflet-control-layers-overlays > label:nth-of-type(2)" 35 | ) 36 | assert control_label.text == "geojson" 37 | control_input = control_label.find_element(By.CSS_SELECTOR, value="input") 38 | assert control_input.get_attribute("checked") is None 39 | -------------------------------------------------------------------------------- /tests/selenium/test_heat_map_selenium.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import io 3 | import os 4 | 5 | from PIL import Image 6 | 7 | import folium 8 | from folium.plugins.heat_map import HeatMap 9 | from folium.utilities import temp_html_filepath 10 | 11 | 12 | def test_heat_map_with_weights(driver): 13 | """Verify that HeatMap uses weights in data correctly. 14 | 15 | This test will fail in non-headless mode because window size will be different. 16 | 17 | """ 18 | figure_width, figure_height = 800, 600 19 | m = folium.Map( 20 | (0.5, 0.5), 21 | zoom_start=8, 22 | tiles=None, 23 | width=figure_width, 24 | height=figure_height, 25 | ) 26 | HeatMap( 27 | # make four dots with different weights: 1, 1, 1.5 and 2. 28 | data=[ 29 | (0, 0, 1.5), 30 | (0, 1, 1), 31 | (1, 0, 1), 32 | (1, 1, 2), 33 | ], 34 | radius=70, 35 | blur=50, 36 | ).add_to(m) 37 | html = m.get_root().render() 38 | with temp_html_filepath(html) as filepath: 39 | driver.get_file(filepath) 40 | assert driver.wait_until(".folium-map") 41 | driver.verify_js_logs() 42 | canvas = driver.wait_until("canvas.leaflet-heatmap-layer") 43 | assert canvas 44 | # get the canvas as a PNG base64 string 45 | canvas_base64 = driver.execute_script( 46 | "return arguments[0].toDataURL('image/png').substring(21);", canvas 47 | ) 48 | screenshot_bytes = base64.b64decode(canvas_base64) 49 | screenshot = Image.open(io.BytesIO(screenshot_bytes)) 50 | # window size is not reliable, so crop to a smaller fixed size 51 | screenshot = screenshot.crop((0, 0, figure_width, figure_height)) 52 | path = os.path.dirname(__file__) 53 | with open(os.path.join(path, "test_heat_map_selenium_screenshot.png"), "rb") as f: 54 | screenshot_expected = Image.open(f) 55 | if list(screenshot.getdata()) != list(screenshot_expected.getdata()): 56 | assert False, "screenshot is not as expected" 57 | -------------------------------------------------------------------------------- /tests/selenium/test_heat_map_selenium_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/python-visualization/folium/8e09fb812887860518e7de0eb1e3d539f01a804c/tests/selenium/test_heat_map_selenium_screenshot.png -------------------------------------------------------------------------------- /tests/snapshots/modules/issue_1885.py: -------------------------------------------------------------------------------- 1 | import folium 2 | 3 | # Library of Congress coordinates (latitude, longitude) 4 | loc_coordinates = (38.8886, -77.0047) 5 | 6 | # Create a Folium map centered around the Library of Congress 7 | m = folium.Map(tiles=None, location=loc_coordinates, zoom_start=15) 8 | 9 | # Define the DivIcon with the custom icon. This variable can be used in one marker successfully, but will fail if we use it in two markers. 10 | 11 | 12 | svg = """ 13 | 15 | """ 30 | 31 | icon = folium.DivIcon( 32 | icon_anchor=(15, 15), 33 | html=f"
{svg}
", 34 | ) 35 | 36 | 37 | folium.Marker( 38 | location=(38.886970844230866, -77.00471380332), 39 | popup="Library of Congress: James Madison Building", 40 | icon=icon, 41 | ).add_to(m) 42 | 43 | folium.Marker(location=loc_coordinates, popup="Library of Congress", icon=icon).add_to( 44 | m 45 | ) 46 | -------------------------------------------------------------------------------- /tests/snapshots/modules/issue_1885_add_child.py: -------------------------------------------------------------------------------- 1 | import folium 2 | 3 | # Library of Congress coordinates (latitude, longitude) 4 | loc_coordinates = (38.8886, -77.0047) 5 | 6 | # Create a Folium map centered around the Library of Congress 7 | m = folium.Map(tiles=None, location=loc_coordinates, zoom_start=15) 8 | 9 | # Define the DivIcon with the custom icon. This variable can be used in one marker successfully, but will fail if we use it in two markers. 10 | 11 | 12 | svg = """ 13 | 15 | """ 30 | 31 | icon = folium.DivIcon( 32 | icon_anchor=(15, 15), 33 | html=f"
{svg}
", 34 | ) 35 | 36 | 37 | m1 = ( 38 | folium.Marker( 39 | location=(38.886970844230866, -77.00471380332), 40 | popup="Library of Congress: James Madison Building", 41 | ) 42 | .add_child(icon) 43 | .add_to(m) 44 | ) 45 | 46 | m2 = ( 47 | folium.Marker(location=loc_coordinates, popup="Library of Congress") 48 | .add_child(icon) 49 | .add_to(m) 50 | ) 51 | -------------------------------------------------------------------------------- /tests/snapshots/modules/issue_1885_add_to.py: -------------------------------------------------------------------------------- 1 | import folium 2 | 3 | # Library of Congress coordinates (latitude, longitude) 4 | loc_coordinates = (38.8886, -77.0047) 5 | 6 | # Create a Folium map centered around the Library of Congress 7 | m = folium.Map(tiles=None, location=loc_coordinates, zoom_start=15) 8 | 9 | # Define the DivIcon with the custom icon. This variable can be used in one marker successfully, but will fail if we use it in two markers. 10 | 11 | svg = """ 12 | 14 | """ 29 | 30 | icon = folium.DivIcon( 31 | icon_anchor=(15, 15), 32 | html=f"
{svg}
", 33 | ) 34 | 35 | m1 = folium.Marker( 36 | location=(38.886970844230866, -77.00471380332), 37 | popup="Library of Congress: James Madison Building", 38 | ).add_to(m) 39 | 40 | m2 = folium.Marker( 41 | location=loc_coordinates, 42 | popup="Library of Congress", 43 | ).add_to(m) 44 | # if we save here, everything will be fine. 45 | 46 | icon.add_to(m1) 47 | icon.add_to(m2) 48 | -------------------------------------------------------------------------------- /tests/snapshots/modules/issue_1885_set_icon.py: -------------------------------------------------------------------------------- 1 | import folium 2 | 3 | # Library of Congress coordinates (latitude, longitude) 4 | loc_coordinates = (38.8886, -77.0047) 5 | 6 | # Create a Folium map centered around the Library of Congress 7 | m = folium.Map(tiles=None, location=loc_coordinates, zoom_start=15) 8 | 9 | # Define the DivIcon with the custom icon. This variable can be used in one marker successfully, but will fail if we use it in two markers. 10 | 11 | 12 | svg = """ 13 | 15 | """ 30 | 31 | icon = folium.DivIcon( 32 | icon_anchor=(15, 15), 33 | html=f"
{svg}
", 34 | ) 35 | 36 | marker1 = folium.Marker( 37 | location=(38.886970844230866, -77.00471380332), 38 | popup="Library of Congress: James Madison Building", 39 | ).add_to(m) 40 | 41 | marker2 = folium.Marker( 42 | location=loc_coordinates, popup="Library of Congress", icon=icon 43 | ).add_to(m) 44 | 45 | marker1.set_icon(icon) 46 | marker2.set_icon(icon) 47 | -------------------------------------------------------------------------------- /tests/snapshots/screenshots/screenshot_issue_1885.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/python-visualization/folium/8e09fb812887860518e7de0eb1e3d539f01a804c/tests/snapshots/screenshots/screenshot_issue_1885.png -------------------------------------------------------------------------------- /tests/snapshots/screenshots/screenshot_issue_1885_add_child.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/python-visualization/folium/8e09fb812887860518e7de0eb1e3d539f01a804c/tests/snapshots/screenshots/screenshot_issue_1885_add_child.png -------------------------------------------------------------------------------- /tests/snapshots/screenshots/screenshot_issue_1885_add_to.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/python-visualization/folium/8e09fb812887860518e7de0eb1e3d539f01a804c/tests/snapshots/screenshots/screenshot_issue_1885_add_to.png -------------------------------------------------------------------------------- /tests/snapshots/screenshots/screenshot_issue_1885_set_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/python-visualization/folium/8e09fb812887860518e7de0eb1e3d539f01a804c/tests/snapshots/screenshots/screenshot_issue_1885_set_icon.png -------------------------------------------------------------------------------- /tests/snapshots/screenshots/screenshot_issue_1989.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/python-visualization/folium/8e09fb812887860518e7de0eb1e3d539f01a804c/tests/snapshots/screenshots/screenshot_issue_1989.png -------------------------------------------------------------------------------- /tests/snapshots/screenshots/screenshot_issue_2109.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/python-visualization/folium/8e09fb812887860518e7de0eb1e3d539f01a804c/tests/snapshots/screenshots/screenshot_issue_2109.png -------------------------------------------------------------------------------- /tests/snapshots/test_snapshots.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | import io 3 | import os 4 | import shutil 5 | 6 | import pytest 7 | from PIL import Image 8 | from pixelmatch.contrib.PIL import pixelmatch 9 | from selenium import webdriver 10 | 11 | options = webdriver.chrome.options.Options() 12 | options.add_argument("--headless") 13 | 14 | 15 | paths = os.listdir("tests/snapshots/modules") 16 | paths = [p.replace(".py", "") for p in paths if p.endswith(".py")] 17 | 18 | 19 | @pytest.mark.parametrize("path", paths) 20 | def test_screenshot(path: str): 21 | driver = webdriver.Chrome(options=options) 22 | m = importlib.import_module(f"tests.snapshots.modules.{path}").m 23 | img_data = m._to_png(3, driver=driver, size=(800, 800)) 24 | img_a = Image.open(io.BytesIO(img_data)) 25 | img_a.save(f"/tmp/screenshot_new_{path}.png") 26 | 27 | if os.path.exists(f"tests/snapshots/screenshots/screenshot_{path}.png"): 28 | img_b = Image.open(f"tests/snapshots/screenshots/screenshot_{path}.png") 29 | 30 | img_diff = Image.new("RGBA", img_a.size) 31 | # note how there is no need to specify dimensions 32 | mismatch = pixelmatch(img_a, img_b, img_diff, threshold=0.2, includeAA=False) 33 | 34 | img_diff.save(f"/tmp/screenshot_diff_{path}.png") 35 | m.save(f"/tmp/folium_map_{path}.html") 36 | assert mismatch < 200 37 | 38 | else: 39 | shutil.copy( 40 | f"/tmp/screenshot_new_{path}.png", 41 | f"tests/snapshots/screenshots/screenshot_{path}.png", 42 | ) 43 | raise Exception("no screenshot available, generating new") 44 | -------------------------------------------------------------------------------- /tests/test_jinja.py: -------------------------------------------------------------------------------- 1 | """Verify behavior of Jinja2's `tojson` template filter""" 2 | 3 | import jinja2 4 | import pytest 5 | 6 | 7 | @pytest.mark.parametrize( 8 | "obj, expected", 9 | [ 10 | (True, "true"), 11 | (1, "1"), 12 | (3.14, "3.14"), 13 | ("hi", '"hi"'), 14 | ( 15 | '
content
', 16 | '"\\u003cdiv style=\\"something\\"\\u003econtent\\u003c/div\\u003e"', 17 | ), 18 | ("Mus\u00e9e d'Orsay", '"Mus\\u00e9e d\\u0027Orsay"'), 19 | ([1, 2, 3], "[1, 2, 3]"), 20 | ([1, "hi", False], '[1, "hi", false]'), 21 | ([[0, 0], [1, 1]], "[[0, 0], [1, 1]]"), 22 | ([(0, 0), (1, 1)], "[[0, 0], [1, 1]]"), 23 | ({"hi": "there"}, '{"hi": "there"}'), 24 | ({"hi": {"there": 1, "what": "up"}}, '{"hi": {"there": 1, "what": "up"}}'), 25 | ], 26 | ) 27 | def test_jinja2_tojson(obj, expected): 28 | res = jinja2.Template("{{ obj|tojson }}").render(obj=obj) 29 | assert res == expected 30 | 31 | 32 | @pytest.mark.parametrize( 33 | "obj, expected", 34 | [ 35 | ( 36 | { 37 | "hi": "there", 38 | "what": "isup", 39 | }, 40 | '{\n "hi": "there",\n "what": "isup"\n}', 41 | ), 42 | ( 43 | [(0, 0), (1, 1)], 44 | "[\n [\n 0,\n 0\n ],\n [\n 1,\n 1\n ]\n]", 45 | ), 46 | ], 47 | ) 48 | def test_jinja2_tojson_indented(obj, expected): 49 | res = jinja2.Template("{{ obj|tojson(2) }}").render(obj=obj) 50 | assert res == expected 51 | -------------------------------------------------------------------------------- /tests/test_repr.py: -------------------------------------------------------------------------------- 1 | """ " 2 | Folium _repr_*_ Tests 3 | --------------------- 4 | 5 | """ 6 | 7 | import io 8 | 9 | import PIL.Image 10 | import pytest 11 | 12 | import folium 13 | 14 | 15 | @pytest.fixture 16 | def m(): 17 | yield folium.Map(png_enabled=False) 18 | 19 | 20 | @pytest.fixture 21 | def m_png(): 22 | yield folium.Map(png_enabled=True) 23 | 24 | 25 | def test__repr_html_is_str(m): 26 | html = m._repr_html_() 27 | assert isinstance(html, str) 28 | 29 | 30 | def test_valid_html(m): 31 | html = m._repr_html_() 32 | parts = html.split("><") 33 | assert len(parts) == 7 34 | assert parts[0].lstrip("
" 44 | 45 | 46 | def test__repr_png_no_image(m): 47 | png = m._repr_png_() 48 | assert png is None 49 | 50 | 51 | def test__repr_png_is_bytes(m_png): 52 | png = m_png._repr_png_() 53 | assert isinstance(png, bytes) 54 | 55 | 56 | def test_valid_png(m_png): 57 | png = m_png._repr_png_() 58 | img = PIL.Image.open(io.BytesIO(png)) 59 | assert isinstance(img, PIL.PngImagePlugin.PngImageFile) 60 | 61 | 62 | def test_valid_png_size(m_png): 63 | from folium.utilities import _parse_size 64 | 65 | w = h = 500 66 | m_png.width = _parse_size(w) 67 | m_png.height = _parse_size(h) 68 | png = m_png._repr_png_() 69 | img = PIL.Image.open(io.BytesIO(png)) 70 | assert img.size == (w, h) 71 | -------------------------------------------------------------------------------- /tests/test_template.py: -------------------------------------------------------------------------------- 1 | from branca.element import Element 2 | 3 | from folium import JsCode 4 | from folium.template import Environment, Template, _to_escaped_json, tojavascript 5 | 6 | 7 | def test_tojavascript_with_jscode(): 8 | js_code = JsCode("console.log('Hello, World!')") 9 | assert tojavascript(js_code) == "console.log('Hello, World!')" 10 | 11 | 12 | def test_tojavascript_with_element(): 13 | element = Element() 14 | assert tojavascript(element) == element.get_name() 15 | 16 | 17 | def test_tojavascript_with_dict(): 18 | dict_obj = {"key": "value"} 19 | assert tojavascript(dict_obj) == '{\n "key": "value",\n}' 20 | 21 | 22 | def test_tojavascript_with_dict_with_mixed_key_types(): 23 | dict_obj = {"key": "value", 1: "another value", 3.14: "pi"} 24 | expected = '{\n "key": "value",\n 1: "another value",\n 3.14: "pi",\n}' 25 | assert tojavascript(dict_obj) == expected 26 | 27 | 28 | def test_tojavascript_with_list(): 29 | list_obj = ["value1", "value2"] 30 | assert tojavascript(list_obj) == '[\n"value1",\n"value2",\n]' 31 | 32 | 33 | def test_tojavascript_with_string(): 34 | assert tojavascript("Hello, World!") == _to_escaped_json("Hello, World!") 35 | 36 | 37 | def test_tojavascript_with_combined_elements(): 38 | js_code = JsCode("console.log('Hello, World!')") 39 | element = Element() 40 | combined_dict = { 41 | "key": "value", 42 | "list": ["value1", "value2", element, js_code], 43 | "nested_dict": {"nested_key": "nested_value"}, 44 | } 45 | result = tojavascript(combined_dict) 46 | expected_lines = [ 47 | "{", 48 | ' "key": "value",', 49 | ' "list": [', 50 | '"value1",', 51 | '"value2",', 52 | element.get_name() + ",", 53 | "console.log('Hello, World!'),", 54 | "],", 55 | ' "nestedDict": {', 56 | ' "nestedKey": "nested_value",', 57 | "},", 58 | "}", 59 | ] 60 | for result_line, expected_line in zip(result.splitlines(), expected_lines): 61 | assert result_line == expected_line 62 | 63 | 64 | def test_to_escaped_json(): 65 | assert _to_escaped_json("hi<>&'") == '"hi\\u003c\\u003e\\u0026\\u0027"' 66 | 67 | 68 | def test_environment_filter(): 69 | env = Environment() 70 | assert "tojavascript" in env.filters 71 | 72 | 73 | def test_template_environment_class(): 74 | assert Template.environment_class == Environment 75 | -------------------------------------------------------------------------------- /tests/vegalite_data/vegalite_v1.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://vega.github.io/schema/vega-lite/v1.3.1.json", 3 | "data": { 4 | "values": [ 5 | { 6 | "folium usage": 0, 7 | "happiness": 1 8 | }, 9 | { 10 | "folium usage": 1, 11 | "happiness": 2.718281828459045 12 | }, 13 | { 14 | "folium usage": 2, 15 | "happiness": 7.38905609893065 16 | }, 17 | { 18 | "folium usage": 3, 19 | "happiness": 20.085536923187668 20 | }, 21 | { 22 | "folium usage": 4, 23 | "happiness": 54.598150033144236 24 | }, 25 | { 26 | "folium usage": 5, 27 | "happiness": 148.4131591025766 28 | }, 29 | { 30 | "folium usage": 6, 31 | "happiness": 403.4287934927351 32 | }, 33 | { 34 | "folium usage": 7, 35 | "happiness": 1096.6331584284585 36 | }, 37 | { 38 | "folium usage": 8, 39 | "happiness": 2980.9579870417283 40 | }, 41 | { 42 | "folium usage": 9, 43 | "happiness": 8103.083927575384 44 | } 45 | ] 46 | }, 47 | "encoding": { 48 | "x": { 49 | "field": "folium usage", 50 | "type": "quantitative" 51 | }, 52 | "y": { 53 | "field": "happiness", 54 | "type": "quantitative" 55 | } 56 | }, 57 | "height": 300, 58 | "mark": "point", 59 | "width": 400 60 | } 61 | -------------------------------------------------------------------------------- /tests/vegalite_data/vegalite_vlater.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "view": { 4 | "height": 300, 5 | "width": 400 6 | } 7 | }, 8 | "data": { 9 | "name": "data-aac17e868e23f98b5e0830d45504be45" 10 | }, 11 | "datasets": { 12 | "data-aac17e868e23f98b5e0830d45504be45": [ 13 | { 14 | "folium usage": 0, 15 | "happiness": 1 16 | }, 17 | { 18 | "folium usage": 1, 19 | "happiness": 2.718281828459045 20 | }, 21 | { 22 | "folium usage": 2, 23 | "happiness": 7.38905609893065 24 | }, 25 | { 26 | "folium usage": 3, 27 | "happiness": 20.085536923187668 28 | }, 29 | { 30 | "folium usage": 4, 31 | "happiness": 54.598150033144236 32 | }, 33 | { 34 | "folium usage": 5, 35 | "happiness": 148.4131591025766 36 | }, 37 | { 38 | "folium usage": 6, 39 | "happiness": 403.4287934927351 40 | }, 41 | { 42 | "folium usage": 7, 43 | "happiness": 1096.6331584284585 44 | }, 45 | { 46 | "folium usage": 8, 47 | "happiness": 2980.9579870417283 48 | }, 49 | { 50 | "folium usage": 9, 51 | "happiness": 8103.083927575384 52 | } 53 | ] 54 | }, 55 | "encoding": { 56 | "x": { 57 | "field": "folium usage", 58 | "type": "quantitative" 59 | }, 60 | "y": { 61 | "field": "happiness", 62 | "type": "quantitative" 63 | } 64 | }, 65 | "mark": "point" 66 | } 67 | --------------------------------------------------------------------------------