From 069a011ac4794cba8a438aead5f1318ba76e3352 Mon Sep 17 00:00:00 2001 From: Frank Anema <33519926+Conengmo@users.noreply.github.com> Date: Wed, 6 Sep 2023 11:48:08 +0200 Subject: [PATCH] Deprecate example notebooks (#1798) --- examples/CheckZorder.ipynb | 67 +- ...th Jenks natural breaks optimization.ipynb | 530 +- examples/ClickEvents.ipynb | 503 +- examples/Colormaps.ipynb | 1112 +--- examples/ContinuousWorld.ipynb | 113 +- examples/ControlScale.ipynb | 41 +- examples/CustomIcon.ipynb | 52 +- examples/CustomPanes.ipynb | 170 +- examples/FeatureGroup.ipynb | 40 +- examples/Features.ipynb | 1552 +----- examples/FitOverlays.ipynb | 500 +- examples/FloatImage.ipynb | 40 +- examples/GeoJSONMarker.ipynb | 346 +- examples/GeoJSONWithoutTitles.ipynb | 146 +- examples/GeoJSON_and_choropleth.ipynb | 877 +-- examples/GeoJsonPopupAndTooltip.ipynb | 955 +--- examples/GeodedeticImageOverlay.ipynb | 202 +- examples/Geopandas_and_geo_interface.ipynb | 373 +- examples/Heatmap.ipynb | 47 +- examples/Highlight_Function.ipynb | 156 +- examples/ImageOverlay.ipynb | 293 +- examples/MarkerCluster.ipynb | 331 +- examples/MinMaxLimits.ipynb | 68 +- examples/MiniMap.ipynb | 203 +- examples/Minicharts.ipynb | 233 +- examples/Plugins.ipynb | 4721 +---------------- examples/PolyLineTextPath_AntPath.ipynb | 138 +- examples/Polygons_from_list_of_points.ipynb | 379 +- examples/Popups.ipynb | 1238 +---- examples/Quickstart.ipynb | 2446 +-------- examples/Rotate_icon.ipynb | 44 +- examples/SmoothFactor.ipynb | 69 +- examples/TagFilterButton.ipynb | 749 +-- examples/TilesExample.ipynb | 216 +- examples/TimeSliderChoropleth.ipynb | 943 +--- examples/VectorLayers.ipynb | 494 +- examples/VideoOverlayLayer.ipynb | 41 +- examples/WMS_and_WMTS.ipynb | 65 +- examples/WidthHeight.ipynb | 304 +- examples/WmsTimeDimension.ipynb | 192 +- examples/flask_example.py | 94 +- examples/plugin-Draw.ipynb | 64 +- examples/plugin-DualMap.ipynb | 166 +- examples/plugin-GroupedLayerControl.ipynb | 375 +- examples/plugin-MeasureControl.ipynb | 33 +- examples/plugin-MousePosition.ipynb | 71 +- examples/plugin-PolyLineOffset.ipynb | 264 +- examples/plugin-Search.ipynb | 900 +--- examples/plugin-patterns.ipynb | 68 +- examples/plugin-vector-tiles.ipynb | 196 +- 50 files changed, 302 insertions(+), 22918 deletions(-) diff --git a/examples/CheckZorder.ipynb b/examples/CheckZorder.ipynb index b85c75a7b..fc17685a7 100644 --- a/examples/CheckZorder.ipynb +++ b/examples/CheckZorder.ipynb @@ -1,64 +1,17 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "cell_type": "markdown", "source": [ - "import folium\n", - "import pandas as pd\n", - "\n", - "\n", - "url = (\n", - " \"https://raw.githubusercontent.com/python-visualization/folium/main/examples/data\"\n", - ")\n", - "state_geo = f\"{url}/us-states.json\"\n", - "state_unemployment = f\"{url}/US_Unemployment_Oct2012.csv\"\n", - "\n", - "state_data = pd.read_csv(state_unemployment)\n", - "\n", - "m = folium.Map(location=[48, -102], zoom_start=3, tiles=\"Stamen Toner\")\n", - "\n", - "folium.Choropleth(\n", - " state_geo,\n", - " data=state_data,\n", - " columns=[\"State\", \"Unemployment\"],\n", - " key_on=\"feature.id\",\n", - " fill_color=\"YlGn\",\n", - " fill_opacity=0.7,\n", - " line_opacity=0.2,\n", - " legend_name=\"Unemployment Rate (%)\",\n", - ").add_to(m)\n", - "\n", - "\n", - "popup = \"Must be on top of the choropleth\"\n", - "\n", - "folium.CircleMarker(\n", - " location=[48, -102],\n", - " radius=10,\n", - " fill=True,\n", - " popup=popup,\n", - " weight=1,\n", - ").add_to(m)\n", - "\n", - "\n", - "m" - ] + "We've updated our documentation and removed this notebook.\n", + "You can find the current documentation at https://python-visualization.github.io/folium/latest/." + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } } ], "metadata": { diff --git a/examples/Choropleth with Jenks natural breaks optimization.ipynb b/examples/Choropleth with Jenks natural breaks optimization.ipynb index 37a26db6e..82e89ed81 100644 --- a/examples/Choropleth with Jenks natural breaks optimization.ipynb +++ b/examples/Choropleth with Jenks natural breaks optimization.ipynb @@ -1,534 +1,14 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "aa1bb64d", - "metadata": {}, - "outputs": [], - "source": [ - "import folium\n", - "import numpy as np\n", - "import pandas as pd\n", - "import json\n", - "import requests" - ] - }, - { - "cell_type": "markdown", - "id": "c7fd1292", - "metadata": {}, - "source": [ - "# Integrating Jenks Natural Break Optimization\n", - "\n", - "Choropleths provide an easy way to visually see data distributions across geography. By default, folium uses the breaks created by numpy.histogram (np.histogram), which generally creates an evenly spaced quantiles.\n", - "\n", - "This works well enough for evenly distributed data, but for unevenly distributed data, these even quantiles can obscure more than they show. To demonstrate this, I have created maps showing the labor force of each US state.\n", - "\n", - "The data was taken from the county-level data and aggregated. Since our geographic data does not have areas representing Puerto Rico or the United States as a whole, I removed those entries while keeping Washington, D.C. in our data set. Already, looking at the first five states alphabetically, we can see that Alaska (AK) has a work force roughly 2% the size of California (CA)." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "a199cc25", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
StateCivilian_labor_force_2011
0AK734088
1AL4381044
2AR2739713
3AZ6068526
4CA36769777
\n", - "
" - ], - "text/plain": [ - " State Civilian_labor_force_2011\n", - "0 AK 734088\n", - "1 AL 4381044\n", - "2 AR 2739713\n", - "3 AZ 6068526\n", - "4 CA 36769777" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "url = (\n", - " \"https://raw.githubusercontent.com/python-visualization/folium/main/examples/data\"\n", - ")\n", - "us_states = f\"{url}/us-states.json\"\n", - "\n", - "geo_json_data = json.loads(requests.get(us_states).text)\n", - "\n", - "county_data = pd.read_csv(f\"{url}/us_county_data.csv\")\n", - "clf = 'Civilian_labor_force_2011'\n", - "labor_force = county_data[['State', clf]][\n", - " (county_data[clf].str.strip()!='') & (~county_data['State'].isin(['PR', 'US']))\n", - "]\n", - "labor_force[clf] = labor_force[clf].astype(int)\n", - "labor_force = labor_force.groupby('State').sum().reset_index()\n", - "\n", - "labor_force.head()" - ] - }, { "cell_type": "markdown", - "id": "4b570c1f", - "metadata": {}, "source": [ - "Using default breaks, most states are represented as being part of the bottom quantile. This distribution is similar to what we might expect if US states follow a Power Law or a Zipf distribution." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "8b06b85d", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/advanced_guide/choropleth%20with%20Jenks%20natural%20breaks%20optimization.html" ], - "source": [ - "m = folium.Map(location=[38, -96], zoom_start=4)\n", - "\n", - "folium.Choropleth(\n", - " geo_data=geo_json_data,\n", - " data=labor_force,\n", - " columns=['State', clf],\n", - " key_on='id',\n", - " fill_color='RdBu',\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "id": "4a36162e", - "metadata": {}, - "source": [ - "However, when using Jenks natural Breaks Optimization, we now see more granular detail at the bottom of the distribution, where most of our states are located. The upper western states (Idaho, Montana, Wyoming and the Dakotas) are distinguished from their Midwestern and Mountain West neighbors to the south. Gradations in the deep south between Mississippi and Alabama provide more visual information than in the previous map. Overall, this is a richer representation of the data distribution.\n", - "\n", - "One notable drawback of this representation is the legend. Because the lower bins are smaller, the numerical values overlap, making them unreadable." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "7ac8ccec", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[38, -96], zoom_start=4)\n", - "\n", - "choropleth = folium.Choropleth(\n", - " geo_data=geo_json_data,\n", - " data=labor_force,\n", - " columns=['State', clf],\n", - " key_on='id',\n", - " fill_color='RdBu',\n", - " use_jenks=True,\n", - ")\n", - "choropleth.add_to(m)\n", - "\n", - "choropleth.color_scale.width = 800\n", - "\n", - "m" - ] + "metadata": { + "collapsed": false + } } ], "metadata": { diff --git a/examples/ClickEvents.ipynb b/examples/ClickEvents.ipynb index 3f5d2aebf..f527c8df3 100644 --- a/examples/ClickEvents.ipynb +++ b/examples/ClickEvents.ipynb @@ -1,505 +1,16 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "6b3009b4", - "metadata": {}, - "outputs": [], - "source": [ - "import folium\n", - "from folium.features import ClickForLatLng, ClickForMarker, LatLngPopup" - ] - }, - { - "cell_type": "markdown", - "id": "df990137", - "metadata": {}, - "source": [ - "#### `ClickForMarker` Lets you create markers on each click" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "55e317b4", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "folium.Map().add_child(ClickForMarker())" - ] - }, - { - "cell_type": "markdown", - "id": "ad4a4cfc", - "metadata": {}, - "source": [ - "*Click on the map to see the effects*" - ] - }, - { - "cell_type": "markdown", - "id": "9cecff8c", - "metadata": {}, - "source": [ - "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}`." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "7755ae9b", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "folium.Map().add_child(ClickForMarker(\"Lat: ${lat}
Lon: ${lng}\"))" - ] - }, - { - "cell_type": "markdown", - "id": "45c985b4", - "metadata": {}, - "source": [ - "*Click on the map to see the effects*" - ] - }, - { - "cell_type": "markdown", - "id": "76e5e9b9", - "metadata": {}, - "source": [ - "#### `LatLngPopup` lets you create a simple popup at each click" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "205a9f4a", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "folium.Map().add_child(LatLngPopup())" - ] - }, - { - "cell_type": "markdown", - "id": "c7ed398a", - "metadata": {}, - "source": [ - "*Click on the map to see the effects*" - ] - }, { "cell_type": "markdown", - "id": "74717849", - "metadata": {}, - "source": [ - "#### `ClickForLatLng` lets you copy coordinates to your browser clipboard" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "5c564b6b", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" + "id": "6b3009b4", + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "folium.Map().add_child(ClickForLatLng(format_str='\"[\" + lat + \",\" + lng + \"]\"'))" - ] - }, - { - "cell_type": "markdown", - "id": "8f2809bd", - "metadata": {}, - "source": [ - "*Click on the map to see the effects*" - ] - }, - { - "cell_type": "markdown", - "id": "f90c1e9b", - "metadata": {}, + }, "source": [ - "If you want to collect back the information in python, you may (install and) import the [clipboard](https://github.com/terryyin/clipboard) library :\n", - "\n", - "```python\n", - "> import clipboard\n", - "> clipboard.paste()\n", - "```\n", - "```\n", - "[-43.580391,-123.824467]\n", - "```" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/features/click_related_classes.html" ] } ], diff --git a/examples/Colormaps.ipynb b/examples/Colormaps.ipynb index 1f195f39c..e42b8ea25 100644 --- a/examples/Colormaps.ipynb +++ b/examples/Colormaps.ipynb @@ -2,1115 +2,13 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, "source": [ - "# Using `folium.colormap`\n", - "\n", - "**A few examples of how to use `folium.colormap` in choropleths.**\n", - "\n", - "Let's load a GeoJSON file, and try to choropleth it." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "\n", - "import folium\n", - "import pandas as pd\n", - "import requests\n", - "\n", - "\n", - "url = (\n", - " \"https://raw.githubusercontent.com/python-visualization/folium/main/examples/data\"\n", - ")\n", - "us_states = f\"{url}/us-states.json\"\n", - "US_Unemployment_Oct2012 = f\"{url}/US_Unemployment_Oct2012.csv\"\n", - "\n", - "geo_json_data = json.loads(requests.get(us_states).text)\n", - "unemployment = pd.read_csv(US_Unemployment_Oct2012)\n", - "\n", - "unemployment_dict = unemployment.set_index(\"State\")[\"Unemployment\"]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Self-defined\n", - "\n", - "You can build a choropleth in using a self-defined function.\n", - "It has to output an hexadecimal color string of the form `#RRGGBB` or `#RRGGBBAA`." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "def my_color_function(feature):\n", - " \"\"\"Maps low values to green and high values to red.\"\"\"\n", - " if unemployment_dict[feature[\"id\"]] > 6.5:\n", - " return \"#ff0000\"\n", - " else:\n", - " return \"#008000\"" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/advanced_guide/colormaps.html" ], - "source": [ - "m = folium.Map([43, -100], tiles=\"cartodbpositron\", zoom_start=4)\n", - "\n", - "folium.GeoJson(\n", - " geo_json_data,\n", - " style_function=lambda feature: {\n", - " \"fillColor\": my_color_function(feature),\n", - " \"color\": \"black\",\n", - " \"weight\": 2,\n", - " \"dashArray\": \"5, 5\",\n", - " },\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## StepColormap\n", - "\n", - "But to help you define your colormap, we've embedded `StepColormap` in `folium.colormap`.\n", - "\n", - "You can simply define the colors you want, and the `index` (*thresholds*) that correspond." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "310" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import branca.colormap as cm\n", - "\n", - "step = cm.StepColormap(\n", - " [\"green\", \"yellow\", \"red\"], vmin=3, vmax=10, index=[3, 4, 8, 10], caption=\"step\"\n", - ")\n", - "\n", - "step" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([43, -100], tiles=\"cartodbpositron\", zoom_start=4)\n", - "\n", - "folium.GeoJson(\n", - " geo_json_data,\n", - " style_function=lambda feature: {\n", - " \"fillColor\": step(unemployment_dict[feature[\"id\"]]),\n", - " \"color\": \"black\",\n", - " \"weight\": 2,\n", - " \"dashArray\": \"5, 5\",\n", - " },\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If you specify no index, colors will be set uniformly." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "0.01.0" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cm.StepColormap([\"r\", \"y\", \"g\", \"c\", \"b\", \"m\"])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## LinearColormap\n", - "\n", - "But sometimes, you would prefer to have a *continuous* set of colors. This can be done by `LinearColormap`." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "310" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "linear = cm.LinearColormap([\"green\", \"yellow\", \"red\"], vmin=3, vmax=10)\n", - "\n", - "linear" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([43, -100], tiles=\"cartodbpositron\", zoom_start=4)\n", - "\n", - "folium.GeoJson(\n", - " geo_json_data,\n", - " style_function=lambda feature: {\n", - " \"fillColor\": linear(unemployment_dict[feature[\"id\"]]),\n", - " \"color\": \"black\",\n", - " \"weight\": 2,\n", - " \"dashArray\": \"5, 5\",\n", - " },\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Again, you can set the `index` if you want something irregular." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "0.01.0" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cm.LinearColormap([\"red\", \"orange\", \"yellow\", \"green\"], index=[0, 0.1, 0.9, 1.0])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If you want to transform a linear map into a *step* one, you can use the method `to_step`." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "3.010.0" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "linear.to_step(6)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can also use more sophisticated rules to create the thresholds." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "31100" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "linear.to_step(\n", - " n=6,\n", - " data=[30.6, 50, 51, 52, 53, 54, 55, 60, 70, 100],\n", - " method=\"quantiles\",\n", - " round_method=\"int\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And the opposite is also possible with `to_linear`." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "310" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "step.to_linear()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Built-in\n", - "\n", - "For convenience, we provide a (small) set of built-in linear colormaps, in `folium.colormap.linear`." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "0.01.0" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cm.linear.OrRd_09" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can also use them to generate regular `StepColormap`." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "0.01.0" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cm.linear.PuBuGn_09.to_step(12)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Of course, you may need to scale the colormaps to your bounds. This is doable with `.scale`." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "312" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cm.linear.YlGnBu_09.scale(3, 12)" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "5100" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cm.linear.RdGy_11.to_step(10).scale(5, 100)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "At last, if you want to check them all, simply ask for `linear` in the notebook." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
viridis0.01.0
Pastel1_030.01.0
Pastel1_050.01.0
Pastel1_040.01.0
Pastel1_070.01.0
YlOrRd_040.01.0
Pastel1_090.01.0
Pastel1_080.01.0
Spectral_070.01.0
RdYlBu_050.01.0
PuBuGn_030.01.0
Set1_080.01.0
PuBuGn_050.01.0
PuBuGn_040.01.0
PuBuGn_070.01.0
PuBuGn_060.01.0
PuBuGn_090.01.0
PuBuGn_080.01.0
YlOrBr_040.01.0
YlOrBr_050.01.0
Set1_070.01.0
YlOrBr_030.01.0
Set1_050.01.0
YlOrRd_030.01.0
PuOr_060.01.0
PuOr_070.01.0
PuOr_040.01.0
PuOr_050.01.0
PuOr_030.01.0
Purples_090.01.0
Set2_060.01.0
RdYlBu_110.01.0
PuOr_080.01.0
PuOr_090.01.0
Paired_030.01.0
RdBu_030.01.0
RdYlBu_100.01.0
Paired_070.01.0
Paired_060.01.0
Paired_050.01.0
Paired_040.01.0
Paired_090.01.0
Paired_080.01.0
RdGy_030.01.0
PiYG_040.01.0
Accent_030.01.0
BuGn_080.01.0
BuGn_090.01.0
BuGn_040.01.0
BuGn_050.01.0
BuGn_060.01.0
BuGn_070.01.0
BuGn_030.01.0
YlGnBu_070.01.0
YlGnBu_060.01.0
YlGnBu_050.01.0
YlGnBu_040.01.0
YlGnBu_030.01.0
RdBu_060.01.0
RdBu_050.01.0
RdBu_040.01.0
Accent_080.01.0
RdBu_090.01.0
RdBu_080.01.0
Set2_040.01.0
YlGnBu_090.01.0
YlGnBu_080.01.0
Blues_080.01.0
Blues_090.01.0
RdPu_090.01.0
RdPu_080.01.0
Set3_070.01.0
Set3_060.01.0
RdPu_050.01.0
RdPu_040.01.0
RdPu_070.01.0
RdPu_060.01.0
Blues_060.01.0
Blues_070.01.0
RdPu_030.01.0
Blues_050.01.0
Paired_100.01.0
Paired_110.01.0
Paired_120.01.0
PuBu_060.01.0
PuBu_070.01.0
PuBu_040.01.0
PuBu_050.01.0
PuRd_050.01.0
PuBu_030.01.0
PuRd_070.01.0
PuRd_060.01.0
PuRd_090.01.0
PuRd_080.01.0
Set2_070.01.0
PuBu_080.01.0
PuBu_090.01.0
RdBu_100.01.0
RdBu_110.01.0
Accent_060.01.0
Set3_030.01.0
Set3_050.01.0
Set3_120.01.0
Set3_100.01.0
Set3_040.01.0
RdGy_110.01.0
RdGy_100.01.0
Set1_030.01.0
Set1_090.01.0
Set3_090.01.0
BuPu_080.01.0
BuPu_090.01.0
RdYlGn_110.01.0
Blues_030.01.0
Set2_050.01.0
BuPu_030.01.0
BuPu_060.01.0
BuPu_070.01.0
BuPu_040.01.0
BuPu_050.01.0
Accent_040.01.0
YlOrRd_050.01.0
YlOrBr_080.01.0
Oranges_080.01.0
Oranges_090.01.0
Oranges_060.01.0
Oranges_070.01.0
Oranges_040.01.0
YlOrBr_090.01.0
Oranges_030.01.0
YlOrBr_060.01.0
Dark2_060.01.0
Blues_040.01.0
YlOrBr_070.01.0
RdYlGn_050.01.0
Set3_080.01.0
YlOrRd_060.01.0
Dark2_030.01.0
Accent_050.01.0
RdYlGn_080.01.0
RdYlGn_090.01.0
PuOr_110.01.0
YlOrRd_070.01.0
Spectral_110.01.0
RdGy_080.01.0
RdGy_090.01.0
RdGy_060.01.0
RdGy_070.01.0
RdGy_040.01.0
RdGy_050.01.0
RdYlGn_040.01.0
PiYG_090.01.0
RdYlGn_060.01.0
RdYlGn_070.01.0
Spectral_040.01.0
Spectral_050.01.0
Spectral_060.01.0
PiYG_080.01.0
Set2_030.01.0
Spectral_030.01.0
Reds_080.01.0
Set1_040.01.0
Spectral_080.01.0
Spectral_090.01.0
Set2_080.01.0
Reds_090.01.0
Greys_070.01.0
Greys_060.01.0
Greys_050.01.0
Greys_040.01.0
Greys_030.01.0
PuOr_100.01.0
Accent_070.01.0
Reds_060.01.0
Greys_090.01.0
Greys_080.01.0
Reds_070.01.0
RdYlBu_080.01.0
RdYlBu_090.01.0
BrBG_090.01.0
BrBG_080.01.0
BrBG_070.01.0
BrBG_060.01.0
BrBG_050.01.0
BrBG_040.01.0
BrBG_030.01.0
PiYG_060.01.0
Reds_030.01.0
Set3_110.01.0
Set1_060.01.0
PuRd_030.01.0
PiYG_070.01.0
RdBu_070.01.0
Pastel1_060.01.0
Spectral_100.01.0
PuRd_040.01.0
OrRd_030.01.0
PiYG_030.01.0
Oranges_050.01.0
OrRd_070.01.0
OrRd_060.01.0
OrRd_050.01.0
OrRd_040.01.0
Reds_040.01.0
Reds_050.01.0
OrRd_090.01.0
OrRd_080.01.0
BrBG_100.01.0
BrBG_110.01.0
PiYG_050.01.0
YlOrRd_080.01.0
GnBu_040.01.0
GnBu_050.01.0
GnBu_060.01.0
GnBu_070.01.0
Purples_080.01.0
GnBu_030.01.0
Purples_060.01.0
Purples_070.01.0
Purples_040.01.0
Purples_050.01.0
GnBu_080.01.0
GnBu_090.01.0
YlOrRd_090.01.0
Purples_030.01.0
RdYlBu_040.01.0
PRGn_090.01.0
PRGn_080.01.0
PRGn_070.01.0
PRGn_060.01.0
PRGn_050.01.0
PRGn_040.01.0
PRGn_030.01.0
RdYlBu_060.01.0
RdYlGn_100.01.0
YlGn_080.01.0
YlGn_090.01.0
RdYlBu_070.01.0
PiYG_100.01.0
PiYG_110.01.0
YlGn_030.01.0
YlGn_040.01.0
YlGn_050.01.0
YlGn_060.01.0
YlGn_070.01.0
Dark2_050.01.0
Dark2_040.01.0
Dark2_070.01.0
Pastel2_030.01.0
Pastel2_040.01.0
Pastel2_050.01.0
Pastel2_060.01.0
Pastel2_070.01.0
Pastel2_080.01.0
RdYlBu_030.01.0
Dark2_080.01.0
RdYlGn_030.01.0
PRGn_110.01.0
Greens_080.01.0
Greens_090.01.0
Greens_060.01.0
Greens_070.01.0
Greens_040.01.0
Greens_050.01.0
PRGn_100.01.0
Greens_030.01.0
\n", - " " - ], - "text/plain": [ - "" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cm.linear" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Draw a `ColorMap` on a map\n", - "\n", - "By the way, a ColorMap is also a Folium `Element` that you can draw on a map." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(tiles=\"cartodbpositron\")\n", - "\n", - "colormap = cm.linear.Set1_09.scale(0, 35).to_step(10)\n", - "colormap.caption = \"A colormap caption\"\n", - "m.add_child(colormap)\n", - "\n", - "m" - ] + "metadata": { + "collapsed": false + } } ], "metadata": { diff --git a/examples/ContinuousWorld.ipynb b/examples/ContinuousWorld.ipynb index d2554d85b..3da78e8ac 100644 --- a/examples/ContinuousWorld.ipynb +++ b/examples/ContinuousWorld.ipynb @@ -2,116 +2,13 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, "source": [ - "## Defaults" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import folium\n", - "\n", - "\n", - "m = folium.Map(world_copy_jump=False, no_wrap=False)\n", - "\n", - "folium.Marker(\n", - " location=[0, 0], popup=\"I will disappear when moved outside the wrapped map domain.\"\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## World copy jump" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/advanced_guide/world_copy.html" ], - "source": [ - "m = folium.Map(world_copy_jump=True, no_wrap=False)\n", - "\n", - "folium.Marker(\n", - " location=[0, 0],\n", - " popup=\"I will magically reappear when moved outside the wrapped map domain.\",\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## No wrap" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(\n", - " world_copy_jump=False,\n", - " no_wrap=True,\n", - ")\n", - "\n", - "folium.Marker(location=[0, 0], popup=\"The map domain here is not wrapped!\").add_to(m)\n", - "\n", - "m" - ] + "metadata": { + "collapsed": false + } } ], "metadata": { diff --git a/examples/ControlScale.ipynb b/examples/ControlScale.ipynb index 3df3d26ba..c161a3098 100644 --- a/examples/ControlScale.ipynb +++ b/examples/ControlScale.ipynb @@ -1,41 +1,14 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "cell_type": "markdown", "source": [ - "import folium\n", - "\n", - "\n", - "lon, lat = -38.625, -12.875\n", - "\n", - "zoom_start = 8\n", - "\n", - "m = folium.Map(\n", - " location=[lat, lon],\n", - " tiles=\"OpenStreetMap\",\n", - " zoom_start=zoom_start,\n", - " control_scale=True,\n", - ")\n", - "\n", - "m" - ] + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/map.html#Scale" + ], + "metadata": { + "collapsed": false + } } ], "metadata": { diff --git a/examples/CustomIcon.ipynb b/examples/CustomIcon.ipynb index 0cd8364c7..636eec657 100644 --- a/examples/CustomIcon.ipynb +++ b/examples/CustomIcon.ipynb @@ -1,53 +1,15 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "import folium\n", - "from folium.features import CustomIcon\n", - "\n", - "\n", - "m = folium.Map(location=[45.372, -121.6972], zoom_start=12, tiles=\"Stamen Terrain\")\n", - "\n", - "url = \"http://leafletjs.com/examples/custom-icons/{}\".format\n", - "icon_image = url(\"leaf-red.png\")\n", - "shadow_image = url(\"leaf-shadow.png\")\n", - "\n", - "icon = CustomIcon(\n", - " icon_image,\n", - " icon_size=(38, 95),\n", - " icon_anchor=(22, 94),\n", - " shadow_image=shadow_image,\n", - " shadow_size=(50, 64),\n", - " shadow_anchor=(4, 62),\n", - " popup_anchor=(-3, -76),\n", - ")\n", - "\n", - "marker = folium.Marker(\n", - " location=[45.3288, -121.6625], icon=icon, popup=\"Mt. Hood Meadows\"\n", - ")\n", - "\n", - "\n", - "m.add_child(marker)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/ui_elements/icons.html#Custom-icon" ] } ], diff --git a/examples/CustomPanes.ipynb b/examples/CustomPanes.ipynb index a547b9145..c44289705 100644 --- a/examples/CustomPanes.ipynb +++ b/examples/CustomPanes.ipynb @@ -2,175 +2,13 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, "source": [ - "Load GeoJSON as in [GeoJSON_and_choropleth.ipynb](https://github.com/python-visualization/folium/blob/main/examples/GeoJSON_and_choropleth.ipynb)." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "ExecuteTime": { - "end_time": "2019-04-05T22:38:12.549432Z", - "start_time": "2019-04-05T22:38:12.533446Z" - } - }, - "outputs": [], - "source": [ - "import json\n", - "\n", - "import folium\n", - "import requests\n", - "\n", - "\n", - "url = (\n", - " \"https://raw.githubusercontent.com/python-visualization/folium/main/examples/data\"\n", - ")\n", - "us_states = f\"{url}/us-states.json\"\n", - "geo_json_data = json.loads(requests.get(us_states).text)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Using CustomPane to place labels above choropleth" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Map without custom pane" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "ExecuteTime": { - "end_time": "2019-04-05T22:38:12.758314Z", - "start_time": "2019-04-05T22:38:12.555438Z" - } - }, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/advanced_guide/custom_panes.html" ], - "source": [ - "m = folium.Map([43, -100], zoom_start=4, tiles=\"stamentoner\")\n", - "\n", - "folium.GeoJson(geo_json_data).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Map with custom pane" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "ExecuteTime": { - "end_time": "2019-04-05T22:38:13.237039Z", - "start_time": "2019-04-05T22:38:12.789303Z" - } - }, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([43, -100], zoom_start=4, tiles=\"stamentonerbackground\")\n", - "\n", - "folium.GeoJson(geo_json_data).add_to(m)\n", - "\n", - "folium.map.CustomPane(\"labels\").add_to(m)\n", - "\n", - "# Final layer associated to custom pane via the appropriate kwarg\n", - "folium.TileLayer(\"stamentonerlabels\", pane=\"labels\").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Same, but with a different tileset" - ] - }, - { - "cell_type": "code", - "execution_count": 4, "metadata": { - "ExecuteTime": { - "end_time": "2019-04-05T22:38:13.543862Z", - "start_time": "2019-04-05T22:38:13.241037Z" - } - }, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([43, -100], zoom_start=4, tiles=\"CartoDBPositronNoLabels\")\n", - "\n", - "folium.GeoJson(geo_json_data).add_to(m)\n", - "\n", - "folium.map.CustomPane(\"labels\").add_to(m)\n", - "\n", - "# Final layer associated to custom pane via the appropriate kwarg\n", - "folium.TileLayer(\"CartoDBPositronOnlyLabels\", pane=\"labels\").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "More tile providers can be found at https://leaflet-extras.github.io/leaflet-providers/preview/." - ] + "collapsed": false + } } ], "metadata": { diff --git a/examples/FeatureGroup.ipynb b/examples/FeatureGroup.ipynb index 0179d335d..543ab5c3f 100644 --- a/examples/FeatureGroup.ipynb +++ b/examples/FeatureGroup.ipynb @@ -1,40 +1,14 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "cell_type": "markdown", "source": [ - "from folium import FeatureGroup, LayerControl, Map, Marker\n", - "\n", - "\n", - "m = Map(location=[45.372, -121.6972], zoom_start=12, tiles=\"Stamen Terrain\")\n", - "\n", - "feature_group = FeatureGroup(name=\"Some icons\")\n", - "Marker(location=[45.3288, -121.6625], popup=\"Mt. Hood Meadows\").add_to(feature_group)\n", - "\n", - "Marker(location=[45.3311, -121.7113], popup=\"Timberline Lodge\").add_to(feature_group)\n", - "\n", - "feature_group.add_to(m)\n", - "LayerControl().add_to(m)\n", - "\n", - "m" - ] + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/getting_started.html#Grouping-and-controlling" + ], + "metadata": { + "collapsed": false + } } ], "metadata": { diff --git a/examples/Features.ipynb b/examples/Features.ipynb index 974cf5565..d55d0dac7 100644 --- a/examples/Features.ipynb +++ b/examples/Features.ipynb @@ -2,1554 +2,14 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, - "source": [ - "## ColorLine" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "x = np.linspace(0, 2 * np.pi, 300)\n", - "\n", - "lats = 20 * np.cos(x)\n", - "lons = 20 * np.sin(x)\n", - "colors = np.sin(5 * x)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "import folium\n", - "from folium import features\n", - "\n", - "\n", - "m = folium.Map([0, 0], zoom_start=3)\n", - "\n", - "color_line = features.ColorLine(\n", - " positions=list(zip(lats, lons)),\n", - " colors=colors,\n", - " colormap=[\"y\", \"orange\", \"r\"],\n", - " weight=10,\n", - ")\n", - "\n", - "color_line.add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Marker, Icon, Popup" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([0, 0], zoom_start=1)\n", - "mk = features.Marker([0, 0])\n", - "pp = folium.Popup(\"hello\")\n", - "ic = features.Icon(color=\"red\")\n", - "\n", - "mk.add_child(ic)\n", - "mk.add_child(pp)\n", - "m.add_child(mk)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Vega popup" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import json\n", - "\n", - "import vincent\n", - "\n", - "N = 100\n", - "\n", - "multi_iter2 = {\n", - " \"x\": np.random.uniform(size=(N,)),\n", - " \"y\": np.random.uniform(size=(N,)),\n", - "}\n", - "\n", - "scatter = vincent.Scatter(multi_iter2, iter_idx=\"x\", height=100, width=200)\n", - "data = json.loads(scatter.to_json())\n", - "\n", - "m = folium.Map([0, 0], zoom_start=1)\n", - "mk = features.Marker([0, 0])\n", - "p = folium.Popup(\"Hello\")\n", - "v = features.Vega(data, width=\"100%\", height=\"100%\")\n", - "\n", - "mk.add_child(p)\n", - "p.add_child(v)\n", - "m.add_child(mk)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Vega-Lite popup" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from altair import Chart\n", - "\n", - "import vega_datasets\n", - "\n", - "# load built-in dataset as a pandas DataFrame\n", - "cars = vega_datasets.data.cars()\n", - "\n", - "scatter = (\n", - " Chart(cars)\n", - " .mark_circle()\n", - " .encode(\n", - " x=\"Horsepower\",\n", - " y=\"Miles_per_Gallon\",\n", - " color=\"Origin\",\n", - " )\n", - ")\n", - "\n", - "vega = folium.features.VegaLite(\n", - " scatter,\n", - " width=\"100%\",\n", - " height=\"100%\",\n", - ")\n", - "\n", - "m = folium.Map(location=[-27.5717, -48.6256])\n", - "\n", - "marker = folium.features.Marker([-27.57, -48.62])\n", - "\n", - "popup = folium.Popup()\n", - "\n", - "vega.add_to(popup)\n", - "popup.add_to(marker)\n", - "\n", - "marker.add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Vega div and a Map\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import branca\n", - "\n", - "N = 100\n", - "\n", - "multi_iter2 = {\n", - " \"x\": np.random.uniform(size=(N,)),\n", - " \"y\": np.random.uniform(size=(N,)),\n", - "}\n", - "\n", - "scatter = vincent.Scatter(multi_iter2, iter_idx=\"x\", height=250, width=420)\n", - "data = json.loads(scatter.to_json())\n", - "\n", - "f = branca.element.Figure()\n", - "\n", - "# Create two maps.\n", - "m = folium.Map(\n", - " location=[0, 0],\n", - " tiles=\"stamenwatercolor\",\n", - " zoom_start=1,\n", - " position=\"absolute\",\n", - " left=\"0%\",\n", - " width=\"50%\",\n", - " height=\"50%\",\n", - ")\n", - "\n", - "m2 = folium.Map(\n", - " location=[46, 3],\n", - " tiles=\"OpenStreetMap\",\n", - " zoom_start=4,\n", - " position=\"absolute\",\n", - " left=\"50%\",\n", - " width=\"50%\",\n", - " height=\"50%\",\n", - " top=\"50%\",\n", - ")\n", - "\n", - "# Create two Vega.\n", - "v = features.Vega(data, position=\"absolute\", left=\"50%\", width=\"50%\", height=\"50%\")\n", - "\n", - "v2 = features.Vega(\n", - " data, position=\"absolute\", left=\"0%\", width=\"50%\", height=\"50%\", top=\"50%\"\n", - ")\n", - "\n", - "f.add_child(m)\n", - "f.add_child(m2)\n", - "f.add_child(v)\n", - "f.add_child(v2)\n", - "\n", - "f" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Vega-Lite div and a Map" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "\n", - "N = 100\n", - "\n", - "multi_iter2 = pd.DataFrame(\n", - " {\n", - " \"x\": np.random.uniform(size=(N,)),\n", - " \"y\": np.random.uniform(size=(N,)),\n", - " }\n", - ")\n", - "\n", - "scatter = Chart(multi_iter2).mark_circle().encode(x=\"x\", y=\"y\")\n", - "scatter.width = 420\n", - "scatter.height = 250\n", - "data = json.loads(scatter.to_json())\n", - "\n", - "f = branca.element.Figure()\n", - "\n", - "# Create two maps.\n", - "m = folium.Map(\n", - " location=[0, 0],\n", - " tiles=\"stamenwatercolor\",\n", - " zoom_start=1,\n", - " position=\"absolute\",\n", - " left=\"0%\",\n", - " width=\"50%\",\n", - " height=\"50%\",\n", - ")\n", - "\n", - "m2 = folium.Map(\n", - " location=[46, 3],\n", - " tiles=\"OpenStreetMap\",\n", - " zoom_start=4,\n", - " position=\"absolute\",\n", - " left=\"50%\",\n", - " width=\"50%\",\n", - " height=\"50%\",\n", - " top=\"50%\",\n", - ")\n", - "\n", - "\n", - "# Create two Vega.\n", - "v = features.VegaLite(data, position=\"absolute\", left=\"50%\", width=\"50%\", height=\"50%\")\n", - "\n", - "v2 = features.VegaLite(\n", - " data, position=\"absolute\", left=\"0%\", width=\"50%\", height=\"50%\", top=\"50%\"\n", - ")\n", - "\n", - "f.add_child(m)\n", - "f.add_child(m2)\n", - "f.add_child(v)\n", - "f.add_child(v2)\n", - "\n", - "f" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### GeoJson" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "N = 1000\n", - "\n", - "lons = +5 - np.random.normal(size=N)\n", - "lats = 48 - np.random.normal(size=N)\n", - "\n", - "data = {\n", - " \"type\": \"FeatureCollection\",\n", - " \"features\": [\n", - " {\n", - " \"type\": \"Feature\",\n", - " \"geometry\": {\n", - " \"type\": \"MultiPoint\",\n", - " \"coordinates\": [[lon, lat] for (lat, lon) in zip(lats, lons)],\n", - " },\n", - " \"properties\": {\"prop0\": \"value0\"},\n", - " },\n", - " ],\n", - "}\n", - "\n", - "m = folium.Map([48, 5], zoom_start=6)\n", - "m.add_child(features.GeoJson(data))\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Div" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "N = 100\n", - "\n", - "multi_iter2 = {\n", - " \"x\": np.random.uniform(size=(N,)),\n", - " \"y\": np.random.uniform(size=(N,)),\n", - "}\n", - "\n", - "scatter = vincent.Scatter(multi_iter2, iter_idx=\"x\", height=250, width=420)\n", - "data = json.loads(scatter.to_json())\n", - "\n", - "f = branca.element.Figure()\n", - "\n", - "d1 = f.add_subplot(1, 2, 1)\n", - "d2 = f.add_subplot(1, 2, 2)\n", - "\n", - "d1.add_child(folium.Map([0, 0], tiles=\"stamenwatercolor\", zoom_start=1))\n", - "d2.add_child(folium.Map([46, 3], tiles=\"OpenStreetMap\", zoom_start=5))\n", - "\n", - "f" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### LayerControl" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + }, "source": [ - "m = folium.Map(tiles=None)\n", - "\n", - "folium.raster_layers.TileLayer(\"OpenStreetMap\").add_to(m)\n", - "folium.raster_layers.TileLayer(\"stamentoner\", show=False).add_to(m)\n", - "\n", - "folium.LayerControl(collapsed=False).add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide.html" ] } ], diff --git a/examples/FitOverlays.ipynb b/examples/FitOverlays.ipynb index bb52359cd..ab85d1bc4 100644 --- a/examples/FitOverlays.ipynb +++ b/examples/FitOverlays.ipynb @@ -3,502 +3,14 @@ { "cell_type": "markdown", "id": "14a617e3", - "metadata": {}, - "source": [ - "# FitOverlays\n", - "\n", - "When you add this class to your map, the map will pan and zoom to fit the enabled overlays." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "45275ca3", - "metadata": {}, - "outputs": [], - "source": [ - "from folium import Map, LayerControl, FeatureGroup, Marker, FitOverlays" - ] - }, - { - "cell_type": "markdown", - "id": "fda0a32d", - "metadata": {}, - "source": [ - "In this first map we placed two markers, but they are not in view. You have to pan or zoom out to find them." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "1467934c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def get_map_with_markers():\n", - " m = Map((52, 0), tiles='cartodbpositron', zoom_start=8)\n", - "\n", - " fg1 = FeatureGroup().add_to(m)\n", - " Marker((52, 5)).add_to(fg1)\n", - "\n", - " fg2 = FeatureGroup(show=False).add_to(m)\n", - " Marker((52, 5.1)).add_to(fg2)\n", - "\n", - " LayerControl(collapsed=False).add_to(m)\n", - " \n", - " return m\n", - "\n", - "get_map_with_markers()" - ] - }, - { - "cell_type": "markdown", - "id": "ea497a79", - "metadata": {}, - "source": [ - "Now we add the `FitOverlays` class, which automatically pans and zooms to show the enabled overlays. We show only the first marker by default, if we enable the second marker, the view changes to include it." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "fc47cce2", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "m = get_map_with_markers()\n", - "\n", - "FitOverlays().add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "id": "099d40d3", - "metadata": {}, - "source": [ - "`FitOverlays` has a couple options:\n", - "- `padding` adds pixels around the bounds.\n", - "- `max_zoom` can be used to prevent zooming in too far.\n", - "- `fly` enables a smoother, longer animation, so you can see how the view changes.\n", - "- `fit_on_map_load` can be used to disable the fitting that happens when the map loads.\n", - "\n", - "Note that `padding` and `max_zoom` can achieve the same effect." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "11910053", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + }, "source": [ - "m = get_map_with_markers()\n", - "\n", - "FitOverlays(\n", - " padding=0,\n", - " max_zoom=10,\n", - " fly=True,\n", - " fit_on_map_load=False,\n", - ").add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/features/fit_overlays.html" ] } ], diff --git a/examples/FloatImage.ipynb b/examples/FloatImage.ipynb index 40d4a6ddc..7bd65133b 100644 --- a/examples/FloatImage.ipynb +++ b/examples/FloatImage.ipynb @@ -1,40 +1,14 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "cell_type": "markdown", "source": [ - "import folium\n", - "from folium.plugins import FloatImage\n", - "\n", - "\n", - "url = (\n", - " \"https://raw.githubusercontent.com/ocefpaf/secoora_assets_map/\"\n", - " \"a250729bbcf2ddd12f46912d36c33f7539131bec/secoora_icons/rose.png\"\n", - ")\n", - "\n", - "m = folium.Map([-13, -38.15], zoom_start=10)\n", - "\n", - "FloatImage(url, bottom=40, left=65).add_to(m)\n", - "\n", - "m" - ] + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins/float_image.html" + ], + "metadata": { + "collapsed": false + } } ], "metadata": { diff --git a/examples/GeoJSONMarker.ipynb b/examples/GeoJSONMarker.ipynb index ca9637f1c..d5818ae19 100644 --- a/examples/GeoJSONMarker.ipynb +++ b/examples/GeoJSONMarker.ipynb @@ -2,350 +2,14 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Using GeoJSON Point Features with Markers" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import folium\n", - "import geopandas as gpd" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [], - "source": [ - "rootpath = os.path.abspath(os.getcwd())" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "gdf = gpd.read_file(os.path.join(rootpath, \"data\", \"subwaystations.geojson\"))" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nameurllineobjectidnotesgeometry
0Astor Plhttp://web.mta.info/nyct/service/4-6-6 Express14 nights, 6-all times, 6 Express-weekdays AM s...POINT (-73.99107 40.73005)
1Canal Sthttp://web.mta.info/nyct/service/4-6-6 Express24 nights, 6-all times, 6 Express-weekdays AM s...POINT (-74.00019 40.71880)
250th Sthttp://web.mta.info/nyct/service/1-231-all times, 2-nightsPOINT (-73.98385 40.76173)
3Bergen Sthttp://web.mta.info/nyct/service/2-3-444-nights, 3-all other times, 2-all timesPOINT (-73.97500 40.68086)
4Pennsylvania Avehttp://web.mta.info/nyct/service/3-454-nights, 3-all other timesPOINT (-73.89489 40.66471)
\n", - "
" - ], - "text/plain": [ - " name url line \\\n", - "0 Astor Pl http://web.mta.info/nyct/service/ 4-6-6 Express \n", - "1 Canal St http://web.mta.info/nyct/service/ 4-6-6 Express \n", - "2 50th St http://web.mta.info/nyct/service/ 1-2 \n", - "3 Bergen St http://web.mta.info/nyct/service/ 2-3-4 \n", - "4 Pennsylvania Ave http://web.mta.info/nyct/service/ 3-4 \n", - "\n", - " objectid notes \\\n", - "0 1 4 nights, 6-all times, 6 Express-weekdays AM s... \n", - "1 2 4 nights, 6-all times, 6 Express-weekdays AM s... \n", - "2 3 1-all times, 2-nights \n", - "3 4 4-nights, 3-all other times, 2-all times \n", - "4 5 4-nights, 3-all other times \n", - "\n", - " geometry \n", - "0 POINT (-73.99107 40.73005) \n", - "1 POINT (-74.00019 40.71880) \n", - "2 POINT (-73.98385 40.76173) \n", - "3 POINT (-73.97500 40.68086) \n", - "4 POINT (-73.89489 40.66471) " - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "gdf.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [], - "source": [ - "gdf['href'] = '' + gdf.url + \"\"\n", - "gdf['service_level'] = gdf.notes.str.split(', ').apply(lambda x: len([v for v in x if \"all\" in v]))\n", - "gdf['lines_served'] = gdf.line.str.split('-').apply(lambda x: len(x))" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[1, 2, 3, 0]" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "service_levels = gdf.service_level.unique().tolist()\n", - "service_levels" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [], - "source": [ - "colors = [\"orange\", \"yellow\", \"green\", \"blue\"]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Use a Circle as a Marker" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[40.75, -73.95], zoom_start=13)\n", - "\n", - "folium.GeoJson(\n", - " gdf,\n", - " name=\"Subway Stations\",\n", - " marker=folium.Circle(radius=4, fill_color=\"orange\", fill_opacity=0.4, color=\"black\", weight=1),\n", - " tooltip=folium.GeoJsonTooltip(fields=[\"name\", \"line\", \"notes\"]),\n", - " popup=folium.GeoJsonPopup(fields=[\"name\", \"line\", \"href\", \"notes\"]),\n", - " style_function=lambda x: {\n", - " \"fillColor\": colors[x['properties']['service_level']],\n", - " \"radius\": (x['properties']['lines_served'])*30,\n", - " },\n", - " highlight_function=lambda x: {\"fillOpacity\": 0.8},\n", - " zoom_on_click=True,\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Or use a DivIcon" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[40.75, -73.95], zoom_start=13)\n", - "\n", - "\n", - "def style_function(feature):\n", - " props = feature.get('properties')\n", - " markup = f\"\"\"\n", - " \n", - "
\n", - "
\n", - "
\n", - " {props.get('name')}\n", - "
\n", - "
\n", - " \"\"\"\n", - " return {\"html\": markup}\n", - "\n", - "\n", - "folium.GeoJson(\n", - " gdf,\n", - " name=\"Subway Stations\",\n", - " marker=folium.Marker(icon=folium.DivIcon()),\n", - " tooltip=folium.GeoJsonTooltip(fields=[\"name\", \"line\", \"notes\"]),\n", - " popup=folium.GeoJsonPopup(fields=[\"name\", \"line\", \"href\", \"notes\"]),\n", - " style_function=style_function,\n", - " zoom_on_click=True,\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Use a Marker" - ] - }, - { - "cell_type": "code", - "execution_count": 36, "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "m = folium.Map(location=[40.75, -73.95], zoom_start=13)\n", - "\n", - "marker_colors = [\"red\", \"orange\", \"green\", \"blue\"]\n", - "\n", - "folium.GeoJson(\n", - " gdf,\n", - " name=\"Subway Stations\",\n", - " zoom_on_click=True,\n", - " marker=folium.Marker(icon=folium.Icon(icon='star')),\n", - " tooltip=folium.GeoJsonTooltip(fields=[\"name\", \"line\", \"notes\"]),\n", - " popup=folium.GeoJsonPopup(fields=[\"name\", \"line\", \"href\", \"notes\"]),\n", - " style_function=lambda x: {\n", - " 'markerColor': marker_colors[x['properties']['service_level']],\n", - " },\n", - ").add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/geojson/geojson_marker.html" ] } ], diff --git a/examples/GeoJSONWithoutTitles.ipynb b/examples/GeoJSONWithoutTitles.ipynb index b4a52510a..815e11034 100644 --- a/examples/GeoJSONWithoutTitles.ipynb +++ b/examples/GeoJSONWithoutTitles.ipynb @@ -1,147 +1,15 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import json\n", - "\n", - "\n", - "us_states = os.path.join(\"data\", \"us-states.json\")\n", - "\n", - "with open(us_states) as f:\n", - " states = json.load(f)\n", - "\n", - "kw = {\"location\": [48, -102], \"zoom_start\": 3}" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import folium\n", - "from folium import GeoJson\n", - "\n", - "\n", - "m = folium.Map(tiles=None, **kw)\n", - "\n", - "GeoJson(states).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import branca\n", - "\n", - "# Create a white image of 4 pixels, and embed it in a url.\n", - "white_tile = branca.utilities.image_to_url([[1, 1], [1, 1]])\n", - "\n", - "# Create a map using this url for each tile.\n", - "m = folium.Map(tiles=white_tile, attr=\"white tile\", **kw)\n", - "\n", - "GeoJson(states).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "images = [[(-1) ** ((i + j) // 30) for i in range(300)] for j in range(300)]\n", - "\n", - "tiles = branca.utilities.image_to_url(images)\n", - "\n", - "m = folium.Map(tiles=tiles, attr=\"Just because we can\", **kw)\n", - "\n", - "GeoJson(states).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "images = [[(-1) ** ((i // 30 + j // 30)) for i in range(300)] for j in range(300)]\n", - "\n", - "tiles = branca.utilities.image_to_url(images)\n", - "\n", - "m = folium.Map(tiles=tiles, attr=\"Just because we can\", **kw)\n", - "\n", - "GeoJson(states).add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/advanced_guide/custom_tiles.html" ] } ], diff --git a/examples/GeoJSON_and_choropleth.ipynb b/examples/GeoJSON_and_choropleth.ipynb index 2ae897ea2..6be025d54 100644 --- a/examples/GeoJSON_and_choropleth.ipynb +++ b/examples/GeoJSON_and_choropleth.ipynb @@ -2,882 +2,13 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, "source": [ - "# GeoJSON and choropleth\n", - "\n", - "**A few examples of how to do that with `folium`.**\n", - "\n", - "\n", - "## Using `GeoJson`\n", - "\n", - "### Loading data\n", - "\n", - "Let us load a GeoJSON file representing the US states." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "\n", - "import requests\n", - "\n", - "url = (\n", - " \"https://raw.githubusercontent.com/python-visualization/folium/main/examples/data\"\n", - ")\n", - "us_states = f\"{url}/us-states.json\"\n", - "\n", - "geo_json_data = json.loads(requests.get(us_states).text)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "It is a classical GeoJSON `FeatureCollection` (see https://en.wikipedia.org/wiki/GeoJSON) of the form :\n", - "\n", - " {\n", - " \"type\": \"FeatureCollection\",\n", - " \"features\": [\n", - " {\n", - " \"properties\": {\"name\": \"Alabama\"},\n", - " \"id\": \"AL\",\n", - " \"type\": \"Feature\",\n", - " \"geometry\": {\n", - " \"type\": \"Polygon\",\n", - " \"coordinates\": [[[-87.359296, 35.00118], ...]]\n", - " }\n", - " },\n", - " {\n", - " \"properties\": {\"name\": \"Alaska\"},\n", - " \"id\": \"AK\",\n", - " \"type\": \"Feature\",\n", - " \"geometry\": {\n", - " \"type\": \"MultiPolygon\",\n", - " \"coordinates\": [[[[-131.602021, 55.117982], ... ]]]\n", - " }\n", - " },\n", - " ...\n", - " ]\n", - " }\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A first way of drawing it on a map, is simply to use `folium.GeoJson` :" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import folium\n", - "\n", - "\n", - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "folium.GeoJson(geo_json_data).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that you can avoid loading the file on yourself ; in simply providing a file path." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "folium.GeoJson(us_states).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can pass a geopandas object." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import geopandas\n", - "\n", - "gdf = geopandas.read_file(us_states)\n", - "\n", - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "folium.GeoJson(\n", - " gdf,\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Click on zoom\n", - "\n", - "You can enable an option that if you click on a part of the geometry the map will zoom in to that.\n", - "\n", - "Try it on the map below:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "folium.GeoJson(geo_json_data, zoom_on_click=True).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Styling\n", - "\n", - "Now this is cool and simple, but we may be willing to choose the style of the data.\n", - "\n", - "You can provide a function of the form `lambda feature: {}` that sets the style of each feature.\n", - "\n", - "For possible options, see:\n", - "\n", - "* For `Point` and `MultiPoint`, see http://leafletjs.com/reference.html#marker\n", - "* For other features, see http://leafletjs.com/reference.html#path-options and http://leafletjs.com/reference.html#polyline-options\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "folium.GeoJson(\n", - " geo_json_data,\n", - " style_function=lambda feature: {\n", - " \"fillColor\": \"#ffff00\",\n", - " \"color\": \"black\",\n", - " \"weight\": 2,\n", - " \"dashArray\": \"5, 5\",\n", - " },\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "What's cool in providing a function, is that you can specify a style depending on the feature. For example, if you want to visualize in green all states whose name contains the letter 'E', just do:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "folium.GeoJson(\n", - " geo_json_data,\n", - " style_function=lambda feature: {\n", - " \"fillColor\": \"green\"\n", - " if \"e\" in feature[\"properties\"][\"name\"].lower()\n", - " else \"#ffff00\",\n", - " \"color\": \"black\",\n", - " \"weight\": 2,\n", - " \"dashArray\": \"5, 5\",\n", - " },\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Wow, this looks almost like a choropleth. To do one, we just need to compute a color for each state.\n", - "\n", - "Let's imagine we want to draw a choropleth of unemployment in the US.\n", - "\n", - "First, we may load the data:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
StateUnemployment
0AL7.1
1AK6.8
2AZ8.1
3AR7.2
4CA10.1
\n", - "
" - ], - "text/plain": [ - " State Unemployment\n", - "0 AL 7.1\n", - "1 AK 6.8\n", - "2 AZ 8.1\n", - "3 AR 7.2\n", - "4 CA 10.1" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "\n", - "US_Unemployment_Oct2012 = f\"{url}/US_Unemployment_Oct2012.csv\"\n", - "unemployment = pd.read_csv(US_Unemployment_Oct2012)\n", - "\n", - "unemployment.head(5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we need to create a function that maps one value to a RGB color (of the form `#RRGGBB`).\n", - "For this, we'll use colormap tools from `folium.colormap`." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#d8f0a3ff\n" - ] - }, - { - "data": { - "text/html": [ - "3.210.3" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from branca.colormap import linear\n", - "\n", - "colormap = linear.YlGn_09.scale(\n", - " unemployment.Unemployment.min(), unemployment.Unemployment.max()\n", - ")\n", - "\n", - "print(colormap(5.0))\n", - "\n", - "colormap" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We need also to convert the table into a dictionary, in order to map a feature to it's unemployment value." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "7.1" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/geojson.html" ], - "source": [ - "unemployment_dict = unemployment.set_index(\"State\")[\"Unemployment\"]\n", - "\n", - "unemployment_dict[\"AL\"]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can do the choropleth." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "folium.GeoJson(\n", - " geo_json_data,\n", - " name=\"unemployment\",\n", - " style_function=lambda feature: {\n", - " \"fillColor\": colormap(unemployment_dict[feature[\"id\"]]),\n", - " \"color\": \"black\",\n", - " \"weight\": 1,\n", - " \"dashArray\": \"5, 5\",\n", - " \"fillOpacity\": 0.9,\n", - " },\n", - ").add_to(m)\n", - "\n", - "folium.LayerControl().add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Of course, if you can create and/or use a dictionary providing directly the good color. Thus, the finishing seems faster:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "color_dict = {key: colormap(unemployment_dict[key]) for key in unemployment_dict.keys()}" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "folium.GeoJson(\n", - " geo_json_data,\n", - " style_function=lambda feature: {\n", - " \"fillColor\": color_dict[feature[\"id\"]],\n", - " \"color\": \"black\",\n", - " \"weight\": 1,\n", - " \"dashArray\": \"5, 5\",\n", - " \"fillOpacity\": 0.9,\n", - " },\n", - ").add_to(m)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that adding a color legend may be a good idea." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "colormap.caption = \"Unemployment color scale\"\n", - "colormap.add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Using `Choropleth` class\n", - "\n", - "Now if you want to get faster, you can use the `Choropleth` class. Have a look at it's docstring, it has several styling options.\n", - "\n", - "Just like the `GeoJson` class you can provide it a filename, a dict, or a geopandas object." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "folium.Choropleth(\n", - " geo_data=us_states,\n", - " fill_opacity=0.3,\n", - " line_weight=2,\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Then, in playing with keyword arguments, you can get a choropleth in a few lines:" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "folium.Choropleth(\n", - " geo_data=us_states,\n", - " data=unemployment,\n", - " columns=[\"State\", \"Unemployment\"],\n", - " key_on=\"feature.id\",\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can force the color scale to a given number of bins (or directly list the bins you would like), by providing the `bins` argument." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "folium.Choropleth(\n", - " geo_data=us_states,\n", - " data=unemployment,\n", - " columns=[\"State\", \"Unemployment\"],\n", - " key_on=\"feature.id\",\n", - " fill_color=\"YlGn\",\n", - " bins=[3, 4, 9, 11],\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can also enable the highlight function, to enable highlight functionality when you hover over each area." - ] - }, - { - "cell_type": "code", - "execution_count": 18, "metadata": { - "scrolled": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "state_data = pd.read_csv(US_Unemployment_Oct2012)\n", - "\n", - "m = folium.Map(location=[48, -102], zoom_start=3)\n", - "folium.Choropleth(\n", - " geo_data=us_states,\n", - " data=state_data,\n", - " columns=[\"State\", \"Unemployment\"],\n", - " key_on=\"feature.id\",\n", - " fill_color=\"YlGn\",\n", - " fill_opacity=0.7,\n", - " line_opacity=0.2,\n", - " legend_name=\"Unemployment Rate (%)\",\n", - " highlight=True,\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can customize the way missing and `nan` values are displayed on your map using the two parameters `nan_fill_color` and `nan_fill_opacity`." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "scrolled": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "messed_up_data = unemployment.drop(0)\n", - "messed_up_data.loc[4, \"Unemployment\"] = float(\"nan\")\n", - "\n", - "folium.Choropleth(\n", - " geo_data=us_states,\n", - " data=messed_up_data,\n", - " columns=[\"State\", \"Unemployment\"],\n", - " nan_fill_color=\"purple\",\n", - " nan_fill_opacity=0.4,\n", - " key_on=\"feature.id\",\n", - " fill_color=\"YlGn\",\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Internally Choropleth uses the `GeoJson` or `TopoJson` class, depending on your settings, and the `StepColormap` class. Both objects are attributes of your `Choropleth` object called `geojson` and `color_scale`. You can make changes to them, but for regular things you won't have to. For example setting a name for in the layer controls or disabling showing the layer on opening the map is possible in `Choropleth` itself." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n" - ] - }, - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "choropleth = folium.Choropleth(\n", - " geo_data=us_states,\n", - " data=state_data,\n", - " columns=[\"State\", \"Unemployment\"],\n", - " key_on=\"feature.id\",\n", - " fill_color=\"YlGn\",\n", - " name=\"Unenployment\",\n", - " show=False,\n", - ").add_to(m)\n", - "\n", - "# The underlying GeoJson and StepColormap objects are reachable\n", - "print(type(choropleth.geojson))\n", - "print(type(choropleth.color_scale))\n", - "\n", - "folium.LayerControl(collapsed=False).add_to(m)\n", - "\n", - "m" - ] + "collapsed": false + } } ], "metadata": { diff --git a/examples/GeoJsonPopupAndTooltip.ipynb b/examples/GeoJsonPopupAndTooltip.ipynb index 6b7366e5c..dac3ddee9 100644 --- a/examples/GeoJsonPopupAndTooltip.ipynb +++ b/examples/GeoJsonPopupAndTooltip.ipynb @@ -1,956 +1,15 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "\n", - "\n", - "income = pd.read_csv(\n", - " \"https://raw.githubusercontent.com/pri-data/50-states/master/data/income-counties-states-national.csv\",\n", - " dtype={\"fips\": str},\n", - ")\n", - "income[\"income-2015\"] = pd.to_numeric(income[\"income-2015\"], errors=\"coerce\")" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
fipscountystateincome-2015income-1989aincome-1989bchange
000000USUS55775.02890653367.281024.316843
101000AlabamaAL44833.02220240990.118778.571546
201001Autauga CountyAL56580.02689849660.0403012.230399
301003Baldwin CountyAL52387.02404344389.0381815.267074
401005Barbour CountyAL31433.01867334474.75398-9.676945
\n", - "
" - ], - "text/plain": [ - " fips county state income-2015 income-1989a income-1989b \n", - "0 00000 US US 55775.0 28906 53367.28102 \\\n", - "1 01000 Alabama AL 44833.0 22202 40990.11877 \n", - "2 01001 Autauga County AL 56580.0 26898 49660.04030 \n", - "3 01003 Baldwin County AL 52387.0 24043 44389.03818 \n", - "4 01005 Barbour County AL 31433.0 18673 34474.75398 \n", - "\n", - " change \n", - "0 4.316843 \n", - "1 8.571546 \n", - "2 12.230399 \n", - "3 15.267074 \n", - "4 -9.676945 " - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "income.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
geometryname
0POLYGON ((-87.35930 35.00118, -85.60667 34.984...Alabama
1MULTIPOLYGON (((-131.60202 55.11798, -131.5691...Alaska
2POLYGON ((-109.04250 37.00026, -109.04798 31.3...Arizona
3POLYGON ((-94.47384 36.50186, -90.15254 36.496...Arkansas
4POLYGON ((-123.23326 42.00619, -122.37885 42.0...California
\n", - "
" - ], - "text/plain": [ - " geometry name\n", - "0 POLYGON ((-87.35930 35.00118, -85.60667 34.984... Alabama\n", - "1 MULTIPOLYGON (((-131.60202 55.11798, -131.5691... Alaska\n", - "2 POLYGON ((-109.04250 37.00026, -109.04798 31.3... Arizona\n", - "3 POLYGON ((-94.47384 36.50186, -90.15254 36.496... Arkansas\n", - "4 POLYGON ((-123.23326 42.00619, -122.37885 42.0... California" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import requests\n", - "import geopandas\n", - "\n", - "\n", - "response = requests.get(\n", - " \"https://raw.githubusercontent.com/python-visualization/folium/main/examples/data/us-states.json\"\n", - ")\n", - "data = response.json()\n", - "states = geopandas.GeoDataFrame.from_features(data, crs=\"EPSG:4326\")\n", - "\n", - "states.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
namealpha-2
0AlabamaAL
1AlaskaAK
2ArizonaAZ
\n", - "
" - ], - "text/plain": [ - " name alpha-2\n", - "0 Alabama AL\n", - "1 Alaska AK\n", - "2 Arizona AZ" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "response = requests.get(\n", - " \"https://gist.githubusercontent.com/tvpmb/4734703/raw/\"\n", - " \"b54d03154c339ed3047c66fefcece4727dfc931a/US%2520State%2520List\"\n", - ")\n", - "abbrs = pd.read_json(response.text)\n", - "\n", - "abbrs.head(3)" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
geometrynamealpha-2
0POLYGON ((-87.35930 35.00118, -85.60667 34.984...AlabamaAL
1MULTIPOLYGON (((-131.60202 55.11798, -131.5691...AlaskaAK
2POLYGON ((-109.04250 37.00026, -109.04798 31.3...ArizonaAZ
3POLYGON ((-94.47384 36.50186, -90.15254 36.496...ArkansasAR
4POLYGON ((-123.23326 42.00619, -120.00186 41.9...CaliforniaCA
\n", - "
" - ], - "text/plain": [ - " geometry name alpha-2\n", - "0 POLYGON ((-87.35930 35.00118, -85.60667 34.984... Alabama AL\n", - "1 MULTIPOLYGON (((-131.60202 55.11798, -131.5691... Alaska AK\n", - "2 POLYGON ((-109.04250 37.00026, -109.04798 31.3... Arizona AZ\n", - "3 POLYGON ((-94.47384 36.50186, -90.15254 36.496... Arkansas AR\n", - "4 POLYGON ((-123.23326 42.00619, -120.00186 41.9... California CA" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "statesmerge = states.merge(abbrs, how=\"left\", left_on=\"name\", right_on=\"name\")\n", - "statesmerge[\"geometry\"] = statesmerge.geometry.simplify(0.05)\n", - "\n", - "statesmerge.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "state\n", - "AK 62561.5\n", - "AL 38721.5\n", - "AR 37890.0\n", - "AZ 43810.0\n", - "CA 53341.0\n", - "Name: income-2015, dtype: float64" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "income.groupby(\"state\")[\"income-2015\"].median().head()" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "statesmerge[\"medianincome\"] = statesmerge.merge(\n", - " income.groupby(\"state\")[\"income-2015\"].median(),\n", - " how=\"left\",\n", - " left_on=\"alpha-2\",\n", - " right_on=\"state\",\n", - ")[\"income-2015\"]\n", - "statesmerge[\"change\"] = statesmerge.merge(\n", - " income.groupby(\"state\")[\"change\"].median(),\n", - " how=\"left\",\n", - " left_on=\"alpha-2\",\n", - " right_on=\"state\",\n", - ")[\"change\"]" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
geometrynamealpha-2medianincomechange
0POLYGON ((-87.35930 35.00118, -85.60667 34.984...AlabamaAL38721.52.779114
1MULTIPOLYGON (((-131.60202 55.11798, -131.5691...AlaskaAK62561.514.758367
2POLYGON ((-109.04250 37.00026, -109.04798 31.3...ArizonaAZ43810.0NaN
3POLYGON ((-94.47384 36.50186, -90.15254 36.496...ArkansasAR37890.010.897394
4POLYGON ((-123.23326 42.00619, -120.00186 41.9...CaliforniaCA53341.06.716596
\n", - "
" - ], - "text/plain": [ - " geometry name alpha-2 \n", - "0 POLYGON ((-87.35930 35.00118, -85.60667 34.984... Alabama AL \\\n", - "1 MULTIPOLYGON (((-131.60202 55.11798, -131.5691... Alaska AK \n", - "2 POLYGON ((-109.04250 37.00026, -109.04798 31.3... Arizona AZ \n", - "3 POLYGON ((-94.47384 36.50186, -90.15254 36.496... Arkansas AR \n", - "4 POLYGON ((-123.23326 42.00619, -120.00186 41.9... California CA \n", - "\n", - " medianincome change \n", - "0 38721.5 2.779114 \n", - "1 62561.5 14.758367 \n", - "2 43810.0 NaN \n", - "3 37890.0 10.897394 \n", - "4 53341.0 6.716596 " - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "statesmerge.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "43969.375" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "statesmerge[\"medianincome\"].quantile(0.25)" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [], - "source": [ - "import branca\n", - "\n", - "\n", - "colormap = branca.colormap.LinearColormap(\n", - " vmin=statesmerge[\"change\"].quantile(0.0),\n", - " vmax=statesmerge[\"change\"].quantile(1),\n", - " colors=[\"red\", \"orange\", \"lightblue\", \"green\", \"darkgreen\"],\n", - " caption=\"State Level Median County Household Income (%)\",\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], + }, "source": [ - "import folium\n", - "from folium.features import GeoJsonPopup, GeoJsonTooltip\n", - "\n", - "\n", - "m = folium.Map(location=[35.3, -97.6], zoom_start=4)\n", - "\n", - "popup = GeoJsonPopup(\n", - " fields=[\"name\", \"change\"],\n", - " aliases=[\"State\", \"% Change\"],\n", - " localize=True,\n", - " labels=True,\n", - " style=\"background-color: yellow;\",\n", - ")\n", - "\n", - "tooltip = GeoJsonTooltip(\n", - " fields=[\"name\", \"medianincome\", \"change\"],\n", - " aliases=[\"State:\", \"2015 Median Income(USD):\", \"Median % Change:\"],\n", - " localize=True,\n", - " sticky=False,\n", - " labels=True,\n", - " style=\"\"\"\n", - " background-color: #F0EFEF;\n", - " border: 2px solid black;\n", - " border-radius: 3px;\n", - " box-shadow: 3px;\n", - " \"\"\",\n", - " max_width=800,\n", - ")\n", - "\n", - "\n", - "g = folium.GeoJson(\n", - " statesmerge,\n", - " style_function=lambda x: {\n", - " \"fillColor\": colormap(x[\"properties\"][\"change\"])\n", - " if x[\"properties\"][\"change\"] is not None\n", - " else \"transparent\",\n", - " \"color\": \"black\",\n", - " \"fillOpacity\": 0.4,\n", - " },\n", - " tooltip=tooltip,\n", - " popup=popup,\n", - ").add_to(m)\n", - "\n", - "colormap.add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/geojson/geojson_popup_and_tooltip.html" ] } ], diff --git a/examples/GeodedeticImageOverlay.ipynb b/examples/GeodedeticImageOverlay.ipynb index 348c553ce..dd9580857 100644 --- a/examples/GeodedeticImageOverlay.ipynb +++ b/examples/GeodedeticImageOverlay.ipynb @@ -1,206 +1,14 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "\n", - "def sample_data(shape=(73, 145)):\n", - " nlats, nlons = shape\n", - " lats = np.linspace(-np.pi / 2, np.pi / 2, nlats)\n", - " lons = np.linspace(0, 2 * np.pi, nlons)\n", - " lons, lats = np.meshgrid(lons, lats)\n", - " wave = 0.75 * (np.sin(2 * lats) ** 8) * np.cos(4 * lons)\n", - " mean = 0.5 * np.cos(2 * lats) * ((np.sin(2 * lats)) ** 2 + 2)\n", - "\n", - " lats = np.rad2deg(lats)\n", - " lons = np.rad2deg(lons)\n", - " data = wave + mean\n", - "\n", - " return lons, lats, data\n", - "\n", - "\n", - "lon, lat, data = sample_data(shape=(73, 145))\n", - "lon -= 180" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "\n", - "import matplotlib\n", - "\n", - "cm = matplotlib.cm.get_cmap(\"cubehelix\")\n", - "\n", - "normed_data = (data - data.min()) / (data.max() - data.min())\n", - "colored_data = cm(normed_data)" - ] - }, { "cell_type": "markdown", - "metadata": {}, "source": [ - "# Bad" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/advanced_guide/geodedetic_image_overlay.html" ], - "source": [ - "import folium\n", - "\n", - "\n", - "m = folium.Map(location=[lat.mean(), lon.mean()], zoom_start=1)\n", - "\n", - "folium.raster_layers.ImageOverlay(\n", - " image=colored_data,\n", - " bounds=[[lat.min(), lon.min()], [lat.max(), lon.max()]],\n", - " opacity=0.25,\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Good" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[lat.mean(), lon.mean()], zoom_start=1)\n", - "\n", - "folium.raster_layers.ImageOverlay(\n", - " image=colored_data,\n", - " bounds=[[lat.min(), lon.min()], [lat.max(), lon.max()]],\n", - " mercator_project=True,\n", - " opacity=0.25,\n", - ").add_to(m)\n", - "\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Same as above but with cartopy" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import cartopy.crs as ccrs\n", - "from cartopy.img_transform import warp_array\n", - "\n", - "source_extent = [lon.min(), lon.max(), lat.min(), lat.max()]\n", - "\n", - "new_data = warp_array(\n", - " colored_data,\n", - " target_proj=ccrs.GOOGLE_MERCATOR,\n", - " source_proj=ccrs.PlateCarree(),\n", - " target_res=data.shape,\n", - " source_extent=source_extent,\n", - " target_extent=None,\n", - " mask_extrapolated=False,\n", - ")\n", - "\n", - "\n", - "m = folium.Map(location=[lat.mean(), lon.mean()], zoom_start=1)\n", - "\n", - "folium.raster_layers.ImageOverlay(\n", - " image=new_data[0],\n", - " bounds=[[lat.min(), lon.min()], [lat.max(), lon.max()]],\n", - " opacity=0.25,\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "TODO: Try [rasterio](https://github.com/mapbox/rasterio/blob/ca75cf0a842943c1b3da4522e6ea3500215130fd/docs/reproject.rst). Rasterio can warp images and arrays." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Compare to original" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "From https://scitools.org.uk/cartopy/docs/latest/gallery/waves.html\n", - "\n", - "![](https://scitools.org.uk/cartopy/docs/latest/_images/sphx_glr_waves_001.png)" - ] + "metadata": { + "collapsed": false + } } ], "metadata": { diff --git a/examples/Geopandas_and_geo_interface.ipynb b/examples/Geopandas_and_geo_interface.ipynb index 93a870819..3225e08a5 100644 --- a/examples/Geopandas_and_geo_interface.ipynb +++ b/examples/Geopandas_and_geo_interface.ipynb @@ -2,375 +2,14 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, - "source": [ - "# How to draw a GeoPandas.GeoDataFrame into folium\n", - "\n", - "GeoPandas is a project to add support for geographic data to [pandas](http://pandas.pydata.org) objects.\n", - "(See https://github.com/geopandas/geopandas)\n", - "\n", - "It provides (among other cool things) a `GeoDataFrame` object that represents a Feature collection.\n", - "When you have one, you may be willing to use it on a folium map. Here's the simplest way to do so." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In this example, we'll use the same file as GeoPandas demo ; it's containing\n", - "[the boroughs of New York City](http://www.nyc.gov/html/dcp/download/bytes/nybb_14aav.zip)." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
BoroCodeBoroNameShape_LengShape_Areageometry
05Staten Island330454.1759331.623847e+09MULTIPOLYGON (((970217.022 145643.332, 970227....
13Brooklyn741227.3370731.937810e+09MULTIPOLYGON (((1021176.479 151374.797, 102100...
24Queens896875.3964493.045079e+09MULTIPOLYGON (((1029606.077 156073.814, 102957...
31Manhattan358400.9128366.364308e+08MULTIPOLYGON (((981219.056 188655.316, 980940....
42Bronx464475.1456511.186822e+09MULTIPOLYGON (((1012821.806 229228.265, 101278...
\n", - "
" - ], - "text/plain": [ - " BoroCode BoroName Shape_Leng Shape_Area \\\n", - "0 5 Staten Island 330454.175933 1.623847e+09 \n", - "1 3 Brooklyn 741227.337073 1.937810e+09 \n", - "2 4 Queens 896875.396449 3.045079e+09 \n", - "3 1 Manhattan 358400.912836 6.364308e+08 \n", - "4 2 Bronx 464475.145651 1.186822e+09 \n", - "\n", - " geometry \n", - "0 MULTIPOLYGON (((970217.022 145643.332, 970227.... \n", - "1 MULTIPOLYGON (((1021176.479 151374.797, 102100... \n", - "2 MULTIPOLYGON (((1029606.077 156073.814, 102957... \n", - "3 MULTIPOLYGON (((981219.056 188655.316, 980940.... \n", - "4 MULTIPOLYGON (((1012821.806 229228.265, 101278... " - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "import geopandas\n", - "\n", - "url = (\n", - " \"https://raw.githubusercontent.com/python-visualization/folium/main/examples/data\"\n", - ")\n", - "nybb = f\"{url}/nybb.zip\"\n", - "boros = geopandas.read_file(nybb)\n", - "\n", - "boros" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To create a map with these features, simply put them in a `GeoJson`:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import folium\n", - "\n", - "\n", - "m = folium.Map([40.7, -74], zoom_start=10, tiles=\"cartodbpositron\")\n", - "\n", - "folium.GeoJson(boros).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Quite easy.\n", - "\n", - "Well, you can also take advantage of your `GeoDataFrame` structure to set the style of the data. For this, just create a column `style` containing each feature's style in a dictionary." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
BoroCodeBoroNameShape_LengShape_Areageometrystyle
05Staten Island330454.1759331.623847e+09MULTIPOLYGON (((970217.022 145643.332, 970227....{'fillColor': '#ff0000', 'weight': 2, 'color':...
13Brooklyn741227.3370731.937810e+09MULTIPOLYGON (((1021176.479 151374.797, 102100...{'fillColor': '#00ff00', 'weight': 2, 'color':...
24Queens896875.3964493.045079e+09MULTIPOLYGON (((1029606.077 156073.814, 102957...{'fillColor': '#0000ff', 'weight': 2, 'color':...
31Manhattan358400.9128366.364308e+08MULTIPOLYGON (((981219.056 188655.316, 980940....{'fillColor': '#ffff00', 'weight': 2, 'color':...
42Bronx464475.1456511.186822e+09MULTIPOLYGON (((1012821.806 229228.265, 101278...{'fillColor': '#00ffff', 'weight': 2, 'color':...
\n", - "
" - ], - "text/plain": [ - " BoroCode BoroName Shape_Leng Shape_Area \\\n", - "0 5 Staten Island 330454.175933 1.623847e+09 \n", - "1 3 Brooklyn 741227.337073 1.937810e+09 \n", - "2 4 Queens 896875.396449 3.045079e+09 \n", - "3 1 Manhattan 358400.912836 6.364308e+08 \n", - "4 2 Bronx 464475.145651 1.186822e+09 \n", - "\n", - " geometry \\\n", - "0 MULTIPOLYGON (((970217.022 145643.332, 970227.... \n", - "1 MULTIPOLYGON (((1021176.479 151374.797, 102100... \n", - "2 MULTIPOLYGON (((1029606.077 156073.814, 102957... \n", - "3 MULTIPOLYGON (((981219.056 188655.316, 980940.... \n", - "4 MULTIPOLYGON (((1012821.806 229228.265, 101278... \n", - "\n", - " style \n", - "0 {'fillColor': '#ff0000', 'weight': 2, 'color':... \n", - "1 {'fillColor': '#00ff00', 'weight': 2, 'color':... \n", - "2 {'fillColor': '#0000ff', 'weight': 2, 'color':... \n", - "3 {'fillColor': '#ffff00', 'weight': 2, 'color':... \n", - "4 {'fillColor': '#00ffff', 'weight': 2, 'color':... " - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "boros[\"style\"] = [\n", - " {\"fillColor\": \"#ff0000\", \"weight\": 2, \"color\": \"black\"},\n", - " {\"fillColor\": \"#00ff00\", \"weight\": 2, \"color\": \"black\"},\n", - " {\"fillColor\": \"#0000ff\", \"weight\": 2, \"color\": \"black\"},\n", - " {\"fillColor\": \"#ffff00\", \"weight\": 2, \"color\": \"black\"},\n", - " {\"fillColor\": \"#00ffff\", \"weight\": 2, \"color\": \"black\"},\n", - "]\n", - "\n", - "boros" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([40.7, -74], zoom_start=10, tiles=\"cartodbpositron\")\n", - "\n", - "folium.GeoJson(boros).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Folium should work with any object that implements the `__geo_interface__` but be aware that sometimes you may need to convert your data to `epsg='4326'` before sending it to `folium`." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + }, "source": [ - "import fiona\n", - "import shapely\n", - "\n", - "fname = f\"{url}/2014_08_05_farol.gpx\"\n", - "with fiona.open(fname, \"r\", layer=\"tracks\") as records:\n", - " tracks = [shapely.geometry.shape(record[\"geometry\"]) for record in records]\n", - "\n", - "track = tracks[0]\n", - "\n", - "m = folium.Map(tiles=\"cartodbpositron\")\n", - "folium.GeoJson(track).add_to(m)\n", - "\n", - "m.fit_bounds(m.get_bounds())\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/geojson/geopandas_and_geo_interface.html" ] } ], diff --git a/examples/Heatmap.ipynb b/examples/Heatmap.ipynb index 1e7082371..8034f621b 100644 --- a/examples/Heatmap.ipynb +++ b/examples/Heatmap.ipynb @@ -1,48 +1,15 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "\n", - "data = (\n", - " np.random.normal(size=(100, 3)) * np.array([[1, 1, 1]]) + np.array([[48, 5, 1]])\n", - ").tolist()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "import folium\n", - "from folium.plugins import HeatMap\n", - "\n", - "\n", - "m = folium.Map([48.0, 5.0], tiles=\"stamentoner\", zoom_start=6)\n", - "\n", - "HeatMap(data).add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins/heatmap.html" ] } ], diff --git a/examples/Highlight_Function.ipynb b/examples/Highlight_Function.ipynb index c24787eef..90dd6f3ac 100644 --- a/examples/Highlight_Function.ipynb +++ b/examples/Highlight_Function.ipynb @@ -1,160 +1,14 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import pandas as pd\n", - "\n", - "\n", - "df = pd.read_csv(os.path.join(\"data\", \"highlight_flight_trajectories.csv\"))" - ] - }, { "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us take a glance at the data.\n", - "Each row represents the trajectory of a flight,\n", - "and the last column contains the coordinates of the flight path in `GeoJSON` format." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Unnamed: 0depdestgeojson
00Place_MontpellierMediterranee_AirportPlace_BastiaPoretta_Airport{\"type\": \"LineString\", \"coordinates\": [[3.9613...
11Place_Bristol___LulsgatePlace_TenerifeSur_ReinaSofia_Airport{\"type\": \"LineString\", \"coordinates\": [[-2.719...
22Place_Valencia_Manises_AirportPlace_Bucuresti_HenriCoanda_Airport{\"type\": \"LineString\", \"coordinates\": [[-0.481...
\n", - "
" - ], - "text/plain": [ - " Unnamed: 0 dep \\\n", - "0 0 Place_MontpellierMediterranee_Airport \n", - "1 1 Place_Bristol___Lulsgate \n", - "2 2 Place_Valencia_Manises_Airport \n", - "\n", - " dest \\\n", - "0 Place_BastiaPoretta_Airport \n", - "1 Place_TenerifeSur_ReinaSofia_Airport \n", - "2 Place_Bucuresti_HenriCoanda_Airport \n", - "\n", - " geojson \n", - "0 {\"type\": \"LineString\", \"coordinates\": [[3.9613... \n", - "1 {\"type\": \"LineString\", \"coordinates\": [[-2.719... \n", - "2 {\"type\": \"LineString\", \"coordinates\": [[-0.481... " - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ - "df" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/geojson/geojson.html#Highlight-function" ], - "source": [ - "import folium\n", - "\n", - "\n", - "m = folium.Map(location=[40, 10], zoom_start=4, control_scale=True, prefer_canvas=True)\n", - "\n", - "\n", - "def style_function(feature):\n", - " return {\"fillColor\": \"#ffaf00\", \"color\": \"blue\", \"weight\": 1.5, \"dashArray\": \"5, 5\"}\n", - "\n", - "\n", - "def highlight_function(feature):\n", - " return {\"fillColor\": \"#ffaf00\", \"color\": \"green\", \"weight\": 3, \"dashArray\": \"5, 5\"}\n", - "\n", - "\n", - "for index, row in df.iterrows():\n", - " c = folium.GeoJson(\n", - " row[\"geojson\"],\n", - " name=(\"{}{}\".format(row[\"dep\"], row[\"dest\"])),\n", - " overlay=True,\n", - " style_function=style_function,\n", - " highlight_function=highlight_function,\n", - " )\n", - " folium.Popup(\"{}\\n{}\".format(row[\"dep\"], row[\"dest\"])).add_to(c)\n", - " c.add_to(m)\n", - "\n", - "folium.LayerControl().add_to(m)\n", - "\n", - "m" - ] + "metadata": { + "collapsed": false + } } ], "metadata": { diff --git a/examples/ImageOverlay.ipynb b/examples/ImageOverlay.ipynb index 5b85021e0..223f0ebbd 100644 --- a/examples/ImageOverlay.ipynb +++ b/examples/ImageOverlay.ipynb @@ -2,295 +2,14 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, - "source": [ - "# How to use ImageOverlay\n", - "\n", - "It may happen that you want to draw an image on you map. Here are example on how to do that.\n", - "\n", - "\n", - "## Using an image from disk\n", - "\n", - "If you have a static image file on your disk, you can simply draw it on the map." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import os\n", - "import folium\n", - "\n", - "m = folium.Map([37, 0], zoom_start=1, tiles=\"stamentoner\")\n", - "merc = os.path.join(\"data\", \"Mercator_projection_SW.png\")\n", - "\n", - "\n", - "if not os.path.isfile(merc):\n", - " print(f\"Could not find {merc}\")\n", - "else:\n", - " img = folium.raster_layers.ImageOverlay(\n", - " name=\"Mercator projection SW\",\n", - " image=merc,\n", - " bounds=[[-82, -180], [82, 180]],\n", - " opacity=0.6,\n", - " interactive=True,\n", - " cross_origin=False,\n", - " zindex=1,\n", - " )\n", - "\n", - " folium.Popup(\"I am an image\").add_to(img)\n", - "\n", - " img.add_to(m)\n", - " folium.LayerControl().add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A few remarks:\n", - "\n", - "* Note that your image has to be in Mercator projection format.\n", - "\n", - " The image we've used is based on https://en.wikipedia.org/wiki/File:Mercator_projection_SW.jpg ; that you can find in wikipedia's article on Mercator Projection (https://en.wikipedia.org/wiki/Mercator_projection).\n", - "\n", - "\n", - "You can also provide simply URL. In this case, the image will not be embedded in folium's output." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "m = folium.Map([37, 0], zoom_start=1, tiles=\"stamentoner\")\n", - "\n", - "folium.raster_layers.ImageOverlay(\n", - " image=\"https://upload.wikimedia.org/wikipedia/commons/f/f4/Mercator_projection_SW.jpg\",\n", - " name=\"I am a jpeg\",\n", - " bounds=[[-82, -180], [82, 180]],\n", - " opacity=1,\n", - " interactive=False,\n", - " cross_origin=False,\n", - " zindex=1,\n", - " alt=\"Wikipedia File:Mercator projection SW.jpg\",\n", - ").add_to(m)\n", - "\n", - "folium.LayerControl().add_to(m)\n", - "\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This works exactly the same way if you want to put a JPG instead of a PNG." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## In creating an image with numpy" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now you may wish to create your own image, based on another python computation.\n", - "For this, you'll need to have numpy installed on your machine.\n", - "\n", - "Let's create an image to draw a rectangle in the bounds `[[0, -60], [60, 60]]`." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "image = np.zeros((61, 61))\n", - "image[0, :] = 1.0\n", - "image[60, :] = 1.0\n", - "image[:, 0] = 1.0\n", - "image[:, 60] = 1.0" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can draw it on the map in using:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([37, 0], zoom_start=2)\n", - "\n", - "folium.raster_layers.ImageOverlay(\n", - " image=image,\n", - " bounds=[[0, -60], [60, 60]],\n", - " colormap=lambda x: (1, 0, 0, x),\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that you need to provide a colormap of the form `lambda x: (R,G,B,A)` where `R,G,B,A` are floats between 0 and 1.\n", - "\n", - "Now, let's try to add a line at latitude 45°, and add a polyline to verify it's well rendered. We'll need to specify `origin='lower` to inform folium that the first lines of the array are to be plotted at the bottom of the image (see `numpy.imshow`, it's the same principle)." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import numpy as np\n", - "\n", - "image = np.zeros((61, 1))\n", - "\n", - "image[45, :] = 1.0\n", - "\n", - "\n", - "m = folium.Map([37, 0], zoom_start=3)\n", - "\n", - "folium.raster_layers.ImageOverlay(\n", - " image=image,\n", - " bounds=[[0, -60], [60, 60]],\n", - " colormap=lambda x: (1, 0, 0, x),\n", - " origin=\"lower\",\n", - ").add_to(m)\n", - "\n", - "folium.PolyLine([[45, -60], [45, 60]]).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "But even with `origin='lower'`, the red line is not at the good latitude. This is due to Mercator projection used in Leaflet (and most other map systems).\n", - "\n", - "You can read wikipedia's article on Mercator Projection (https://en.wikipedia.org/wiki/Mercator_projection), or simply let folium do the job, in precising that you want the mercator stuff to be handled." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([37, 0], zoom_start=3)\n", - "\n", - "folium.PolyLine([[45, -60], [45, 60]]).add_to(m)\n", - "\n", - "folium.raster_layers.ImageOverlay(\n", - " image=image,\n", - " bounds=[[0, -60], [60, 60]],\n", - " origin=\"lower\",\n", - " colormap=lambda x: (1, 0, 0, x),\n", - " mercator_project=True,\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, + }, "source": [ - "This time, the lines are properly positioned (at the precision of the array)." + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/raster_layers/image_overlay.html" ] } ], diff --git a/examples/MarkerCluster.ipynb b/examples/MarkerCluster.ipynb index 48d4208cf..f370b4316 100644 --- a/examples/MarkerCluster.ipynb +++ b/examples/MarkerCluster.ipynb @@ -1,334 +1,15 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import folium\n", - "from folium.plugins import MarkerCluster\n", - "\n", - "\n", - "m = folium.Map(location=[44, -73], zoom_start=5)\n", - "\n", - "marker_cluster = MarkerCluster().add_to(m)\n", - "\n", - "\n", - "folium.Marker(\n", - " location=[40.67, -73.94],\n", - " popup=\"Add popup text here.\",\n", - " icon=folium.Icon(color=\"green\", icon=\"ok-sign\"),\n", - ").add_to(marker_cluster)\n", - "\n", - "folium.Marker(\n", - " location=[44.67, -73.94],\n", - " popup=\"Add popup text here.\",\n", - " icon=folium.Icon(color=\"red\", icon=\"remove-sign\"),\n", - ").add_to(marker_cluster)\n", - "\n", - "folium.Marker(\n", - " location=[44.67, -71.94],\n", - " popup=\"Add popup text here.\",\n", - " icon=None,\n", - ").add_to(marker_cluster)\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "size = 100\n", - "lons = np.random.randint(-180, 180, size=size)\n", - "lats = np.random.randint(-90, 90, size=size)\n", - "\n", - "locations = list(zip(lats, lons))\n", - "popups = [\"lon:{}
lat:{}\".format(lon, lat) for (lat, lon) in locations]" - ] - }, { "cell_type": "markdown", - "metadata": {}, - "source": [ - "Adding all icons in a single call" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "icon_create_function = \"\"\"\\\n", - "function(cluster) {\n", - " return L.divIcon({\n", - " html: '' + cluster.getChildCount() + '',\n", - " className: 'marker-cluster marker-cluster-large',\n", - " iconSize: new L.Point(20, 20)\n", - " });\n", - "}\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from folium.plugins import MarkerCluster\n", - "\n", - "m = folium.Map(\n", - " location=[np.mean(lats), np.mean(lons)], tiles=\"Cartodb Positron\", zoom_start=1\n", - ")\n", - "\n", - "marker_cluster = MarkerCluster(\n", - " locations=locations,\n", - " popups=popups,\n", - " name=\"1000 clustered icons\",\n", - " overlay=True,\n", - " control=True,\n", - " icon_create_function=icon_create_function,\n", - ")\n", - "\n", - "marker_cluster.add_to(m)\n", - "\n", - "folium.LayerControl().add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Explicit loop allow for customization in the loop." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 17.8 ms, sys: 3.64 ms, total: 21.4 ms\n", - "Wall time: 21.8 ms\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "%%time\n", - "\n", - "m = folium.Map(\n", - " location=[np.mean(lats), np.mean(lons)],\n", - " tiles='Cartodb Positron',\n", - " zoom_start=1\n", - ")\n", - "\n", - "marker_cluster = MarkerCluster(\n", - " name='1000 clustered icons',\n", - " overlay=True,\n", - " control=False,\n", - " icon_create_function=None\n", - ")\n", - "\n", - "for k in range(size):\n", - " location = lats[k], lons[k]\n", - " marker = folium.Marker(location=location)\n", - " popup = 'lon:{}
lat:{}'.format(location[1], location[0])\n", - " folium.Popup(popup).add_to(marker)\n", - " marker_cluster.add_child(marker)\n", - "\n", - "marker_cluster.add_to(m)\n", - "\n", - "folium.LayerControl().add_to(m);" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`FastMarkerCluster` is not as flexible as MarkerCluster but, like the name suggests, it is faster." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "from folium.plugins import FastMarkerCluster" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 5.66 ms, sys: 0 ns, total: 5.66 ms\n", - "Wall time: 4.98 ms\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "\n", - "\n", - "m = folium.Map(\n", - " location=[np.mean(lats), np.mean(lons)],\n", - " tiles='Cartodb Positron',\n", - " zoom_start=1\n", - ")\n", - "\n", - "FastMarkerCluster(data=list(zip(lats, lons))).add_to(m)\n", - "\n", - "folium.LayerControl().add_to(m);" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + }, "source": [ - "callback = \"\"\"\\\n", - "function (row) {\n", - " var icon, marker;\n", - " icon = L.AwesomeMarkers.icon({\n", - " icon: \"map-marker\", markerColor: \"red\"});\n", - " marker = L.marker(new L.LatLng(row[0], row[1]));\n", - " marker.setIcon(icon);\n", - " return marker;\n", - "};\n", - "\"\"\"\n", - "m = folium.Map(\n", - " location=[np.mean(lats), np.mean(lons)], tiles=\"Cartodb Positron\", zoom_start=1\n", - ")\n", - "\n", - "FastMarkerCluster(data=list(zip(lats, lons)), callback=callback).add_to(m)\n", - "\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins/marker_cluster.html" ] } ], diff --git a/examples/MinMaxLimits.ipynb b/examples/MinMaxLimits.ipynb index 0056a8a16..7f0f728da 100644 --- a/examples/MinMaxLimits.ipynb +++ b/examples/MinMaxLimits.ipynb @@ -1,68 +1,14 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "cell_type": "markdown", "source": [ - "import folium\n", - "\n", - "\n", - "lon = -(41 + 20 / 60.0 + 17 / 60 / 60.0)\n", - "lat = -(20 + 59 / 60.0 + 35 / 60 / 60.0)\n", - "\n", - "min_lon, max_lon = -45, -35\n", - "min_lat, max_lat = -25, -15\n", - "\n", - "m = folium.Map(\n", - " max_bounds=True,\n", - " location=[lat, lon],\n", - " zoom_start=6,\n", - " min_lat=min_lat,\n", - " max_lat=max_lat,\n", - " min_lon=min_lon,\n", - " max_lon=max_lon,\n", - ")\n", - "\n", - "\n", - "kw = {\n", - " \"radius\": 10,\n", - " \"color\": \"black\",\n", - " \"fill\": True,\n", - " \"weight\": 1,\n", - " \"fill_color\": \"green\",\n", - " \"fill_opacity\": 1,\n", - "}\n", - "\n", - "c0 = folium.CircleMarker(location=[max_lat, min_lon], tooltip=\"Upper Left Corner\", **kw)\n", - "c1 = folium.CircleMarker(location=[min_lat, min_lon], tooltip=\"Lower Left Corner\", **kw)\n", - "c2 = folium.CircleMarker(\n", - " location=[min_lat, max_lon], tooltip=\"Lower Right Corner\", **kw\n", - ")\n", - "c3 = folium.CircleMarker(\n", - " location=[max_lat, max_lon], tooltip=\"Upper Right Corner\", **kw\n", - ")\n", - "\n", - "for c in [c0, c1, c2, c3]:\n", - " m.add_child(c)\n", - "\n", - "m" - ] + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/map.html#Limits" + ], + "metadata": { + "collapsed": false + } } ], "metadata": { diff --git a/examples/MiniMap.ipynb b/examples/MiniMap.ipynb index 25ef870f2..1310eeb01 100644 --- a/examples/MiniMap.ipynb +++ b/examples/MiniMap.ipynb @@ -2,205 +2,14 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Demo of a Minimap in Folium" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import folium\n", - "from folium.plugins import MiniMap\n", - "\n", - "\n", - "m = folium.Map(location=(30, 20), zoom_start=4)\n", - "\n", - "minimap = MiniMap()\n", - "m.add_child(minimap)\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Make the minimap collapsible" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "m = folium.Map(location=(30, 20), zoom_start=4)\n", - "minimap = MiniMap(toggle_display=True)\n", - "minimap.add_to(m)\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Change the minimap tile layer" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=(30, 20), zoom_start=4)\n", - "minimap = MiniMap(tile_layer=\"Stamen Toner\")\n", - "minimap.add_to(m)\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Change the minimap position" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=(30, 20), zoom_start=4)\n", - "minimap = MiniMap(position=\"topleft\")\n", - "minimap.add_to(m)\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Change the minimap size" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=(30, 20), zoom_start=4)\n", - "minimap = MiniMap(width=400, height=100)\n", - "minimap.add_to(m)\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Change the zoom offset" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + }, "source": [ - "m = folium.Map(location=(30, 20), zoom_start=8)\n", - "minimap = MiniMap(zoom_level_offset=-8)\n", - "minimap.add_to(m)\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins/mini_map.html" ] } ], diff --git a/examples/Minicharts.ipynb b/examples/Minicharts.ipynb index 9f8312c02..c10ae3a9a 100644 --- a/examples/Minicharts.ipynb +++ b/examples/Minicharts.ipynb @@ -1,236 +1,15 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
languagecoordinatesconsonantsvowels
0Turkish(39.8667, 32.8667)258
1Korean(37.5, 128.0)2111
2Tiwi(-11.6308, 130.94899999999998)224
3Liberia Kpelle(6.92048, -9.96128)2212
4Tulu(12.8114, 75.2651)2413
\n", - "
" - ], - "text/plain": [ - " language coordinates consonants vowels\n", - "0 Turkish (39.8667, 32.8667) 25 8\n", - "1 Korean (37.5, 128.0) 21 11\n", - "2 Tiwi (-11.6308, 130.94899999999998) 22 4\n", - "3 Liberia Kpelle (6.92048, -9.96128) 22 12\n", - "4 Tulu (12.8114, 75.2651) 24 13" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import os\n", - "import ast\n", - "\n", - "import pandas\n", - "\n", - "\n", - "data = pandas.read_csv(\n", - " \"data\" + os.path.sep + \"consonants_vowels.csv\",\n", - " # To ensure that tuples are read as tuples\n", - " converters={\"coordinates\": ast.literal_eval},\n", - ")\n", - "\n", - "data.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Charts" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "import io\n", - "\n", - "import matplotlib.pyplot as plt\n", - "\n", - "pie_charts_data = zip(data.consonants, data.vowels)\n", - "\n", - "fig = plt.figure(figsize=(0.5, 0.5))\n", - "fig.patch.set_alpha(0)\n", - "ax = fig.add_subplot(111)\n", - "plots = []\n", - "for sizes in pie_charts_data:\n", - " ax.pie(sizes, colors=(\"#e6194b\", \"#19e6b4\"))\n", - " buff = io.StringIO()\n", - " plt.savefig(buff, format=\"SVG\")\n", - " buff.seek(0)\n", - " svg = buff.read()\n", - " svg = svg.replace(\"\\n\", \"\")\n", - " plots.append(svg)\n", - " plt.cla()\n", - "plt.clf()\n", - "plt.close()" - ] - }, { "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Legend" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "import branca\n", - "\n", - "legend_html = \"\"\"\n", - "{% macro html(this, kwargs) %}\n", - "
\n", - "

â—¼ Consonants

\n", - "

â—¼ Vowels

\n", - "
\n", - "
\n", - "
\n", - "{% endmacro %}\n", - "\"\"\"\n", - "\n", - "legend = branca.element.MacroElement()\n", - "legend._template = branca.element.Template(legend_html)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Map" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "import folium\n", - "\n", - "\n", - "m = folium.Map(location=(0, 0), zoom_start=2)\n", - "\n", - "for i, coord in enumerate(data.coordinates):\n", - " marker = folium.Marker(coord)\n", - " icon = folium.DivIcon(html=plots[i])\n", - " marker.add_child(icon)\n", - " popup = folium.Popup(\n", - " \"Consonants: {}
\\nVowels: {}\".format(data.consonants[i], data.vowels[i])\n", - " )\n", - " marker.add_child(popup)\n", - " m.add_child(marker)\n", - "m.get_root().add_child(legend)\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/advanced_guide/piechart_icons.html" ] } ], diff --git a/examples/Plugins.ipynb b/examples/Plugins.ipynb index ba691962c..e3c52af92 100644 --- a/examples/Plugins.ipynb +++ b/examples/Plugins.ipynb @@ -2,4726 +2,13 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, "source": [ - "# Examples of plugins usage in folium" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In this notebook we show a few illustrations of folium's plugin extensions. These are available after importing `folium.plugins`." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## ScrollZoomToggler\n", - "Adds a button to enable/disable zoom scrolling." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import folium\n", - "from folium import plugins\n", - "\n", - "m = folium.Map([45, 3], zoom_start=4)\n", - "\n", - "plugins.ScrollZoomToggler().add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## MarkerCluster" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Adds a MarkerCluster layer on the map." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import numpy as np\n", - "\n", - "\n", - "N = 100\n", - "data = np.array(\n", - " [\n", - " np.random.uniform(low=35, high=60, size=N), # Random latitudes in Europe.\n", - " np.random.uniform(low=-12, high=30, size=N), # Random longitudes in Europe.\n", - " ]\n", - ").T\n", - "popups = [str(i) for i in range(N)] # Popups texts are simple numbers.\n", - "\n", - "m = folium.Map([45, 3], zoom_start=4)\n", - "\n", - "plugins.MarkerCluster(data, popups=popups).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Terminator" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([45, 3], zoom_start=1)\n", - "\n", - "plugins.Terminator().add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## BoatMarker" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([30, 0], zoom_start=3)\n", - "\n", - "plugins.BoatMarker(\n", - " location=(34, -43), heading=45, wind_heading=150, wind_speed=45, color=\"#8f8\"\n", - ").add_to(m)\n", - "\n", - "plugins.BoatMarker(\n", - " location=(46, -30), heading=-20, wind_heading=46, wind_speed=25, color=\"#88f\"\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## BeautifyIcon" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([45.5, -122], zoom_start=3)\n", - "\n", - "icon_plane = plugins.BeautifyIcon(\n", - " icon=\"plane\", border_color=\"#b3334f\", text_color=\"#b3334f\", icon_shape=\"triangle\"\n", - ")\n", - "\n", - "icon_number = plugins.BeautifyIcon(\n", - " border_color=\"#00ABDC\",\n", - " text_color=\"#00ABDC\",\n", - " number=10,\n", - " inner_icon_style=\"margin-top:0;\",\n", - ")\n", - "\n", - "folium.Marker(location=[46, -122], popup=\"Portland, OR\", icon=icon_plane).add_to(m)\n", - "\n", - "folium.Marker(location=[50, -122], popup=\"Portland, OR\", icon=icon_number).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Fullscreen" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[41.9, -97.3], zoom_start=4)\n", - "\n", - "plugins.Fullscreen(\n", - " position=\"topright\",\n", - " title=\"Expand me\",\n", - " title_cancel=\"Exit me\",\n", - " force_separate_button=True,\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Timestamped GeoJSON" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[35.68159659061569, 139.76451516151428], zoom_start=16)\n", - "\n", - "# Lon, Lat order.\n", - "lines = [\n", - " {\n", - " \"coordinates\": [\n", - " [139.76451516151428, 35.68159659061569],\n", - " [139.75964426994324, 35.682590062684206],\n", - " ],\n", - " \"dates\": [\"2017-06-02T00:00:00\", \"2017-06-02T00:10:00\"],\n", - " \"color\": \"red\",\n", - " },\n", - " {\n", - " \"coordinates\": [\n", - " [139.75964426994324, 35.682590062684206],\n", - " [139.7575843334198, 35.679505030038506],\n", - " ],\n", - " \"dates\": [\"2017-06-02T00:10:00\", \"2017-06-02T00:20:00\"],\n", - " \"color\": \"blue\",\n", - " },\n", - " {\n", - " \"coordinates\": [\n", - " [139.7575843334198, 35.679505030038506],\n", - " [139.76337790489197, 35.678040905014065],\n", - " ],\n", - " \"dates\": [\"2017-06-02T00:20:00\", \"2017-06-02T00:30:00\"],\n", - " \"color\": \"green\",\n", - " \"weight\": 15,\n", - " },\n", - " {\n", - " \"coordinates\": [\n", - " [139.76337790489197, 35.678040905014065],\n", - " [139.76451516151428, 35.68159659061569],\n", - " ],\n", - " \"dates\": [\"2017-06-02T00:30:00\", \"2017-06-02T00:40:00\"],\n", - " \"color\": \"#FFFFFF\",\n", - " },\n", - "]\n", - "\n", - "features = [\n", - " {\n", - " \"type\": \"Feature\",\n", - " \"geometry\": {\n", - " \"type\": \"LineString\",\n", - " \"coordinates\": line[\"coordinates\"],\n", - " },\n", - " \"properties\": {\n", - " \"times\": line[\"dates\"],\n", - " \"style\": {\n", - " \"color\": line[\"color\"],\n", - " \"weight\": line[\"weight\"] if \"weight\" in line else 5,\n", - " },\n", - " },\n", - " }\n", - " for line in lines\n", - "]\n", - "\n", - "plugins.TimestampedGeoJson(\n", - " {\n", - " \"type\": \"FeatureCollection\",\n", - " \"features\": features,\n", - " },\n", - " period=\"PT1M\",\n", - " add_last_point=True,\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "scrolled": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins.html" ], - "source": [ - "table = \"\"\"\\\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
FirstnameLastnameAge
JillSmith50
EveJackson94
\n", - "\"\"\"\n", - "\n", - "points = [\n", - " {\n", - " \"time\": \"2017-06-02\",\n", - " \"popup\": \"

address1

\",\n", - " \"coordinates\": [-2.548828, 51.467697],\n", - " },\n", - " {\n", - " \"time\": \"2017-07-02\",\n", - " \"popup\": \"

address2

\",\n", - " \"coordinates\": [-0.087891, 51.536086],\n", - " },\n", - " {\n", - " \"time\": \"2017-08-02\",\n", - " \"popup\": \"

address3

\",\n", - " \"coordinates\": [-6.240234, 53.383328],\n", - " },\n", - " {\n", - " \"time\": \"2017-09-02\",\n", - " \"popup\": \"

address4

\",\n", - " \"coordinates\": [-1.40625, 60.261617],\n", - " },\n", - " {\"time\": \"2017-10-02\", \"popup\": table, \"coordinates\": [-1.516113, 53.800651]},\n", - "]\n", - "\n", - "features = [\n", - " {\n", - " \"type\": \"Feature\",\n", - " \"geometry\": {\n", - " \"type\": \"Point\",\n", - " \"coordinates\": point[\"coordinates\"],\n", - " },\n", - " \"properties\": {\n", - " \"time\": point[\"time\"],\n", - " \"popup\": point[\"popup\"],\n", - " \"id\": \"house\",\n", - " \"icon\": \"marker\",\n", - " \"iconstyle\": {\n", - " \"iconUrl\": \"https://leafletjs.com/examples/geojson/baseball-marker.png\",\n", - " \"iconSize\": [20, 20],\n", - " },\n", - " },\n", - " }\n", - " for point in points\n", - "]\n", - "\n", - "features.append(\n", - " {\n", - " \"type\": \"Feature\",\n", - " \"geometry\": {\n", - " \"type\": \"LineString\",\n", - " \"coordinates\": [\n", - " [-2.548828, 51.467697],\n", - " [-0.087891, 51.536086],\n", - " [-6.240234, 53.383328],\n", - " [-1.40625, 60.261617],\n", - " [-1.516113, 53.800651],\n", - " ],\n", - " },\n", - " \"properties\": {\n", - " \"popup\": \"Current address\",\n", - " \"times\": [\n", - " \"2017-06-02\",\n", - " \"2017-07-02\",\n", - " \"2017-08-02\",\n", - " \"2017-09-02\",\n", - " \"2017-10-02\",\n", - " ],\n", - " \"icon\": \"circle\",\n", - " \"iconstyle\": {\n", - " \"fillColor\": \"green\",\n", - " \"fillOpacity\": 0.6,\n", - " \"stroke\": \"false\",\n", - " \"radius\": 13,\n", - " },\n", - " \"style\": {\"weight\": 0},\n", - " \"id\": \"man\",\n", - " },\n", - " }\n", - ")\n", - "\n", - "m = folium.Map(\n", - " location=[56.096555, -3.64746],\n", - " tiles=\"cartodbpositron\",\n", - " zoom_start=5,\n", - ")\n", - "\n", - "plugins.TimestampedGeoJson(\n", - " {\"type\": \"FeatureCollection\", \"features\": features},\n", - " period=\"P1M\",\n", - " add_last_point=True,\n", - " auto_play=False,\n", - " loop=False,\n", - " max_speed=1,\n", - " loop_button=True,\n", - " date_options=\"YYYY/MM/DD\",\n", - " time_slider_drag_update=True,\n", - " duration=\"P2M\",\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## FeatureGroupSubGroup\n", - "\n", - "### Sub categories\n", - "\n", - "Disable all markers in the category, or just one of the subgroup." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[0, 0], zoom_start=6)\n", - "\n", - "fg = folium.FeatureGroup(name=\"groups\")\n", - "m.add_child(fg)\n", - "\n", - "g1 = plugins.FeatureGroupSubGroup(fg, \"group1\")\n", - "m.add_child(g1)\n", - "\n", - "g2 = plugins.FeatureGroupSubGroup(fg, \"group2\")\n", - "m.add_child(g2)\n", - "\n", - "folium.Marker([-1, -1]).add_to(g1)\n", - "folium.Marker([1, 1]).add_to(g1)\n", - "\n", - "folium.Marker([-1, 1]).add_to(g2)\n", - "folium.Marker([1, -1]).add_to(g2)\n", - "\n", - "folium.LayerControl(collapsed=False).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Marker clusters across groups\n", - "\n", - "Create two subgroups, but cluster markers together." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[0, 0], zoom_start=6)\n", - "\n", - "mcg = folium.plugins.MarkerCluster(control=False)\n", - "m.add_child(mcg)\n", - "\n", - "g1 = folium.plugins.FeatureGroupSubGroup(mcg, \"group1\")\n", - "m.add_child(g1)\n", - "\n", - "g2 = folium.plugins.FeatureGroupSubGroup(mcg, \"group2\")\n", - "m.add_child(g2)\n", - "\n", - "folium.Marker([-1, -1]).add_to(g1)\n", - "folium.Marker([1, 1]).add_to(g1)\n", - "\n", - "folium.Marker([-1, 1]).add_to(g2)\n", - "folium.Marker([1, -1]).add_to(g2)\n", - "\n", - "folium.LayerControl(collapsed=False).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Minimap\n", - "\n", - "Adds a locator minimap to a folium document." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=(30, 20), zoom_start=4)\n", - "\n", - "minimap = plugins.MiniMap()\n", - "m.add_child(minimap)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## DualMap\n", - "The DualMap plugin can be used to display two maps side by side, where panning and zooming is synchronized.\n", - "\n", - "The `DualMap` class can be used just like the normal `Map` class. The two sub-maps can be accessed with its `m1` and `m2` attributes." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = plugins.DualMap(location=(52.1, 5.1), tiles=None, zoom_start=8)\n", - "\n", - "folium.TileLayer(\"cartodbpositron\").add_to(m.m2)\n", - "folium.TileLayer(\"openstreetmap\").add_to(m)\n", - "\n", - "fg_both = folium.FeatureGroup(name=\"markers_both\").add_to(m)\n", - "fg_1 = folium.FeatureGroup(name=\"markers_1\").add_to(m.m1)\n", - "fg_2 = folium.FeatureGroup(name=\"markers_2\").add_to(m.m2)\n", - "\n", - "icon_red = folium.Icon(color=\"red\")\n", - "folium.Marker((52, 5), tooltip=\"both\", icon=icon_red).add_to(fg_both)\n", - "folium.Marker((52.4, 5), tooltip=\"left\").add_to(fg_1)\n", - "folium.Marker((52, 5.4), tooltip=\"right\").add_to(fg_2)\n", - "\n", - "folium.LayerControl(collapsed=False).add_to(m)\n", - "\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Side by side layers\n", - "\n", - "This plugin can be used to compare two layers on the same map using a vertical separator managed by the user.\n", - "\n", - "The SideBySideLayers class must be instantiated with left and right layers, then added to the map along with layers.\n", - "\n", - "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`." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=(30, 20), zoom_start=4)\n", - "\n", - "layer_right = folium.TileLayer('openstreetmap')\n", - "layer_left = folium.TileLayer('cartodbpositron')\n", - "\n", - "sbs = plugins.SideBySideLayers(layer_left=layer_left, layer_right=layer_right)\n", - "\n", - "layer_left.add_to(m)\n", - "layer_right.add_to(m)\n", - "sbs.add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Locate control\n", - "\n", - "Adds a control button that when clicked, the user device geolocation is displayed.\n", - "For list of all possible keyword options see:\n", - "https://github.com/domoritz/leaflet-locatecontrol#possible-options\n", - "\n", - "To work properly in production, the connection needs to be encrypted (HTTPS), otherwise browser will not\n", - "allow users to share their location." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([41.97, 2.81])\n", - "\n", - "plugins.LocateControl().add_to(m)\n", - "\n", - "# If you want get the user device position after load the map, set auto_start=True\n", - "plugins.LocateControl(auto_start=True).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## SemiCircle\n", - "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. \n", - "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. " - ] - }, - { - "cell_type": "code", - "execution_count": 15, "metadata": { - "scrolled": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([45, 3], zoom_start=5)\n", - "\n", - "plugins.SemiCircle(\n", - " (45, 3),\n", - " radius=400000,\n", - " start_angle=50,\n", - " stop_angle=200,\n", - " color=\"green\",\n", - " fill_color=\"green\",\n", - " opacity=0,\n", - " popup=\"start angle - 50 degrees, stop angle - 200 degrees\",\n", - ").add_to(m)\n", - "\n", - "plugins.SemiCircle(\n", - " (46.5, 9.5),\n", - " radius=200000,\n", - " direction=360,\n", - " arc=90,\n", - " color=\"red\",\n", - " fill_color=\"red\",\n", - " opacity=0,\n", - " popup=\"Direction - 0 degrees, arc 90 degrees\",\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Geocoder\n", - "\n", - "Adds a search box to the map to search for geographic features like cities, countries, etc. You can search with names or addresses.\n", - "\n", - "Uses the Nomatim service from OpenStreetMap. Please respect their usage policy: https://operations.osmfoundation.org/policies/nominatim/" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map()\n", - "\n", - "plugins.Geocoder().add_to(m)\n", - "\n", - "m" - ] + "collapsed": false + } } ], "metadata": { diff --git a/examples/PolyLineTextPath_AntPath.ipynb b/examples/PolyLineTextPath_AntPath.ipynb index 85aa4b5fb..734e36b99 100644 --- a/examples/PolyLineTextPath_AntPath.ipynb +++ b/examples/PolyLineTextPath_AntPath.ipynb @@ -1,139 +1,15 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "import folium\n", - "from folium import plugins\n", - "\n", - "\n", - "m = folium.Map([30, 0], zoom_start=3)\n", - "\n", - "wind_locations = [\n", - " [59.35560, -31.992190],\n", - " [55.178870, -42.89062],\n", - " [47.754100, -43.94531],\n", - " [38.272690, -37.96875],\n", - " [27.059130, -41.13281],\n", - " [16.299050, -36.56250],\n", - " [8.4071700, -30.23437],\n", - " [1.0546300, -22.50000],\n", - " [-8.754790, -18.28125],\n", - " [-21.61658, -20.03906],\n", - " [-31.35364, -24.25781],\n", - " [-39.90974, -30.93750],\n", - " [-43.83453, -41.13281],\n", - " [-47.75410, -49.92187],\n", - " [-50.95843, -54.14062],\n", - " [-55.97380, -56.60156],\n", - "]\n", - "\n", - "wind_line = folium.PolyLine(wind_locations, weight=15, color=\"#8EE9FF\").add_to(m)\n", - "\n", - "attr = {\"fill\": \"#007DEF\", \"font-weight\": \"bold\", \"font-size\": \"24\"}\n", - "\n", - "plugins.PolyLineTextPath(\n", - " wind_line, \") \", repeat=True, offset=7, attributes=attr\n", - ").add_to(m)\n", - "\n", - "danger_line = folium.PolyLine(\n", - " [[-40.311, -31.952], [-12.086, -18.727]], weight=10, color=\"orange\", opacity=0.8\n", - ").add_to(m)\n", - "\n", - "attr = {\"fill\": \"red\"}\n", - "\n", - "plugins.PolyLineTextPath(\n", - " danger_line, \"\\u25BA\", repeat=True, offset=6, attributes=attr\n", - ").add_to(m)\n", - "\n", - "plane_line = folium.PolyLine(\n", - " [[-49.38237, -37.26562], [-1.75754, -14.41406], [51.61802, -23.20312]],\n", - " weight=1,\n", - " color=\"black\",\n", - ").add_to(m)\n", - "\n", - "attr = {\"font-weight\": \"bold\", \"font-size\": \"24\"}\n", - "\n", - "plugins.PolyLineTextPath(\n", - " plane_line, \"\\u2708 \", repeat=True, offset=8, attributes=attr\n", - ").add_to(m)\n", - "\n", - "\n", - "line_to_new_delhi = folium.PolyLine(\n", - " [\n", - " [46.67959447, 3.33984375],\n", - " [46.5588603, 29.53125],\n", - " [42.29356419, 51.328125],\n", - " [35.74651226, 68.5546875],\n", - " [28.65203063, 76.81640625],\n", - " ]\n", - ").add_to(m)\n", - "\n", - "\n", - "line_to_hanoi = folium.PolyLine(\n", - " [\n", - " [28.76765911, 77.60742188],\n", - " [27.83907609, 88.72558594],\n", - " [25.68113734, 97.3828125],\n", - " [21.24842224, 105.77636719],\n", - " ]\n", - ").add_to(m)\n", - "\n", - "\n", - "plugins.PolyLineTextPath(line_to_new_delhi, \"To New Delhi\", offset=-5).add_to(m)\n", - "\n", - "\n", - "plugins.PolyLineTextPath(line_to_hanoi, \"To Hanoi\", offset=-5).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + }, "source": [ - "m = folium.Map()\n", - "\n", - "folium.plugins.AntPath(\n", - " locations=wind_locations, reverse=\"True\", dash_array=[20, 30]\n", - ").add_to(m)\n", - "\n", - "m.fit_bounds(m.get_bounds())\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins/polyline_textpath_and_antpath.html" ] } ], diff --git a/examples/Polygons_from_list_of_points.ipynb b/examples/Polygons_from_list_of_points.ipynb index 052c6394d..0e8f602c6 100644 --- a/examples/Polygons_from_list_of_points.ipynb +++ b/examples/Polygons_from_list_of_points.ipynb @@ -2,381 +2,16 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, "source": [ - "# Creating a polygon from a list of points\n", - "\n", - "For many of those working with geo data it is a common task being asked to create a polygon from a list of points. More specific, to create a polygon that wraps around those points in a meaningful manner. So, there are several sources in the web explaining how to create the shape (see sources at end of document). This example notebook is the application of those solutions to folium maps." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Helpers" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "# Imports\n", - "import random\n", - "\n", - "import folium\n", - "from scipy.spatial import ConvexHull\n", - "\n", - "\n", - "# Function to create a list of some random points\n", - "def randome_points(amount, LON_min, LON_max, LAT_min, LAT_max):\n", - "\n", - " points = []\n", - " for _ in range(amount):\n", - " points.append(\n", - " (random.uniform(LON_min, LON_max), random.uniform(LAT_min, LAT_max))\n", - " )\n", - "\n", - " return points\n", - "\n", - "\n", - "# Function to draw points in the map\n", - "def draw_points(map_object, list_of_points, layer_name, line_color, fill_color, text):\n", - "\n", - " fg = folium.FeatureGroup(name=layer_name)\n", - "\n", - " for point in list_of_points:\n", - " fg.add_child(\n", - " folium.CircleMarker(\n", - " point,\n", - " radius=1,\n", - " color=line_color,\n", - " fill_color=fill_color,\n", - " popup=(folium.Popup(text)),\n", - " )\n", - " )\n", - "\n", - " map_object.add_child(fg)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Convex hull\n", - "\n", - "The convex hull is probably the most common approach - its goal is to create the smallest polygon that contains all points from a given list. The scipy.spatial package provides this algorithm (https://docs.scipy.org/doc/scipy-0.19.0/reference/generated/scipy.spatial.ConvexHull.html, accessed 29.12.2018)." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# Function that takes a map and a list of points (LON,LAT tupels) and\n", - "# returns a map with the convex hull polygon from the points as a new layer\n", - "\n", - "\n", - "def create_convexhull_polygon(\n", - " map_object, list_of_points, layer_name, line_color, fill_color, weight, text\n", - "):\n", - "\n", - " # Since it is pointless to draw a convex hull polygon around less than 3 points check len of input\n", - " if len(list_of_points) < 3:\n", - " return\n", - "\n", - " # Create the convex hull using scipy.spatial\n", - " form = [list_of_points[i] for i in ConvexHull(list_of_points).vertices]\n", - "\n", - " # Create feature group, add the polygon and add the feature group to the map\n", - " fg = folium.FeatureGroup(name=layer_name)\n", - " fg.add_child(\n", - " folium.vector_layers.Polygon(\n", - " locations=form,\n", - " color=line_color,\n", - " fill_color=fill_color,\n", - " weight=weight,\n", - " popup=(folium.Popup(text)),\n", - " )\n", - " )\n", - " map_object.add_child(fg)\n", - "\n", - " return map_object" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Initialize map\n", - "my_convexhull_map = folium.Map(location=[48.5, 9.5], zoom_start=8)\n", - "\n", - "# Create a convex hull polygon that contains some points\n", - "list_of_points = randome_points(\n", - " amount=10, LON_min=48, LON_max=49, LAT_min=9, LAT_max=10\n", - ")\n", - "\n", - "create_convexhull_polygon(\n", - " my_convexhull_map,\n", - " list_of_points,\n", - " layer_name=\"Example convex hull\",\n", - " line_color=\"lightblue\",\n", - " fill_color=\"lightskyblue\",\n", - " weight=5,\n", - " text=\"Example convex hull\",\n", - ")\n", - "\n", - "draw_points(\n", - " my_convexhull_map,\n", - " list_of_points,\n", - " layer_name=\"Example points for convex hull\",\n", - " line_color=\"royalblue\",\n", - " fill_color=\"royalblue\",\n", - " text=\"Example point for convex hull\",\n", - ")\n", - "\n", - "# Add layer control and show map\n", - "folium.LayerControl(collapsed=False).add_to(my_convexhull_map)\n", - "my_convexhull_map" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Envelope\n", - "\n", - "The envelope is another interesting approach - its goal is to create a box that contains all points from a given list." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "def create_envelope_polygon(\n", - " map_object, list_of_points, layer_name, line_color, fill_color, weight, text\n", - "):\n", - "\n", - " # Since it is pointless to draw a box around less than 2 points check len of input\n", - " if len(list_of_points) < 2:\n", - " return\n", - "\n", - " # Find the edges of box\n", - " from operator import itemgetter\n", - "\n", - " list_of_points = sorted(list_of_points, key=itemgetter(0))\n", - " x_min = list_of_points[0]\n", - " x_max = list_of_points[len(list_of_points) - 1]\n", - "\n", - " list_of_points = sorted(list_of_points, key=itemgetter(1))\n", - " y_min = list_of_points[0]\n", - " y_max = list_of_points[len(list_of_points) - 1]\n", - "\n", - " upper_left = (x_min[0], y_max[1])\n", - " upper_right = (x_max[0], y_max[1])\n", - " lower_right = (x_max[0], y_min[1])\n", - " lower_left = (x_min[0], y_min[1])\n", - "\n", - " edges = [upper_left, upper_right, lower_right, lower_left]\n", - "\n", - " # Create feature group, add the polygon and add the feature group to the map\n", - " fg = folium.FeatureGroup(name=layer_name)\n", - " fg.add_child(\n", - " folium.vector_layers.Polygon(\n", - " locations=edges,\n", - " color=line_color,\n", - " fill_color=fill_color,\n", - " weight=weight,\n", - " popup=(folium.Popup(text)),\n", - " )\n", - " )\n", - " map_object.add_child(fg)\n", - "\n", - " return map_object" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/advanced_guide/polygons_from_list_of_points.html" ], - "source": [ - "# Initialize map\n", - "my_envelope_map = folium.Map(location=[49.5, 8.5], zoom_start=8)\n", - "\n", - "# Create an envelope polygon that contains some points\n", - "list_of_points = randome_points(\n", - " amount=10, LON_min=49.1, LON_max=50, LAT_min=8, LAT_max=9\n", - ")\n", - "\n", - "create_envelope_polygon(\n", - " my_envelope_map,\n", - " list_of_points,\n", - " layer_name=\"Example envelope\",\n", - " line_color=\"indianred\",\n", - " fill_color=\"red\",\n", - " weight=5,\n", - " text=\"Example envelope\",\n", - ")\n", - "\n", - "draw_points(\n", - " my_envelope_map,\n", - " list_of_points,\n", - " layer_name=\"Example points for envelope\",\n", - " line_color=\"darkred\",\n", - " fill_color=\"darkred\",\n", - " text=\"Example point for envelope\",\n", - ")\n", - "\n", - "# Add layer control and show map\n", - "folium.LayerControl(collapsed=False).add_to(my_envelope_map)\n", - "my_envelope_map" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Concave hull (alpha shape)\n", - "In some cases the convex hull does not yield good results - this is when the shape of the polygon should be concave instead of convex. The solution is a concave hull that is also called alpha shape. Yet, there is no ready to go, off the shelve solution for this but there are great resources (see: http://blog.thehumangeo.com/2014/05/12/drawing-boundaries-in-python/, accessed 04.01.2019 or https://towardsdatascience.com/the-concave-hull-c649795c0f0f, accessed 29.12.2018)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Main code\n", - "Just putting it all together..." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "# Initialize map\n", - "my_map_global = folium.Map(location=[48.2460683, 9.26764125], zoom_start=7)\n", - "\n", - "# Create a convex hull polygon that contains some points\n", - "list_of_points = randome_points(\n", - " amount=10, LON_min=48, LON_max=49, LAT_min=9, LAT_max=10\n", - ")\n", - "\n", - "create_convexhull_polygon(\n", - " my_map_global,\n", - " list_of_points,\n", - " layer_name=\"Example convex hull\",\n", - " line_color=\"lightblue\",\n", - " fill_color=\"lightskyblue\",\n", - " weight=5,\n", - " text=\"Example convex hull\",\n", - ")\n", - "\n", - "draw_points(\n", - " my_map_global,\n", - " list_of_points,\n", - " layer_name=\"Example points for convex hull\",\n", - " line_color=\"royalblue\",\n", - " fill_color=\"royalblue\",\n", - " text=\"Example point for convex hull\",\n", - ")\n", - "\n", - "# Create an envelope polygon that contains some points\n", - "list_of_points = randome_points(\n", - " amount=10, LON_min=49.1, LON_max=50, LAT_min=8, LAT_max=9\n", - ")\n", - "\n", - "create_envelope_polygon(\n", - " my_map_global,\n", - " list_of_points,\n", - " layer_name=\"Example envelope\",\n", - " line_color=\"indianred\",\n", - " fill_color=\"red\",\n", - " weight=5,\n", - " text=\"Example envelope\",\n", - ")\n", - "\n", - "draw_points(\n", - " my_map_global,\n", - " list_of_points,\n", - " layer_name=\"Example points for envelope\",\n", - " line_color=\"darkred\",\n", - " fill_color=\"darkred\",\n", - " text=\"Example point for envelope\",\n", - ")\n", - "\n", - "# Add layer control and show map\n", - "folium.LayerControl(collapsed=False).add_to(my_map_global)\n", - "my_map_global" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Sources:\n", - "\n", - "* http://blog.yhat.com/posts/interactive-geospatial-analysis.html, accessed 28.12.2018\n", - "\n", - "* https://docs.scipy.org/doc/scipy-0.19.0/reference/generated/scipy.spatial.ConvexHull.html, accessed 29.12.2018\n", - "\n", - "* https://www.oreilly.com/ideas/an-elegant-solution-to-the-convex-hull-problem, accessed 29.12.2018\n", - "\n", - "* https://medium.com/@vworri/simple-geospacial-mapping-with-geopandas-and-the-usual-suspects-77f46d40e807, accessed 29.12.2018\n", - "\n", - "* https://towardsdatascience.com/the-concave-hull-c649795c0f0f, accessed 29.12.2018\n", - "\n", - "* http://blog.thehumangeo.com/2014/05/12/drawing-boundaries-in-python/, accessed 04.01.2019\n" - ] + } } ], "metadata": { diff --git a/examples/Popups.ipynb b/examples/Popups.ipynb index 0252030b0..e125379eb 100644 --- a/examples/Popups.ipynb +++ b/examples/Popups.ipynb @@ -2,1240 +2,14 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, - "source": [ - "# How to create Popups\n", - "\n", - "## Simple popups\n", - "\n", - "You can define your popup at the feature creation, but you can also overwrite them afterwards:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import folium\n", - "\n", - "\n", - "m = folium.Map([45, 0], zoom_start=4)\n", - "\n", - "folium.Marker([45, -30], popup=\"inline implicit popup\").add_to(m)\n", - "\n", - "folium.CircleMarker(\n", - " location=[45, -10],\n", - " radius=25,\n", - " fill=True,\n", - " popup=folium.Popup(\"inline explicit Popup\"),\n", - ").add_to(m)\n", - "\n", - "ls = folium.PolyLine(\n", - " locations=[[43, 7], [43, 13], [47, 13], [47, 7], [43, 7]], color=\"red\"\n", - ")\n", - "\n", - "ls.add_child(folium.Popup(\"outline Popup on Polyline\"))\n", - "ls.add_to(m)\n", - "\n", - "gj = folium.GeoJson(\n", - " data={\"type\": \"Polygon\", \"coordinates\": [[[27, 43], [33, 43], [33, 47], [27, 47]]]}\n", - ")\n", - "\n", - "gj.add_child(folium.Popup(\"outline Popup on GeoJSON\"))\n", - "gj.add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "m = folium.Map([45, 0], zoom_start=2)\n", - "\n", - "folium.Marker(\n", - " location=[45, -10],\n", - " popup=folium.Popup(\"Let's try quotes\", parse_html=True, max_width=100),\n", - ").add_to(m)\n", - "\n", - "folium.Marker(\n", - " location=[45, -30],\n", - " popup=folium.Popup(u\"Ça c'est chouette\", parse_html=True, max_width=\"100%\"),\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Vega Popup\n", - "\n", - "You may know that it's possible to create awesome Vega charts with (or without) `vincent`. If you're willing to put one inside a popup, it's possible thanks to `folium.Vega`." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "\n", - "import numpy as np\n", - "import vincent\n", - "\n", - "scatter_points = {\n", - " \"x\": np.random.uniform(size=(100,)),\n", - " \"y\": np.random.uniform(size=(100,)),\n", - "}\n", - "\n", - "# Let's create the vincent chart.\n", - "scatter_chart = vincent.Scatter(scatter_points, iter_idx=\"x\", width=600, height=300)\n", - "\n", - "# Let's convert it to JSON.\n", - "scatter_json = scatter_chart.to_json()\n", - "\n", - "# Let's convert it to dict.\n", - "scatter_dict = json.loads(scatter_json)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "popup = folium.Popup()\n", - "folium.Vega(scatter_chart, height=350, width=650).add_to(popup)\n", - "folium.Marker([30, -120], popup=popup).add_to(m)\n", - "\n", - "# Let's create a Vega popup based on scatter_json.\n", - "popup = folium.Popup(max_width=0)\n", - "folium.Vega(scatter_json, height=350, width=650).add_to(popup)\n", - "folium.Marker([30, -100], popup=popup).add_to(m)\n", - "\n", - "# Let's create a Vega popup based on scatter_dict.\n", - "popup = folium.Popup(max_width=650)\n", - "folium.Vega(scatter_dict, height=350, width=650).add_to(popup)\n", - "folium.Marker([30, -80], popup=popup).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Fancy HTML popup" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import branca\n", - "\n", - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "html = \"\"\"\n", - "

This is a big popup


\n", - " With a few lines of code...\n", - "

\n", - " \n", - " from numpy import *
\n", - " exp(-2*pi)\n", - "
\n", - "

\n", - " \"\"\"\n", - "\n", - "\n", - "folium.Marker([30, -100], popup=html).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can also put any HTML code inside of a Popup, thaks to the `IFrame` object." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "html = \"\"\"\n", - "

This popup is an Iframe


\n", - " With a few lines of code...\n", - "

\n", - " \n", - " from numpy import *
\n", - " exp(-2*pi)\n", - "
\n", - "

\n", - " \"\"\"\n", - "\n", - "iframe = branca.element.IFrame(html=html, width=500, height=300)\n", - "popup = folium.Popup(iframe, max_width=500)\n", - "\n", - "folium.Marker([30, -100], popup=popup).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "\n", - "df = pd.DataFrame(\n", - " data=[[\"apple\", \"oranges\"], [\"other\", \"stuff\"]], columns=[\"cats\", \"dogs\"]\n", - ")\n", - "\n", - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "html = df.to_html(\n", - " classes=\"table table-striped table-hover table-condensed table-responsive\"\n", - ")\n", - "\n", - "popup = folium.Popup(html)\n", - "\n", - "folium.Marker([30, -100], popup=popup).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that you can put another `Figure` into an `IFrame` ; this should let you do strange things..." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Let's create a Figure, with a map inside.\n", - "f = branca.element.Figure()\n", - "folium.Map([-25, 150], zoom_start=3).add_to(f)\n", - "\n", - "# Let's put the figure into an IFrame.\n", - "iframe = branca.element.IFrame(width=500, height=300)\n", - "f.add_to(iframe)\n", - "\n", - "# Let's put the IFrame in a Popup\n", - "popup = folium.Popup(iframe, max_width=2650)\n", - "\n", - "# Let's create another map.\n", - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "# Let's put the Popup on a marker, in the second map.\n", - "folium.Marker([30, -100], popup=popup).add_to(m)\n", - "\n", - "# We get a map in a Popup. Not really useful, but powerful.\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Lazy loading\n", - "\n", - "If whatever you are showing in the popup is slow or heavy to load and you have many popups, you may not want to render the popup contents immediately. There's an argument to prevent loading until the popup is opened." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + }, "source": [ - "m = folium.Map([43, -100], zoom_start=4)\n", - "\n", - "html = \"{a resource that is heavy to load, such as an image}\"\n", - "\n", - "folium.Marker([30, -100], popup=html, lazy=True).add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/ui_elements/popups.html" ] } ], diff --git a/examples/Quickstart.ipynb b/examples/Quickstart.ipynb index 6bfec5c40..da2339479 100644 --- a/examples/Quickstart.ipynb +++ b/examples/Quickstart.ipynb @@ -2,2451 +2,13 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, "source": [ - "Quickstart\n", - "==========\n", - "\n", - "\n", - "Getting Started\n", - "---------------\n", - "\n", - "\n", - "To create a base map, simply pass your starting coordinates to Folium:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import folium\n", - "\n", - "\n", - "m = folium.Map(location=[45.5236, -122.6750])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To display it in a Jupyter notebook, simply ask for the object representation:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "to save it in a file," - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "m.save(\"index.html\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The default tiles are set to `OpenStreetMap`, but `Stamen Terrain`, `Stamen Toner`, `Mapbox Bright`, and `Mapbox Control Room`, and many others tiles are built in." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "folium.Map(location=[45.5236, -122.6750], zoom_start=13)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "One can use `Cloudmade` or `Mapbox` custom tilesets--simply pass your key to the `API_key` keyword:\n", - "\n", - "```python\n", - "folium.Map(location=[45.5236, -122.6750],\n", - " tiles='Mapbox',\n", - " API_key='your.API.key')\n", - "```\n", - "\n", - "Lastly, Folium supports passing any `leaflet.js` compatible custom tileset:\n", - "\n", - "```python\n", - "folium.Map(location=[45.372, -121.6972],\n", - " zoom_start=12,\n", - " tiles='http://{s}.tiles.yourtiles.com/{z}/{x}/{y}.png',\n", - " attr='My Data Attribution')\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Markers\n", - "-------\n", - "\n", - "There are numerous marker types, starting with a simple `Leaflet`\n", - "style location marker with a popup and tooltip `HTML`." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/getting_started.html" ], - "source": [ - "m = folium.Map(location=[45.372, -121.6972], zoom_start=12, tiles=\"Stamen Terrain\")\n", - "\n", - "tooltip = \"Click me!\"\n", - "\n", - "folium.Marker(\n", - " [45.3288, -121.6625], popup=\"Mt. Hood Meadows\", tooltip=tooltip\n", - ").add_to(m)\n", - "folium.Marker(\n", - " [45.3311, -121.7113], popup=\"Timberline Lodge\", tooltip=tooltip\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There is built in support for colors and marker icon types from bootstrap." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[45.372, -121.6972], zoom_start=12, tiles=\"Stamen Terrain\")\n", - "\n", - "folium.Marker(\n", - " location=[45.3288, -121.6625],\n", - " popup=\"Mt. Hood Meadows\",\n", - " icon=folium.Icon(icon=\"cloud\"),\n", - ").add_to(m)\n", - "\n", - "folium.Marker(\n", - " location=[45.3311, -121.7113],\n", - " popup=\"Timberline Lodge\",\n", - " icon=folium.Icon(color=\"green\"),\n", - ").add_to(m)\n", - "\n", - "folium.Marker(\n", - " location=[45.3300, -121.6823],\n", - " popup=\"Some Other Location\",\n", - " icon=folium.Icon(color=\"red\", icon=\"info-sign\"),\n", - ").add_to(m)\n", - "\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Leaflet's `Circle` and `CircleMarker`, implemented to reflect radii in units of meters and pixels respectively, are available as `features`. See the `features.py` for more options." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[45.5236, -122.6750], tiles=\"Stamen Toner\", zoom_start=13)\n", - "\n", - "folium.Circle(\n", - " radius=100,\n", - " location=[45.5244, -122.6699],\n", - " popup=\"The Waterfront\",\n", - " color=\"crimson\",\n", - " fill=False,\n", - ").add_to(m)\n", - "\n", - "folium.CircleMarker(\n", - " location=[45.5215, -122.6261],\n", - " radius=50,\n", - " popup=\"Laurelhurst Park\",\n", - " color=\"#3186cc\",\n", - " fill=True,\n", - " fill_color=\"#3186cc\",\n", - ").add_to(m)\n", - "\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "a convenience function to enable lat/lon popovers. This can help users to find a location by interactively browsing the map." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[46.1991, -122.1889], tiles=\"Stamen Terrain\", zoom_start=13)\n", - "\n", - "m.add_child(folium.LatLngPopup())\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "and click-for-marker functionality for on-the-fly placement of markers:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[46.8527, -121.7649], tiles=\"Stamen Terrain\", zoom_start=13)\n", - "\n", - "folium.Marker([46.8354, -121.7325], popup=\"Camp Muir\").add_to(m)\n", - "\n", - "m.add_child(folium.ClickForMarker(popup=\"Waypoint\"))\n", - "\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Polylines\n", - "\n", - "`folium` can show linear elements on a map using `PolyLine`. This object can help put emphasis on a trail, a road, or a coastline." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[-71.38, -73.9], zoom_start=11)\n", - "\n", - "trail_coordinates = [\n", - " (-71.351871840295871, -73.655963711222626),\n", - " (-71.374144382613707, -73.719861619751498),\n", - " (-71.391042575973145, -73.784922248007007),\n", - " (-71.400964450973134, -73.851042243124397),\n", - " (-71.402411391077322, -74.050048183880477),\n", - "]\n", - "\n", - "\n", - "folium.PolyLine(trail_coordinates, tooltip=\"Coast\").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Vincent/Vega and Altair/VegaLite Markers\n", - "\n", - "`folium` enables passing any HTML object as a popup,\n", - "including [`bokeh`](https://docs.bokeh.org/en/latest/) plots,\n", - "but there is a built-in support for [vincent](https://github.com/wrobstory/vincent) and [altair](https://altair-viz.github.io) visualizations to any marker type, with the visualization as the popover." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "\n", - "import requests\n", - "\n", - "url = (\n", - " \"https://raw.githubusercontent.com/python-visualization/folium/main/examples/data\"\n", - ")\n", - "vis1 = json.loads(requests.get(f\"{url}/vis1.json\").text)\n", - "vis2 = json.loads(requests.get(f\"{url}/vis2.json\").text)\n", - "vis3 = json.loads(requests.get(f\"{url}/vis3.json\").text)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[46.3014, -123.7390], zoom_start=7, tiles=\"Stamen Terrain\")\n", - "\n", - "folium.Marker(\n", - " location=[47.3489, -124.708],\n", - " popup=folium.Popup(max_width=450).add_child(\n", - " folium.Vega(vis1, width=450, height=250)\n", - " ),\n", - ").add_to(m)\n", - "\n", - "folium.Marker(\n", - " location=[44.639, -124.5339],\n", - " popup=folium.Popup(max_width=450).add_child(\n", - " folium.Vega(vis2, width=450, height=250)\n", - " ),\n", - ").add_to(m)\n", - "\n", - "folium.Marker(\n", - " location=[46.216, -124.1280],\n", - " popup=folium.Popup(max_width=450).add_child(\n", - " folium.Vega(vis3, width=450, height=250)\n", - " ),\n", - ").add_to(m)\n", - "\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For more information about popups, please visit [Popups.ipynb](https://nbviewer.org/github/python-visualization/folium/blob/main/examples/Popups.ipynb)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## GeoJSON/TopoJSON Overlays\n", - "\n", - "Both GeoJSON and TopoJSON layers can be passed to the map as an overlay, and multiple layers can be visualized on the same map:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "scrolled": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "url = (\n", - " \"https://raw.githubusercontent.com/python-visualization/folium/main/examples/data\"\n", - ")\n", - "antarctic_ice_edge = f\"{url}/antarctic_ice_edge.json\"\n", - "antarctic_ice_shelf_topo = f\"{url}/antarctic_ice_shelf_topo.json\"\n", - "\n", - "\n", - "m = folium.Map(\n", - " location=[-59.1759, -11.6016],\n", - " tiles=\"cartodbpositron\",\n", - " zoom_start=2,\n", - ")\n", - "\n", - "folium.GeoJson(antarctic_ice_edge, name=\"geojson\").add_to(m)\n", - "\n", - "folium.TopoJson(\n", - " json.loads(requests.get(antarctic_ice_shelf_topo).text),\n", - " \"objects.antarctic_ice_shelf\",\n", - " name=\"topojson\",\n", - ").add_to(m)\n", - "\n", - "folium.LayerControl().add_to(m)\n", - "\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Choropleth maps\n", - "\n", - "Choropleth can be easily created by binding the data between Pandas DataFrames/Series and Geo/TopoJSON geometries. [Color Brewer](https://colorbrewer2.org/) sequential color schemes are built-in to the library, and can be passed to quickly visualize different combinations." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "\n", - "url = (\n", - " \"https://raw.githubusercontent.com/python-visualization/folium/main/examples/data\"\n", - ")\n", - "state_geo = f\"{url}/us-states.json\"\n", - "state_unemployment = f\"{url}/US_Unemployment_Oct2012.csv\"\n", - "state_data = pd.read_csv(state_unemployment)\n", - "\n", - "m = folium.Map(location=[48, -102], zoom_start=3)\n", - "\n", - "folium.Choropleth(\n", - " geo_data=state_geo,\n", - " name=\"choropleth\",\n", - " data=state_data,\n", - " columns=[\"State\", \"Unemployment\"],\n", - " key_on=\"feature.id\",\n", - " fill_color=\"YlGn\",\n", - " fill_opacity=0.7,\n", - " line_opacity=0.2,\n", - " legend_name=\"Unemployment Rate (%)\",\n", - ").add_to(m)\n", - "\n", - "folium.LayerControl().add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The legend on the upper right is automatically generated for your values using 6 same sized bins.\n", - "Passing your own bins (number or list) is simple:" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "bins = list(state_data[\"Unemployment\"].quantile([0, 0.25, 0.5, 0.75, 1]))\n", - "\n", - "m = folium.Map(location=[48, -102], zoom_start=3)\n", - "\n", - "folium.Choropleth(\n", - " geo_data=state_geo,\n", - " data=state_data,\n", - " columns=[\"State\", \"Unemployment\"],\n", - " key_on=\"feature.id\",\n", - " fill_color=\"BuPu\",\n", - " fill_opacity=0.7,\n", - " line_opacity=0.5,\n", - " legend_name=\"Unemployment Rate (%)\",\n", - " bins=bins,\n", - " reset=True,\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "By binding data via the Pandas DataFrame, different datasets can be quickly visualized." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Styling function\n", - "\n", - "`GeoJson` and `TopoJson` features accepts `style_function` to allow for further custimization of the map.\n", - "Take a look at the use examples below." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import branca\n", - "\n", - "url = (\n", - " \"https://raw.githubusercontent.com/python-visualization/folium/main/examples/data\"\n", - ")\n", - "county_data = f\"{url}/us_county_data.csv\"\n", - "county_geo = f\"{url}/us_counties_20m_topo.json\"\n", - "\n", - "\n", - "df = pd.read_csv(county_data, na_values=[\" \"])\n", - "\n", - "colorscale = branca.colormap.linear.YlOrRd_09.scale(0, 50e3)\n", - "employed_series = df.set_index(\"FIPS_Code\")[\"Employed_2011\"]\n", - "\n", - "\n", - "def style_function(feature):\n", - " employed = employed_series.get(int(feature[\"id\"][-5:]), None)\n", - " return {\n", - " \"fillOpacity\": 0.5,\n", - " \"weight\": 0,\n", - " \"fillColor\": \"#black\" if employed is None else colorscale(employed),\n", - " }\n", - "\n", - "\n", - "m = folium.Map(location=[48, -102], tiles=\"cartodbpositron\", zoom_start=3)\n", - "\n", - "folium.TopoJson(\n", - " json.loads(requests.get(county_geo).text),\n", - " \"objects.us_counties_20m\",\n", - " style_function=style_function,\n", - ").add_to(m)\n", - "\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "colorscale = branca.colormap.linear.YlGnBu_09.scale(0, 30)\n", - "\n", - "employed_series = df.set_index(\"FIPS_Code\")[\"Unemployment_rate_2011\"]\n", - "\n", - "\n", - "def style_function(feature):\n", - " employed = employed_series.get(int(feature[\"id\"][-5:]), None)\n", - " return {\n", - " \"fillOpacity\": 0.5,\n", - " \"weight\": 0,\n", - " \"fillColor\": \"#black\" if employed is None else colorscale(employed),\n", - " }\n", - "\n", - "\n", - "m = folium.Map(location=[48, -102], tiles=\"cartodbpositron\", zoom_start=3)\n", - "\n", - "folium.TopoJson(\n", - " json.loads(requests.get(county_geo).text),\n", - " \"objects.us_counties_20m\",\n", - " style_function=style_function,\n", - ").add_to(m)\n", - "\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "colorscale = branca.colormap.linear.PuRd_09.scale(0, 100000)\n", - "\n", - "employed_series = df.set_index(\"FIPS_Code\")[\"Median_Household_Income_2011\"].dropna()\n", - "\n", - "\n", - "def style_function(feature):\n", - " employed = employed_series.get(int(feature[\"id\"][-5:]), None)\n", - " return {\n", - " \"fillOpacity\": 0.5,\n", - " \"weight\": 0,\n", - " \"fillColor\": \"#black\" if employed is None else colorscale(employed),\n", - " }\n", - "\n", - "\n", - "m = folium.Map(location=[48, -102], tiles=\"cartodbpositron\", zoom_start=3)\n", - "\n", - "folium.TopoJson(\n", - " json.loads(requests.get(county_geo).text),\n", - " \"objects.us_counties_20m\",\n", - " style_function=style_function,\n", - ").add_to(m)\n", - "\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For more examples and use cases please take a look at the gallery:\n", - "\n", - "https://nbviewer.org/github/python-visualization/folium_contrib/tree/main/notebooks/" - ] + "collapsed": false + } } ], "metadata": { diff --git a/examples/Rotate_icon.ipynb b/examples/Rotate_icon.ipynb index ca3666e40..10fd352b1 100644 --- a/examples/Rotate_icon.ipynb +++ b/examples/Rotate_icon.ipynb @@ -1,45 +1,15 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "import folium\n", - "\n", - "\n", - "m = folium.Map(location=[41, -71], zoom_start=4)\n", - "\n", - "kw = {\"prefix\": \"fa\", \"color\": \"green\", \"icon\": \"arrow-up\"}\n", - "\n", - "angle = 180\n", - "icon = folium.Icon(angle=angle, **kw)\n", - "folium.Marker(location=[41, -72], icon=icon, tooltip=str(angle)).add_to(m)\n", - "\n", - "angle = 45\n", - "icon = folium.Icon(angle=angle, **kw)\n", - "folium.Marker(location=[41, -75], icon=icon, tooltip=str(angle)).add_to(m)\n", - "\n", - "angle = 90\n", - "icon = folium.Icon(angle=angle, **kw)\n", - "folium.Marker([41, -78], icon=icon, tooltip=str(angle)).add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/ui_elements/icons.html#Rotate-icons" ] } ], diff --git a/examples/SmoothFactor.ipynb b/examples/SmoothFactor.ipynb index 26aa437d7..6c813df4b 100644 --- a/examples/SmoothFactor.ipynb +++ b/examples/SmoothFactor.ipynb @@ -2,73 +2,14 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Using Leaflet's Smooth Factor Option\n", - "\n", - "[Polyline](http://leafletjs.com/reference.html#polyline) objects in leaflet are smoothed by default. This removes points from the line, putting less load on the browser when drawing. The level of smoothing [can be specified](http://leafletjs.com/reference.html#polyline-smoothfactor) by passing `smoothFactor` as an option when creating any Polyline object.\n", - "\n", - "In folium, the level of smoothing 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." - ] - }, - { - "cell_type": "code", - "execution_count": 1, "metadata": { - "scrolled": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "import json\n", - "\n", - "import folium\n", - "import requests\n", - "\n", - "\n", - "m = folium.Map(location=[-59.1759, -11.6016], tiles=\"cartodbpositron\", zoom_start=2)\n", - "\n", - "\n", - "url = (\n", - " \"https://raw.githubusercontent.com/python-visualization/folium/main/examples/data\"\n", - ")\n", - "fname = f\"{url}/antarctic_ice_shelf_topo.json\"\n", - "topo = json.loads(requests.get(fname).text)\n", - "\n", - "\n", - "folium.TopoJson(\n", - " data=topo,\n", - " object_path=\"objects.antarctic_ice_shelf\",\n", - " name=\"default_smoothing\",\n", - " smooth_factor=1,\n", - " style_function=lambda x: {\"color\": \"#004c00\", \"opacity\": \"0.7\"},\n", - ").add_to(m)\n", - "\n", - "\n", - "folium.TopoJson(\n", - " data=topo,\n", - " object_path=\"objects.antarctic_ice_shelf\",\n", - " name=\"default_smoothing\",\n", - " smooth_factor=10,\n", - " style_function=lambda x: {\"color\": \"#1d3060\", \"opacity\": \"0.7\"},\n", - ").add_to(m)\n", - "\n", - "folium.LayerControl().add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/geojson/smoothing.html" ] } ], diff --git a/examples/TagFilterButton.ipynb b/examples/TagFilterButton.ipynb index c477bd996..383fc6670 100644 --- a/examples/TagFilterButton.ipynb +++ b/examples/TagFilterButton.ipynb @@ -1,752 +1,15 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import folium" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import random\n", - "\n", - "# Generate base data\n", - "data = (np.random.normal(size=(100, 2)) * np.array([[1, 1]]) +\n", - " np.array([[48, 5]]))\n", - "# Generate the data to segment by (levels of another pandas column in practical usage)\n", - "categories = ['category{}'.format(i+1) for i in range(5)]\n", - "category_column = [random.choice(categories) for i in range(len(data))]" - ] - }, { "cell_type": "markdown", - "metadata": {}, - "source": [ - "Create markers, and add tags to each marker. There can be multiple tags per marker, but in this example we add just one.\n", - "\n", - "Then, create the `TagFilterButton` object and let it know which tags you want to filter on." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "from folium.plugins import TagFilterButton\n", - "\n", - "# Create map and add the data with additional parameter tags as the segmentation\n", - "m = folium.Map([48., 5.], tiles='stamentoner', zoom_start=7)\n", - "for i, latlng in enumerate(data):\n", - " category = category_column[i]\n", - " folium.Marker(\n", - " tuple(latlng),\n", - " tags=[category]\n", - " ).add_to(m)\n", - " \n", - "TagFilterButton(categories).add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins/tag_filter_button.html" ] } ], diff --git a/examples/TilesExample.ipynb b/examples/TilesExample.ipynb index 657496377..f1e5451d3 100644 --- a/examples/TilesExample.ipynb +++ b/examples/TilesExample.ipynb @@ -1,219 +1,15 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import folium\n", - "\n", - "\n", - "lon, lat = -38.625, -12.875\n", - "\n", - "zoom_start = 8" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[lat, lon], tiles=\"OpenStreetMap\", zoom_start=zoom_start)\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[lat, lon], tiles=\"Stamen Terrain\", zoom_start=zoom_start)\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[lat, lon], tiles=\"Stamen Toner\", zoom_start=zoom_start)\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[lat, lon], tiles=\"Stamen Watercolor\", zoom_start=zoom_start)\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[lat, lon], tiles=\"Cartodb Positron\", zoom_start=zoom_start)\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[lat, lon], tiles=\"Cartodb dark_matter\", zoom_start=zoom_start)\n", - "\n", - "m" - ] - }, { "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Custom tiles" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "attr = (\n", - " '© OpenStreetMap '\n", - " 'contributors, © CartoDB'\n", - ")\n", - "tiles = \"http://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png\"\n", - "\n", - "m = folium.Map(location=[lat, lon], tiles=tiles, attr=attr, zoom_start=zoom_start)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### There are plenty tile sources to choose from" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, + }, "source": [ - "For a list of many more tile providers go to http://leaflet-extras.github.io/leaflet-providers/preview/" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/raster_layers/tiles.html" ] } ], diff --git a/examples/TimeSliderChoropleth.ipynb b/examples/TimeSliderChoropleth.ipynb index a3cdbae09..3e2af6cfe 100644 --- a/examples/TimeSliderChoropleth.ipynb +++ b/examples/TimeSliderChoropleth.ipynb @@ -2,948 +2,13 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, "source": [ - "# Introduction\n", - "\n", - "In this notebook we'll make a choropleth with a timeslider. We'll use my branched version of `folium`, which contains a plugin with a class called `TimeDynamicGeoJson`.\n", - "\n", - "The class needs at least two arguments to be instantiated. \n", - "\n", - "1. A string-serielized geojson containing all the features (i.e., the areas)\n", - "2. A dictionary with the following structure:\n", - "\n", - "```python\n", - "styledict = {\n", - " '0': {\n", - " '2017-1-1': {'color': 'ffffff', 'opacity': 1}\n", - " '2017-1-2': {'color': 'fffff0', 'opacity': 1}\n", - " ...\n", - " },\n", - " ...,\n", - " 'n': {\n", - " '2017-1-1': {'color': 'ffffff', 'opacity': 1}\n", - " '2017-1-2': {'color': 'fffff0', 'opacity': 1}\n", - " ...\n", - " }\n", - "}\n", - "```\n", - "\n", - "In the above dictionary, the keys are the feature-ids.\n", - "\n", - "Using both color and opacity gives us the ability to simultaneously visualize two features on the choropleth. I typically use color to visualize the main feature (like, average height) and opacity to visualize how many measurements were in that group.\n", - "\n", - "## Loading the features\n", - "We use `geopandas` to load a dataset containing the boundaries of all the countries in the world." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import geopandas as gpd\n", - "\n", - "assert \"naturalearth_lowres\" in gpd.datasets.available\n", - "datapath = gpd.datasets.get_path(\"naturalearth_lowres\")\n", - "gdf = gpd.read_file(datapath)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA0IAAAGiCAYAAADKhXbfAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOydZXhc19W27zPMJGaWZWaIE8d2EoexSSmFpEnapil8KdPbNm1TSPuW6U3TNsxtoEnaMDl2zMyymHk0jOd8P0aWLYtlyZLsfV/RNfHMgT3SzDn72WutZ0mKoigIBAKBQCAQCAQCwVmEarIHIBAIBAKBQCAQCASnGyGEBAKBQCAQCAQCwVmHEEICgUAgEAgEAoHgrEMIIYFAIBAIBAKBQHDWIYSQQCAQCAQCgUAgOOsQQkggEAgEAoFAIBCcdQghJBAIBAKBQCAQCM46hBASCAQCgUAgEAgEZx2ayR7AqSLLMo2NjVitViRJmuzhCAQCgUAgEAgEgklCURS8Xi+ZmZmoVEPHfKa9EGpsbCQnJ2eyhyEQCAQCgUAgEAimCHV1dWRnZw+5zbQXQlarFUi8WZvNNsmjEQgEAoFAIBAIBJOFx+MhJyenVyMMxbQXQsfS4Ww2mxBCAoFAIBAIBAKBYEQlM8IsQSAQCAQCgUAgEJx1CCEkEAgEAoFAIBAIzjqEEBIIBAKBQCAQCARnHUIICQQCgUAgEAgEgrMOIYQEAoFAIBAIBALBWYcQQgKBQCAQCAQCgeCsQwghgUAgEAgEAoFAcNYhhJBAIBAIBAKBQCA46xBCSCAQCAQCgUAgEJx1CCEkEAgEAoFAIBAIzjqEEBIIBAKBQCAQCARnHUIICQQCgUAgEAgEgrMOIYQEAoFAIBAIBALBWYdmsgcgEAgEgpEhywqRuEw4JhOJyQBoVBJqtZR4VEloVCpUEkiSNMmjFQgEAoFgaiOEkEAgmBAURSEUlfGFY8Rkmbis9PnRa9RkO41EZRlvKNbzE8UTTGyv06jQa9ToNSr0GlXvv3Un/FujkqblhL/TH6G8xUskLqOWEgJGrZJQqRKCJhqX2VTZyVuHWjna5iPSI3xisjLicxwXRj2PalWff+s0KjLsBrIdJnJcRrKdxx9TLHpUqun3exUIBAKBYDQIISQQCEZMLC7T4A6i16gx69VYDVoA2rxh/vz2Uara/TR0Ben0R/CEokTjQ0/c1SqJ+Cgm9yejkugjmMx6DVaDBptBi9WgId1uoDDZTEGyhZkZVpIs+jGfa6wcbPJwsMnD4WYvB5u9HGry0OoNT/h5Y7JCTFYY6kyVbX6go9/zOo2KbIeRLKeRHJeJ0lQLl8xJJ8NunLDxCgQCgUBwuhFCSCAQAIkIjj8SJxyNE47JdAUidPoTP43uEFuqOtha3YUvHOvdpzDFzPICF68daKHdFxn1OU9FBAHICoSiMqFoIk2MkwSGVa9hRrqVGelWDFpVHyGkKArBaBxfOIY/HMcfjuEPx4grCiT+69kuIdjmZtux6BOXzFA0zv5GD3vq3eyp7yYalylOtVCUkvgpTDFj0KrpDkb51P1bafaETul9jpYsh5GSNAsaVSJqpqAQl0FWEuLIoleTajWgVSeiUMeiUqoTolOKopBs0TM/x0FJqgWNWpSUCgQCgeDMQgghgeAs5+V9zfz29SPUdQbwR+Kj2reyzd8TVZgcND0CpTjFQpJFT5JZR5JFR5JFT1GKmSxHIoLxyOZa/rWjgT+9dZSm7hDNnhCeYJTR6DCtWmJhrhNfKMaRFu+waWpGrRqrQYPTpCPVpscdiOIORPCEYkPuNx40uIM9EblEPZEywFCPpcZl2o1kOBKPwVico60+Ktp81HUGWFmUzMWz03tFkKIoBCLxXoHcGYjQ6YvQFYjQ4Y/Q5U/8v1atwmbUYjdqsRkSj5kOA6tLU6ZlKqNAIBAIzkyEEBIIzhION3s51OwhGleIxmVkRWHNjFQunpVGXpKJTZUdPLerkd117ske6ogxatVo1SoyHUZWFiWxINeBXqPGF46xv6Gb9ys6cAeibKho5+3Dbad0rmhcYUtV54i3D0bjBKPx05IGNxDeYQRXJCZT0xGgpiMw4OtpNj2zMm385e2jVLUHqO7wU9cZINxj0jAaUq16ZqRbMes1LM13jXp/gUCQSE1u84Vp7g7R4gkRjskszXeR6RApqwLBWJEUZaC1wumDx+PBbrfT3d2NzWab7OEIBFOKDl+Yh96v4b2j7XT5I1S2943eqCS4aGYaV8zLINdlIttp5EiLl40VHexr8LC/sbs35U2SQKvqKbhXS2jVKqJxGX84NqrIyqmQYtWzMMfRm+62OM+JzaDlQJOHPfXd7GvoZk+9m8p2/4BREMHEYtCqmJVhY0a6jRlplsRjuhWXWTfZQ5t0wrE43YEoLrOuN8IWickcbvZiNWhItekx6ab22mQkJtPiSUzCm7pDtHnDBCKJ7//aGalUtvvYXtNFTUeANJuesnQbH1qa05tSKhgdwUicrdWdbDjazoaKdg40ega81hYkmzmnKIlLZqezqjhZGJ0IznpGow2EEBIIzlDeOdLGlx7fSXcwOqr9DNpEhCXTbiTXZeSLF5TgDcd4r7wdjfpEJzIVqVY9VoOGLVWdvH24jW01ncMaJIyFgmQzn1tTxLULstBpEpPIDl+YX7x8mH/uqD/lWiPByFFJ4DDpcJi0uEw6clwmFuY6cJp0rJmR0mugcbahKEpvtFVRFB7aVMPbh9to94Vp84Z7I3Q6tYrCFDOpNgM7a7rwnlBzZ9FrSLXqyXAYmJFmoyzDysx0GzMzrFOuRqs7GOV/ntvHaweaMek05CeZ+MCibHJcJpItOtJsBlwmnZiUj5H9jd38a3sDe+rdbKvpGvF++UkmPnFOPjcszsZuPDu/iwKBEEICgYBQNM5vXjvCMzsbaDuF9Kxsp5GfXDeH1/a38NrBFlo8E5fqpdeoWJDjINmqx2XS4TLrKEu3cvHsdNQDTKgURaHDH6G2M0BdZ4B/bq9nfXn7hI1P0Jcr5mbw/atmkWYzTPZQJoy3DrVysNlDXWeAus4gtZ0BNGqJL15QjFWvJa4ovFfezsObanr3yXIYWVWSRLbThMusw2LQUt7i5aH3a/CFYyMS7klmHVfNz+T6RdnMybJN2doqWVaE2JlAFEXht6+X87s3yke1n1Gr5rtXzOTjK/ImaGQCwdRFCCGBYJpz37uV+CMxHEYtjp5i+7wkM+k2w4CCYChkWWF/o4euQARvKMZjW2p4v6JjxOlskgRl6TZWlSTzqZX57K53c/sjO8bwro5j1qmZlWnjA4uyyU8yY9AmLLDzk00jSg/yhWM9E9MAtZ0B6rsSE9T3ytuJxEdfwyIYHWadmv/94Hwum5sx2UOZcDZXdnDz/VsJRkdnJHIiWQ4ji/KcLM51sCjXSX6yiVBUxhOK4QvH0KoljFo1Jp0Go1aNUadGq56ePbIEE8OO2i42V3ayvaaTXXXuEbl03nP9XD68NJdNlR28dqCFNm8Yh0lLaVoirbg0zTrq+4lAMB0YjTYQibsCwQRS2xHg1QPN7Kx1YzdpKUqxsGZGCkUpliH3O780hXePtPGXdyr6RGB0ahXZTiO5SSbOK07mppX5aHtSZtaXt/G39VXoNQnHrpJUC2tmpFKaZmFuth2AqnY/vnB8RCIo2aLjg4uzKU2zsr22i0PNXj563ybqu4Jj/4X04I8k3MkAVhS6+k34QtE4je4gdV1B6nqETl1X4rG+M0CHf/RW3YLx46nbz2F2pn2yh3FaWF6YxNO3n8Of3jrKK/ubR10Pp9OoyHIYsejVxGSFjkCE9KiBVJuBVLF2Jxghi3KdLMp1AkVA4hrZ5g3T3FOz1dwdQlHAYkj0UrMatMzNtPGz/x7kr+9WDlgzadFrmJ9j5/pF2XxgUfbpfUMCwRRBRIQEggkiHIuztaqL5u4g3nAMs07DnCwbBckWjDr1kPvGZYUDjR78kRixuEJMlmn3RdjX0M3+xm4ON3vxhGLMzLDx8K3LSLbo8YaifPnJXbxxqLX3pmczaPjjjYs4vzSlz/HLW7wcafHhCUXxBKN4QlEkJIw6NQatmiyHgQvK0ugORnnvaBsNXUGq2gP8Z2/TKa2MQyLlZ2aGjWUFLq5dkEVukqnP6195chfP7Gw4pXMIJpY9d12M7SysBarvCvDw+zU8ta2OrsDIau9+95EFXLMgq/ffVe1+/vTWUeq7ArR6w6RZDdx93Rzyk8xidV4wblS1+/nS4zspb/ViN2pxGHXYjVrsJi2OHmt7hynxeH5pCnlJ5skeskAwbojUOIFgAvCFY8TiciJ6oUCbL+GctCDH0a9AvNEd5Of/PcSbh1rxhWNYDZreRptfWFtM4TARoZEQiydSazRqqc+ktMMXpsEdJMth5ImtdbR6QkR6irhnZdj4+Iq8XsOB4Y7/oXvfp7YzSHGqmeJUC8kWPRuPdrCtpnPUK+MXzUzlx9fOId1mGDLlR1EU6ruCHGr2cqjJw+EWL12BCJ5gDG8oiicUwxOMDtvHRzBx/OdLq5iVefZeb2VZoa4rwONb6vjHe1X90jE1Kokbl+dyTmFSv/TBg00efv3aEXbWumn3hUm3GZiZYWV+joPL52ZQmmY9nW9FcIbSHYii16owaPsvuvnDiV5o5S0+bEYtszNtZDuNIhVTcMYwZYRQfn4+NTU1/Z6/4447+NOf/sTNN9/Mgw8+2Oe15cuXs2nTphGfQwghwURS2xHglf3NvLK/me21Xf3SCyQJ9t11CeZB7GHjskJ3MIrTpD2tNxlZVnhhTyOKkjAg0GtVpFgMzM60DVvYHI7FaXKHaHAHeWlvE49trh3zOMrSrXx2dSGzMuzYjVqSLbpRuV/JssLRNh8NXUHq3UEauoI0uIOJxqTBKO2+CO2+8Jh62wjGjk6t4lPn5vP5C4rPysgQQKc/wj+31/H24Ta2Vvd1S7zl3AK+f9WsYY8Rjcu9qa0CwUQRi8u8eqCFZ3c2cKjZQ13n8fRmnVrFglwHF89K45LZ6ThM2rPW+VFw5jBlhFBbWxvx+PE0mn379rFu3Treeust1qxZw80330xLSwv3339/7zY6nQ6Xa+QN94QQEow3oWicf+9u5KH3q9nX4On3ul6jwmHSkukwcvPKfK5ZkEUsLqNWDV/c3B2M8vyuBnbVuUm3GfjgkhwKkseWkuAORNhZ66YrEMGkS9QfzM60U5BspqLNx/++cpgNR9vxnNBYM8msY1mBC/0JEaEki57rFmYxJytR8/H/ntjJC7sbx603kFmnZmGuk0W5Dm47v3DUE+fKNh/P7WrkuZ0N1HYO3PxTMLEUp1r45Dl5zM92UJxqwahVC6ewE/CFY2yu7MAXjqHXqFlZnHTWCsTJ4FgUeWedm121bspbvbgDUbqDiZ9zi5P42QfmnZV20uFYnOv+tJEDTf3vZYPx95uWEIrK7G/sRgEkEot+EhIqCTIcRhbkOITZgmDKMmWE0MnceeedvPjii5SXlyNJEjfffDNut5vnnntuzMcUQkgwnuys7eJHLx5gZ60bAJdZR4pFT2m6lSV5ThbnOSlLP97TY1t1J/e+W8l75e3IikKWw0iW05h4dBiZmWHjvJLk3vSEw81evvr0rl6BNTPDxhOfXoFJr6a5O4Req8Ju1KLX9E9n6PRHuP3h7ei1Kpq7Q5T3mA2ciE6t4uFbl7G8MAlIRFS84URKmTcUozsY5Y2DLTyxta63rwnAjDQrj39mRZ/Gl7G4TCQu4wvH6PJH6fCHicYVLHpN4segwaLTYNar8YfjNHtCicLd7sSjy6wbV2ciRVHYU9/N+vI2Nld1IisKeo0anToR8dKqVWh7+xypUEmJm3Y0LhOKyoRicQKROEdavNR0CEE1Wix6DecVJ3PFvAyump852cMRnCV0B6Lsb+xmX2M35T11jb5wDG8ohi8UwxNKXN9OjAo7TVrykszkJ5nITTKzdkYKC3Odk/guTo1YXGZ3fTehaLznRyYUjWM3alle6MITirG1qpOt1YmfijY/EvQuVkQmKGJu0qmZl23n3KJkPrYib1o2To7LCo3uIFXtflo8IVRSomG4pqd5uEGrItdlIsdlEtHbacSUFEKRSITMzEy+8pWv8J3vfAeAm2++meeeew6dTofD4WD16tX85Cc/ITU1dcTHFUJIMBGEonFUkjRoLU0sLvP7N4/yxzfLh42cWPQaLpqZyqVz0slymNBpVDywsZrHtyRSzpwmLf5wvLfO4KZz8vjhNXMGHNNnH96OWZ+w2X3jYMuABduP3Lqc80qSgYQQqu7wc6DJQ7bTxPxsO5Ik0eAOcu7P3+y3b5bDyCWz01mY60CvSeSXm/UabAYNBq2aZk+Imo6EbbUnFCUYSYiLUDSOVqPC1LP9ikIXa8tSBxR0U4EOX5hddW521rrZVtPJpsrOyR7StEGnUbH7+xcPa/ghEIwWfzjGzlo3u+vd7GtIiJ8T07hOxKhVU5hipijFQlGKhYIUMwVJZnKTTNMy8hONy+ypT5jheHts1QPhGL5wYvFmb0P3gPtJEgM6wp1uFuc5+dfnVk72MEaFLCt89pHtvHagZdht1SqJHKeRgmQzBckWCpJNrJmRSo7LhKIotPnCuEyjS/0WTBxTUgg99dRT3HjjjdTW1pKZmVhNfPLJJ7FYLOTl5VFVVcX3vvc9YrEY27dvR6/XD3iccDhMOHzcTtjj8ZCTkyOEkOC0sqWqk5f2NFLXFSQQiaHTqNGpE8JJp1ah06iQkKhq93OwydOne/zJ6NQqjDo1Zp2abKeJe26YN6J0uc8/toP1R9rwhGLo1AnL7HOLk/jthxcgSRLP72rgu8/uw3fCuRfkOLj3E4tJsxm49YGtvHGodVx+HwNhN2p56Uvnke00Db/xJOILx/jAnzdwpKV/hE3Ql5VFSVwyO52r52finIarv4Kpx+FmL09urWNrdScHmjyDNpstSbWwblYaywuTKE61kGEzTNv0THcgwqv7WwjF4nhDsUQkp6oTf+TUHDlPN8fSns8tTuayOenkjzHNe7Jo84b51auHeWV/84hdII+xdkYKf/n4YgxaNZVtPn784gH21HcTkxWSzDpSrHrS7QbSbAaynUaunJc5LSNm05UpKYQuueQSdDodL7zwwqDbNDU1kZeXxxNPPMEHPvCBAbe56667+OEPf9jveSGEBONFNC4TjMax6DRjutG2ekN87pEd7GvoJhyTSbPpKU2zMiPNSmm6ldI0K6lWPWadBqNOPSIHt8FQFIVIXB40lW53XWJltTsYxR+JkeUw8tnVRWjVKrqDUfY3dFPvDlLfdcyIIECbN4w7EKUrEOkX7VKrJKwGTW96nNWgwajT4AtFafOFicRk8pISK7MrilxcPjdjykaFTqamw8+jm2v567uVkz2UKYskwc0r8/nGJWUiIiQ4ZWRZ4aW9TXzx8Z39XlNJsDTfxbpZaVw0M23aTbIHQlEUHnq/ht+8fgT3KCfeU4HZmTYW5DiYn+NgYY6DwhTLGVEjFI3LbK7s5J0jrThMOgqSzeS6TJh0amQl8XeTFZAVBVlRUBQoTbP2u3crikJdZ5DyVi++cCJtU69RsW5mmlg4Os1MOSFUU1NDYWEhzzzzDNdcc82Q25aUlHDbbbfxzW9+c8DXRURIMJ5sONrOz/57kE5fhEA0TuCEFDWDVkV+kpkclwmjVo1GLaFTJ2pRzHoNK4uSWF7o6jfRVxSFaFxBo5KmxIqloihUdwTYWNFOMBLvqaGR0KhVpFr15LhMZDuNmHR9ne9kOSGyjtXaqCQpUTB7hlusPrWtjm8/s3fQlemzEZdZx3ULszinMAmjTt2bMy8QjIWqdj/P7qjnmZ0N/Ro0SxLcem4Bn19bfEZOHt881MI3/rmHdt/0aQqtUUl8cEk2KwqTyEsyU5Jq6XVK7Q5Gp2UqouDMZjRCaGDP33Hm/vvvJzU1lSuuuGLI7To6OqirqyMjI2PQbfR6/aBpcwLBaDm3OJnPrynmc4/u6PdaKConetk0ewfc9//eqcBm0PCBRdl84YJiki2Jz6UkSeg0oxcLh5o9vF/RQSQmo0CvOcNAwmNvfTePbKphV52b4jQLhclmQtE47kAUdzDKHWuKWJjrxB2IcMejO9hY0THkua+cl8GPrpnTG7qXZYXttV1Utvlo8SS6l3cHo3z5olKKUxM9kLqDUY62+jja6uVoq4/uYJTPry0mL8nMI5tqeONgS2+NkVmXeFycl0ijGKi3xVThQ0tySLMZuOOR7dMuVWWi6PRHeH5XIxeUpXJucfJkD0cwjanvCvDr147wwu7Gfq8VpZj55Qfns2iaGRv89d0Kdtd30+gO0tIdAkCtltCqVGjUEooC3h5Th+l4TYnJCo9vqePxLXW9z2U7jSgKNLiD3PfJJWhUEnsbumn1hmj1hFFJEma9Bos+ce239GQSXLswa0hHxep2P3948yjJFh0uc+LHqFOjKKAAOc6EY91ELsi5AxGe2lbH6wda6QxECIRjzM22c15JCpfMSiPVZpiwcwtOPxMuhGRZ5v777+emm25Cozl+Op/Px1133cX1119PRkYG1dXVfOc73yE5OZnrrrtuooclEADw5NZavvf8/lHtI0mJWptzi5JJMuvoCkb5xj/30OGPsCzfyTcvLUOjVhGJyXQHo6RY+wr3E1fQ9jV088TWWnyhGDkuE4FInDcPtdLUHeRH18xhSX5/K/m4rLCtppP/7G3CG45xuOW4UNNrVHz/qlnM7bHC3nC0Y1ARpFFJzMq08c1Ly/pMbp/b2cBvXj/Sz1ntmAhq6g7ymYe2D1i8+9yuRj63uojzS5N590gb/93X3G8bs07N2rJUvnVZ2ZStH1pdmsJTt5/DrQ9so9kTmuzhnHYcJi1fWFvM6tIUDFo1aTbDKaVwCgTRuMzL+5q5f0MVO3pcOY+hU6u4Y20Rt68umtBFku5AlD0Nbix6DWk2AylW/bg4gb11qI33K4debDrTODGS99mHt4243cL7FR0syXdh0KowaNQYtGqMusT/67VqDjV7+NeO+iGPkWk3cOmcDD51bv6ERKbjssK5xcnMz3bgCyeMK2RFQUKixRMWQugMY8JT41599VUuueQSDh8+TGlpae/zwWCQa6+9lp07d+J2u8nIyGDt2rX8+Mc/JicnZ8THF65xgrHyyKYa/ue5fSPaVq2SuHxuBmtKU2j1hnl5XxP7Gz3ETrr6z8u2YzVoqOkI0OgOIiswJ8vGdQuzKUg28cDGGt490sa8bDvfvLSM+TkOLvvdu32ckTJseu68qJQPL8vtc2xFUfjofZtwB6LYjFoiMZldde5+YzVoVZxTmMTHV+SxvDCJy3+3vk//nQvKUvn6JTMoSrH0m9y+fqCFTz+8bVAXoptX5vPyvuZhxcH5pSk8dMsyajr8dPojOE063j7cyvuVHZSl25ibZWNJvguHaWqnvnhCUT587yYOjqIHx3SmMMXM3Cw7e+q7qWr3s2ZGCg98atlkD0twBjCYOcuqkmR+dM2cMfdTGylvHmrhtgf7T9iTzDpWFCbxp48t6n2utiPAh+59n3/cvJRZmcPPK+76934e2Fg9ziMWDMfMDBvPfX7luNWhyrLCu+Vt/HdvM+8caUOrkXAYdThMWhwmHQ6jFqdJi92kw2nSnvS8DptRe0bUTJ0JTKnUuIsvvpiBtJbRaOSVV16Z6NMLBAPy1LY6vvf8yETQ2hkpfOfymbjMOm59cNuA4uMYe+r7R0n2NXjY13Cg33affXg7z96xki9dUMLX/7mn97UmT5if/vcQF8xM6xNNkiSJxz+9gv2NHl490MKr+/tHWyCR0vfW4TYW5jq5cGYav//oQv7xXlXvKtdHl+UMmlbwi1cODWnFOtKbvTsQ4Wf/PUhVm5/qDj/V7YHe2qtX9iesSrVqiblZdi6dk86V8zLJdBhHdOzTRTQu88uXD581IggSE4GYrPDhpTlcWJZKmy88/E4CwRBsrGjn9QOt7K53D/j6dy6fOeEiqKk7yNee3jNg1KLDH6HdF0aWFVQqCVlWqO0M0B2M8q8d9ThMBWyt7mRbdRd7G7oJRGJEYnKiDlQtcV5xMmtnpNLiCQ0YARdMHNcuyEQ3jnbVkgT/3t3IMzsaep+rY2D79sGwGTQ4zQlx5DDpWF2aws0r86dEvbBgYE5rQ9WJYKpFhN4rb6e6w4/VoGF2pp3CZPO0+AIoinLGF8GfSJc/ws66LrZVd7Gtpovdde4+DfmOUZhi5s2vrkFRFO55+TBvHGyhpuP4pP5UybQbehzd+ueNf3BxNr/84Pwh96/tCHDvuxU8sbWOuKwgSYnmqEvyndxybgEWvYYfv3SQF3Y3otOoyHYYuWxuOp9YkU+6vX94/0cvHOAfG6rG5b2Nlnuun8u6Wem97nUpVgOL8yavVmBTZQe/fu0I3lCMPJeJ8lYvFW3+SRvPRKJRSf2imzq1iusXZ/Hli0pFKohgzDy6uYY/vnmUpu6Bo8ifXlXA1y8pm5DUyzZvmPvWV/LIphoCg9TmXDkvg199aD7hmMx971byr+31NPaM9fWvnM8zOxr489sVw57LpFMPeg7BxJDlMPKja2Zz4cy0Ps83uoPc+uA2ilMtrC5NYVm+izZfmIo2HxVtPvRqFUWpFopTLeS6TLxf0cHehm5cZh1mnYYfv3SgT8PxU+WcwiRuWpnPeSXJWPSnpTT/tKMoChVtPopTrZM9FGAKusZNJFNNCN3+8HbeOdKGSaemONXC2rJUPrOqcMqIIUVRcAeimPUaOv0RXtzTyL93N3KkxUuuy0Suy8zlc9O5bmEWnmAMpESqlU6tOqOFkjcU5Zv/2oMnGGNmhpWZGTZmZtj6pY/F4jLvVybqbo40eylv9VHXFZiQhnY6tYrHP7OChTmOYT8/0bhMlz+CXqPGbtL2vqeVP3tzwB5GOrWKu6+dw4eW9k1DbfWGONLs49UDzTy9rZ5gdHJv7DcszuZLF5SQ4zJO+udPURR21Lr55/Z6XtzTOK43yskmxarnnuvncv+GataXt/d57fpF2fzqQ0MLcsGpoygKG4520O4Lo+3pRRaLyzR1h2j2hGj1hMhPNrM038WCHEeva9d0wR+OUd3h54cvHGBLVd8GxilWPR9bnsuNy3NJtY6P6P7Vq4e5b30loejQi1ZOk5afXz+Pi2el8dLeJu769wHaeyKhWQ5jYqJ8ltX/TDdWlSRzYY+RS5JFz4fufZ+jrVOvL5xOrWJZQaLZ+AVlqWTYDQQicfzhWOIxEiMQ7nmMxDBo1LjMOpIsOpIt+imbSv7K/mZ+9MIBJAne++YFkz0cQAihSWUqRVZkOdHtuL4ryO46d6JpW3VX70V+KPKTTFSfUCw/I83Kh5fmkOlIFJh6gjG6AhHSbQYKUyyk2fRT5n2fTJc/Qn1XkNJ0y7jkEr+4p5GNFR3E4wpxRUGvUSUKPrVq9BoV7mC0J6oR5Gir75TFRKpVz9oZqawtS+GcwuReoTMcNR1+Vv/y7SG3ue28Ar59+cw+ec01HX7+/FYF68vbaPOFicYn/xJh7llYKE61UpKWaKxYlGI5Lec+0uLl+j9vxB+JYdFryE0ykWo1cLjZS4N7dGkTUxGbQcPHV+Rx+5oibAYtu+vc3L+hCq1aRYbdQLbLxAcXZ0/Z7/eZwM7aLn72n0Nsqe4cfmMSNYuzM20sy3fxkWW5vU6O04HuQJQGd5BgNE4wEk88RuOEInHsJi0XzUwblzqLrzy5i2d2Ngy/IZDjMvL219aiVkk0dQdZ88u3B8wQEEx9tGppStyzJoKLZqbx/StnkZs0tUyGQtE4gUgck049ZRxhhRA6ywlG4jy2pZa/r6/sDfFPNCadmrwkM06Tttcu2W7UUphiQaOWaOgK0uYNk5+cKMaenWnDZdaN2+QqFI2zo6aL8lYflW0+OvwRbl9dRJJFx0//c4gXdjeSbjNw50Ul3LA4G406sdr6/K5GVpUk96b+hKJxVJI0bJqGoii8sr+Z/Y0eGt0hmrqDuANRdBoVeo2KYDROTUciz3w8UUkwN8vO2rJU7ryotM9rtR0BHtlcw9wsO+cVJxONy3z9n3t472j7oD1xZmbY+MNHFw46kVIUBU8wRpMnSE1HgJoOP4ebvTR7QvjDcbyhKJ5QDE8wOuDEwWbQcOHMNHKcRh7bUjtuvTMkCa6Ym8EvbpjXr//RePOrVw/zhzePDvia1aCZ9pGh4lQLNoMGjUqV6DGlltCqVczLtnPdwizykqZ/I8vJpssfYV9jN3vqu9nX0E15qw+1JGHQqlAYuLYQElbBaTYDUk8fr2ZPkJqOhPguS7fyfx9fTH6yGUVR6PRHSLKcua0lonF5VA5v7kCE1b98e0TXYLNOzb4fXgLA5x/bwX/2ilofwdTkoVuWcX5pyrgdrzsQ5R8bqnCYtCRZ9CT3RJ+SzDocJh3RuEwkLifaeiiQbBm/edtEIoTQWYyiKPzwhQPTwsHGotdwXkkycVlJNGh0GilNs7Ik3zWgEGnxhNhY0c6OGjcGrQqXWY9Oo+L9inbeO9reLwVCkhgwZa0w2cwNS7L55/Z6Ktv8fO/KWaTbDFS0+bjv3Uq84RhatcSsTDvnlyRzfmkKszNt/SbcdZ0BvvPs3n6pRBOFzZDowWA1aMhxmvhIj6vc4WYv/3iviud2NfSKEZUEywuS+O4VM8l0GHlgQxX3vlvZR6xoVBJrZqSQ5TCSbjdy8eyRRVku/916DvQYCDhMWtKsBlJtepYVuLiwLA2LXoPVoOnnoKMoCsFonINNXu5+6QA7T7LQHQsrCl384+alEyqGdte5uW99JRsrOghEYhSlWFhW4OKimWkkWXRc+tv1E3bu082sDBuXzUnnsrnpUybXe7qiKAqbKjv567sVvHW4rc9rWpVEdBi/4eUFLjaflEKmUUmk2vQ0ukMYtWpmZdqYn23nnSNtVLT5mZtl5/pFWVw1P/OMEkW/ff0Iv329HJdZR5rNQJpNT5o18ViWYWNxnpO0k+rYajsCfPGJnbR7w8NGbufnOHj+8+eyvaaL6/+ycSLfikBwSizp6cU3J8tOuy9MRauPZk+IWE+GiqIoOE093xO7AYdRiz8c6+1jNTvLzsWz0nrFzHM7G/jyU7tGnN5v1qkpTrNSmmqhNM1KcZqFBdmOKdf8WAihSaSyzUeOyzQuvQmGo7YjgDccJRZXiMZl3q/o4NmdDVS2T5+C7oU5Dnae5MJm1WtYPSOFVSXJvTe3h9+vGdB69XSS5TBSlGqhKMVMYbKZbJeJLLuB2q4gahUkmfXUdgbYUePm4U3Vw4bntWqJohQLszJslGVYSbcbseo1xGSFqnYfFa1+Ktt9tHrDdPgi+MIx/t+FJXx5Xd9IkCwr7Kxz85+9TXQFIqRaDZS3eNle24XdqOWpz55Dms1AXWeAdb95Z9Cc+Xuun8sFZWn88pVDxOIKX15XOmCPhtW/fKtfj6FjqCT45qVlfHZ10ZDvfXedm1sf3DrmCJFWLbEwx8mKoiSuX3R6ohZyz8T1WL2Woih8//n9PLypZsLPPVHoNSrOKUpi7YxEzvpE9OQ424jFZV7e38xf363sE+nJdBjIdpgwaFVUtvvJchipavejkkCrUdHpi+CPxNGqJBbkOthR6+4XyV1e4CImy3QHolS2+wft3SJJ4DTpSDL3rO72rPKWpVu5oCx1Us0vPKEoipyIpg5V++gORHprIuKywuNbavne8/sGnbBlO41cNDONi2ensSzfhabnHizLCt//9z6e2FLXzxDkGEvynDx06zL0GjV/efsobd4wT2+vF+YHgjOSOVk2vrKulLUzUukORvnlK4d5dHPtmI+nkmBpvotrFmRx4/Lc4Xc4DQghNInc/vB2NlS0c0FZKhfPSmf1jJQJcQl5flcDdz45chU/VVmQ4xjSjno6oVOruGhWKl+6sARPMMaWqg4seg3mngiJ1aDt86hWSTywoZqt1Z0Eo3G8oRiN7iB5SWaumJvOzT2ub8cIReNoVFLvDf5k3IEIr+5vobYzwIx0Kwty7D2NMBM5u28dauVTD2wddPyrSpLZVevuNVfQqVW89KXzKEk7Hhl442ALtz00eJ8hs07Nrz60gEvnpA/7+/KHYxxt9XGkxcuO2i5eO9AyYmF0XnEyl8xO4/zSlNOauhWJyWysaGdTZSfvV3awexp9dnVqFZkOA5kOI8WpFtbMSNScGXVTI6d7uuMPx3h6Wx1/31BFXWeQPFci0iorCpGYjF6jYkt1FwAaFczOshONyRxoSjREliTIc5nwhGJ0+gf+HizOdbB9HCKp87PtXDgzjQvKUpmdaRsy1cUXjvGv7fW4zLrez0+q1TDiOp4OX5gtVZ1srupkU2UHTd0hvnZxKTcuz8MXirG1upOYrBCXEwt6exu6eedIG0dbfawqSebrl8ygrjPIT/9zcMQ1eU6TlgtnpnHJ7HRWlSRj0Kp5bHMt33l276D7pFr13HX1bC6fm8GzO+v58pO7R3QugWC6kmE30OwJjds8MttpFGYJk8FUFEIvn9DfRadWsWZGCh9cksOaGSnjFilKWBX62VbdyfO7Gqetq81AEaHpyrnFSdyxppiVRUn9JhayrBCIxqlo9dEZiLC6JAVZUXjjUCu/evUwR1r6O9wkW3R8cEkO0ZhMIBpnbpadcwqTyEsy9R4/LiuEonHUKonazgAX/+bdPsf41mVl5CeZeO9oO5srOykfhZNOskXPlu9c2Ltqu6fezUf/umlAq+9j3Lwynx9cNWvIiZU3FOWOR3dwoNGD3aTlK+tKuXJeJnFZYUdtF//7yuF+KUFDkZdkYmVRMsWpFvKTTJSkWiekmFRRFL729J5hu55PJjq1inWz0rhoVioGjRq1SiLNlpi8Jpl1U8a98kyi1RPigY3VPLq5lu5glMW5DtRqFe5AZMDv9cnkJ5mwGbWD1gmdiE6jYl5PSkz1IFHZ0ZJhN3BBWSpXz89keWHSgNtsruzgw3/d1PtvtUritvMK+NZlZf2+643uINtqutha1cnmqo5+v4Msh5HCFDNWg4Z3j7TjG8DVcjwx6dQsynWyoaJ92Anf329awoUz0zjS4uXG+zaPyFhIIBAkmK5CaHr5b05DInE50fzyQAvJFj0fWJTFBxdn91llHwuSJPW4aFn4yLJc9tZ3851n97K3YfibqWBi2HC0gw1HO7DqNaTY9ETjMoFwwk3lZOe4+dl2PnVuAS/tbRp0stTui/CXAfpXZNoNJFv1tHrCtPnCgxohAOyqdfPr144QGYMDUrsvzBcf38mPrpnNP7fX86tXjwzbP+mBjdXkJZn41LkFg27z3K7G3roqbyiGO5AoZlarJJbmu3jwlmVc9rv1VI0wxTNh4tA3rH/j8ly+dVkZNsPIHPZGwp/frpjSImhFoYvffWRhv1oJwcTx1uFWvvT4zl7DjGUFrn7W0MNR3RFgfo59RNtGYjLbarooS7di0KgIjYOzWVN3iEc31/Lo5lquWZDJ7z6ysN82L+5p6v3//CQTX7l4BqlWPZG4jF6jprLNx69fO8L2mq5B+wUdo8EdPK1ui4FInPeODl3HadSquevqWVw4M41ITGbD0XbisnCNEwjOBoQQOo20+8L89d1K/vpuJf/50iqe39WATqPCotdgMWiw6DWUpiV62IyWudl2/vW5lTy7s55X9rfwXnn7uDX9FIwObziGt23oVc7d9d3c+eSuMR2/sTs0YjfAE6OTY+GlvU28eqB5RHakNoOGK+ZlctFJze1O5toFmaTbDJh0akrTrKRY+xZ1v7K/mVbPqbkdPra5ljcOtvD/Liwl3a7HqNWQn2wiw24c0/EURcGsU2PVawbsyzTZfGFtMXdeVDJo2qRgfFEUhb+8U8EvXzncG2VYkucctQg6fsCRb1qWbqW8xctEOAQ/v6uRe66f188C96aV+eyo7WJ/o4e4olCaZqEs3UYsLlPbEeAPbx7tI5amEyc6ZyqKwh/eLB/UJVIgEJx5CCE0STy3q4H3ytt73bdOZHVpCl+4oJil+a4hjyHLiU6+O2vd7Kp34+8ppv/w0lzafWHufGLXsCthk47I1JnynCiCzilMItdl4p0jbciKQobdQH6ymcvmZLC2LGVEfZqsBi3rZvUXS+FYnB+9cGDERZtatURqj2Pd0VZfPxvrFk+4T03AU589Z8xCSJIkrpqfyT0vHx7T/hNBXpKJS+ekc9W8TOZkjSyiMFL84RgtnhCt3jAmnZq5WfZ+KVBxWelTJ9LuC/Pq/hbqugKYtGqMOjUfXpqDdRyjclOBQCTG1/+5h5dOmPjPy7azo7ZrzMccTc+aIy1eFuQkzBQGwmrQ8M1Ly7h4VhpH23wcafZyuMVHeYuXwy3eAe3eJQnWzUzjjrXF6DUq3q/o4GirF7tJx8qiJAqTzeQlmdjf6KGuM8ilv11PlsNIiyc0qAHBdOCq+Zn88oZ5dPgjfOnxnWyt7hw2oiUQCM4shBAaZ9LtBj5zfiGhaJyH3h/cTeqv71YO+to7R9p450gbn15VwHcun9lnAlLd7ueNQ628c6SNnbVd/W5qnmAUtSrRUCwuK6gkBnUWmhJM5bEJ+pDrMvGrD80n0zE2MTEcv371yKica372gXncsDgbgDZvmJ/+5yDPDtBAUadR8ZV1pSzNd57S+Dr9EZKtOuo6T38T1RSrnpkZNnJdiUL1i2amMTPDOiH9HN450sZnHtrWZ3I+P8fBLefmc05hEq8caOG5nQ3sqXczK8PG/BwH5S0+Nld19LnWpNn03DJEiuR0pLYjwGce3sahZm/vc/Oy7Rxq9o7pOmvRaxIpzilm1s1K44XdjcPW/sgK7Kxzsyh3YDHkDcX4n+f28dd3K/nyuhJuPuFvoCgKzZ4Qh5u9VLT5cZm1lKRaKUwxoyjwzM4GvvHP3X3SdTUqiRnpVvY39l20OxOaCb+wu5HXDjSjlqQhax8FAsGZizBLGGe+8NgOvnRhCU6Tjj+8WY5KShQrdwUi7K5zD1oErlVLfPKcfOxGLTaDhjlZdhbnOftMdLoDUf74VjmPba49Yy7aC3Md49JPRjCxzM+28/ebl/KDf+9nR00XD9+6DGDUvWaOtvqIyTKyDLKiEIjE8QSjeEJR3jrcxgu7G0d8rMV5Tv7nipkszD0ucN6v6OA3rx/pTVFamOvglzfMG7eeOP5wjF+8fIgHh1jkGA/WzkjhgrJUilOtlKRZSD5NPWEUReHd8nZqO/w0dodo7g7xn71No4pYnMjFs9L4/lWzyHZOf1vuV/c389Wnd/dZfFqS52RHbdeoRZBBq+IHV83mI0tz+lzjFUVhf6OHWx7YSqt38EJ9lQSladY+gmwgilLMvPHVNcOOZ+PRdj778PYpmfYpEAimB9PVLEEIoXHmaKt30ElXLC7z9X/uYXNlR78aD5dZx47vrRvRObqDUb75zz0jqv+wGjSYdGpaPFPT/UYIoalPht3Ay//vfBQUlv7k9T6pckvynFw2N4OLZ6UN24Pmb+srufulg+M+vrUzUrh6QaI26VgaVlN3kF21bi6enT5im9/R8PnHdvRJjRpPfnLdHG5cljtp3btjcZnNVZ2sL2+nqTvIq/tb+pl9jBSTTs3XL5kxpHnGVCcal/nlK4f7RfHHYoxwjIdvXcaqkv7d4avb/Ty1rY7HttT2mogMxEivm0lmHdtPuK+8vK+ZBzZWMT/bwTlFSSzNd2HWa5BlhS89sXPa1vkIBILJxWrQ8MHFOXz/qlmTPRRAuMZNKkOtPGvUKn7z4QVAwmL06W31PL+7gUA4zuJRpO3YjVr+9LFFVLX7KG/xcbTVh0olkWTWYdCq2V7TRbbTyKVz0tGqVdz24LYpK4QEUxeVlHBf++q6GdhNWtaXt/UzTdhW08W2mi5+/OIBCpPNXDEvg69ePKPfsWJxmTZvmFSrHoXERdN6gknIR5bmsqW6k5f2NFHbOTpb4LcOt/HW4TZ0GhVfWFvMly4sIcNuJGPuxKTwAZSkWibkuCoJPrY8b0KOPVI0ahXnFiczO9PGzjo3wUicVw+0jOoYyRYdF5Sl8pV1M0i3T18Xu30N3dz17/1sq+lf/zPWNUS9RoVG1dfU4kCjhz+/fZT/7G0aUXRpZ62b5T1CbKjNu4NR3jrUyuJ8JzaDlnS7gaOtPjZVdnLvu5VoVBILchzoNCq2Vo/R6EEgEJx1SBJctzCLi2elY9AmGnOPpEZ4KiIiQlMMXziGWace19Xg7TVdXP+XjeN2vPFERISmDskWPZ89v5CCZDMmnZosp7G3WWmrN8R3ntnH6wf7TogdJi2fX1PM3oZu/r27EY1K4gOLsojLcNPKPOZlO0Y1BkVR2NvQzQu7G3lhdxPNY3CP+7+PLx5RQ9dTocsf4co/vDfudRLrZqVx3yeXjOsxT4WNR9t5clsdje4gje4QzZ7QgHbtuS4TS/NdLCtwsjTfRUGyedIiWuNBRY8d9MlRP7NO3eMuBvXuAJ3+waM2J6PTqLhxWS53rCkitcfifFedm9+/Uc6bh1pHPcYcp5Gm7iAjyVqUJJidaePS2encv6GajkEatgoEAsFoWDsjhb/ftHTK9agTqXHTmCe31rK/0UMkJnOo2cv5JckUpVo4pzCp9+Y5GNG4jASoJIl/7ahnw9F2jDo1L+9rpmuINIvJRAihqcPO763Dadb1e15RFHbXd6NRSTR3h7jtoW3MzbJz3cIsrl+cjd2o7Wnw66OizU9Fmw+LXsMVczNIOoXaln9tr+fr/9w94Ap5XpKJNaUp1HYGeO9oe59IVZbDyHvfXDvhE/Gqdj9ffHwH+xr6Oz+OFkmCy+dm8NNr52I3TV2Xtbis0OYN09QdpKk7lIgo5DpItU7fqM8xonGZLVWdPLOjgWd31g/4uVuc52T7ANGhobAZNNy4PI+bV+b3RsfCsTi/ea2ce9+tGHNX97J0K5GYTOUI+20JBALBRPD1S2bw+bXFkz2MPgghdIbgDUXZWNFBilXP/GzHoLUOsqxw0/1bWF/ejlGrJtWmp2acuo5PNEIITS4z0qwsynOQaTfyxQtLRrRPfVegt/hdURT+u6+Z2s4AKgkumplGYcr4pY0dSyF983Are+rdfSaNKinR3+S2VYVsq+7k/YoOdtW5WZzn5CfXzR23MQxFJCbzq1cPc+8QLpBDoZLg6vmZfOGC4nEzdBCMnFA0zvrydl7e18wbh1qGrMvRqqUR9dM6RpbDyGfOL+SGxdmY9cez0BVF4fOP7eA/e0+tx9cxZmfaqO3w4w2fGQY6AoFg+nHbeQX8z5VToz4IhBA6q2j3hfn2M3t5bZQ5/FOFwSxgBROLTq3iznUlfGZV4Sk14fzt60f47evlzMu2c8eaIi6eld4bIveEorywu5FLZqeTbNHT4Qvzp7cqqO0MUJRqpjjFQmGKhTSbHoNWzfryNsJRmcvmZmA39o+KuAMRNlZ0sL68nYNNHirbfHhCMZLMOr59+cxeK21FUU57Wtb68jZue3DbqN3V9BoV67+xdthor2B8URSFRzbV8PP/HhqVA6ckMeIIzgtfOI+52f37O/nCMc79+Zt0B8cnSr8038nW6rH3MBIIBNMfu1HLty4rw2XW8fs3yvvZ3Y8XqVY95xUns6Ioibis0OgO0uAOkp9k5ksjXEw9HQizhLOELn+EK3//3pjqKARnL0lmHY/ctpyZGae+cHDnRaX8v56L38ni4/ldjfzy5UMsL0gi2aInLiv8Y0MVAK8PYR73/X/v5wMLs/js6iIKks29zztMOi6fm8HlczOAxGS2KxClqt1Pbae/t8HnZNSmrCpJ4ZuXlvGjFw+Mar9wTOa5XQ185vyiCRqZYCB+83o5v3+jfNT7JZl1tPuGr6+5ZHbagCIIEr2DPremiJ//99Coz38imQ4DTpNOiCCB4AxHkiDDZiASlwe9/txz/TwunZPO1urOcRNBKgky7EZK0yycW5zMqpIUStMs07r+cyCEEJrG1HUFMOpOv0tHht0gum9PU+xG7biJoGMMdlH8xIo8PrYstzdClGozkGk39LOOP5lITOaJrXU8ta2Or6wr5QsXDLzKJEkSLrMOl1nH4rxTa5Y6Hty8Mp8jLV6e2Fo34n2MWjXXLsiawFEJBkI7xsJerVoi1aofsscPDO/8lzRALd5I0WtULMhxsKOmi0a3uA4LBGcayRYdt68uoiTNSq7LRKbDgF6j5mCTh6v/+F5viq5GJXHFvAxuXpnPwlwnsqzwoxdGtxg3ECnWRDPsG5fnDpidcaYhhNA0Zl62g1fuPJ/S//nvaTnfkjwnKwqTiMRlntxa1ye1w6LXMC/bTkmqhW01XRMWlhWMHUmC+z+1dFxF0HCc7CSzMM9J4wh7lcgK/O+rR/jjW0cx6TQYtWq+e8XM3ojQVEOlkvj59fP4yLJcnt/V0CeFalNlx4DNL289r0CkxU0CuUlja/Da1B3GNQIR851n9/L4p1cM2ltruEaogzE/x06zOzRoY26BQDC9uWp+Jj+8evaA15mZGTa+eEEJD2ys5mPLc/n4ijzSbAYiMZlndtTzt/VVHGga+9xrZoaNm1fmce3CrGlrhT0WhBCaZsiywoaKdg41edGoJdbOSOUHV83iya11Y765joQbFmfzrcvKOO+eNwlF+9dBnFucxL2fOG77W97i5fWDrWyv6WRbTdegRci+cIwFOQ6icZnqdv+o8vUFo+PyuRksyp3cyMnHluWOuhFpKCoTiibSAcKx4T8f3lCUdl+kT1rd6WRBjoMFOY4+z8VlhWd21PO/rx7u7ellM2j49PmFkzBCwTFb+NFSkGymagQubfVdQa78w3t8ZV0pH1ue268O77uXz+TSOen89vUjbDja0ec1m0HD/BwH87LtZDtNmHRqTDoNkgSPb65ld133mMYuEAimLklmHXdfO4fLhlno+9yaIj5zfiEGrZpQNM5f3q7g/g1Vw0apj53jgrJULpyZhkYl8ce3jrKrzs2iXAffvnwmS/KcZ1za20gQQmiaoVJJ5CeZ2Vnr5nC9l7J0G586t4CbzsnnmZ0N7GvopjDFjN2o5W/rq9jbcGo3zYJkM59fW8wHFmbxf+9W9BFBOS4j87MdzMywMSOtr+NVSZqVkjQrUIQsJ6yVA5E4VoMGg1ZNRZuPPfXd7K5zs6+hm8YeK965WXY6/ZF+/VnMOjXJFj01o2y2KTjO6gE62Z9uFuY6STLrxtzHpLzFN+TrR1u9fOqBrURjCs9+fiUZ9olrqjoa1CqJDy7J4cp5mTR2BzHrjjeTFZx+8gaJ1AxFqlXPaKYI3cEov3+jnItnp/X7HKpUEkvzXfzj5qXcv6Eam0FLjstInstMjss44GREURI1cFXtfmGZLRBME7RqibisDNkoeVGug/s+uWRE7Sa0ahVaNbxxsIW7XthPXefxudLCXAezMmy0eMIYdWpuXplPXFZ4+3ArF85MY0FOX/fhC2emsrGig9mZNhymsafrTneEa9wZzN/fq+LHoyzePpGPLM3hJ9fN7f3iPLW1jmd3NjA708Ylc9LHdfWg3Rfmya113Le+kkAkzoJsB1uqO8lyGEmx6tnf2I2swIJsO9uFy9yY+NONi7hi3uSllXX5I9z64NZTcgmcn23n+S+cN+Brrd4Q1/1pY6+ILku38uhty0+pl5HgzOXS3747ZBRdr1Hx6VWFvHGolS5/mEhcoXMUAl6jknjs0ytYVuAadttDzR42Hu1gZ52b6nY/je4g4ZhMfrKJDLuRuKxg1Kp5ae/ooqkCgWD80Kgkki16kq26xKNFj0WvIRCJ4QvH8IaO/USx6DXcsCSHaxZkYtZp6PCHeeNgK99+Zm+/46pVEt+6tIzbVhUMO6dqdAf53nP7eOOkJswalcSLXzqPsnQxDwZhny3o4amtdfzfOxWsKknm6gVZ/OHNclSSxNuHW5mf48AfjjE/28HzuxqJxAe2/X3stuWsLE4+bWP2hWM8uLGav75bSapVT1W7n9hJSylzsmz4w/ERpagIjrMs38WcLDuZDgNXz888rbUpiqLw8b9v7pcGNFpUEly3MJuZGVY+viIPgzaRx1zd7uf/PbGT3fV9I6Az0qw8+unlJAsxNK2JxWUkSUKtkpBlhXBMPmWjmN+/Uc6vXzsy4GuXzUnnO5fPJMdlwhOK8sXHdvLOkbYRHTc/ycQls9O5oCyV5YVJI9rnK0/t4pkdDYO+viTfyfbqLqb1zVogmIYkW/R8+7IyLihLxW7U9qt7HQ2769z8a0c9dqMWu1FLht1IpsNAlsNIskU/7LFf2N3Id5/diycUO2mMOv78scUjWnQ5WxBCSDAgiqKgKFDV4aeop+nllx7fyb93N/bb1m7U8osb5nHJ7PTTPUwgUefx7pF2tlQlisxjskJMVghH43hDMVo8IeZl29lV5x4y5CwYmI+vyOXua09P09Fj+MIxfvXqYR7cWD0uf7N52XZuXJbLszsbhiweL0618Nhty4UpwTQlHItz24Pb2HC0HbNeg0qSeOiWZcw/qQ5rtERiMm8dbuVf2+t572g7uS4TZelWPrgkh3NPWvx5+3ArN9+/dUTH/c2H53PdwuxRjcUdiPC39VW8eqCZIwOkfy4rcLFFGCQIBKcNlQSfPCefL68rnXTnNG8oyg+e388zO/svluS6TDzxmRVkOqZGGvhUQQghwYiIxWXm/fBVAj0GBWqVxPICF9cvyua8kmReP9jCmwdbkaSEHezastRJHvFx/vhmOf/76hGW5DvZJvpojBqdRsVbX1tD1iRcPJ/f1cD/e2LXaT1nWbqVJz9zDnbTmW8Feqbx5Sd38WzPBMCi1/D7jy4g2aInGpexG7UUp1qHOcLwDNaE1xOKEo8rOExabrxvM+9XDh/RfPfra0fkSheLy+xp6GZhjqP33F98fAc17QH0WhXtvkhv1HthjoOdde7RvSmBQDAmFuc5+fE1c5iVOXlzyjcOtvDcrkaq2/1UtvkGNZLKdZn40oUlzM2yMyP91K+FZwqioapgWN490savXj3cK4I+sDCLH1w1G7tJSzQus/Qnr/c6va2ZkTLlVhtuW1XIv3Y0sK26i+UFLmEnO0oiMZm7/r2fH1w1i5qOAPVdAfKSzCzIcfSmm00U1yzIYmetmwc2Vk/oeU7kULOXWx/cysO3Lp+U3luCsdHmDfeJWPvCMW55YFvvvz+7upBvXzbzlM9zoghq94Vp94V5ams9j2yu4cnPrGCh2cn3rpzFtX/aMGgaMSTSaHJcw18rXz/Qwree2UO7L8JN5+Txg6tm4w3FeHFPUx/b9RynEa1ahU5z9jk5CQSnG5dZx7cvK+P6RdmnlAJ3qnT5I/zhzYSj23DUdgb42tO7cZq07Pz+xRM/uDMQIYTOIhRFYUtVJ/dvqOaVA82oJInzipO5bG461yzI6nWw0qpV/PbDC9hW3cV1i7J60+imEgatmhe+eF5vqtWSPCfbakRkaDS8dqCF1w609HlOq5aYnWnnvOJkrl+cPWEW1BfOTD2tQghgW00XB5s9k24hLhg5+xq7iQ+SR2kzaPjQkpxxPd+26k5uvG9zr9iZmWFjXrYDgFmZNr57xUx+8O/9g+7/0WU5wxY7d/kj3PnkLnzhRJ7/g+/X8OKeJmKywsn5GXVdCeOPynY/aVY9LSOwyBUIBKPno8ty+ealMybdPe1Ii5dP/H1zb5uFkSLqYMeOEEJnCXWdAb7w+E5296wwZDmMPPv5laRaB66bWDMjlTUzpk4q3EBY9Bp+cNVsLihL5RN/38LMDCsmnZr9DR5CscFXbQWDE40r7Kpzs6vOzR/fOspFM9O4+9o5pNvHt77mjYOtw280zmTYDSjK4GlQgqnH2hmp3Lg8l8c21/Z53mbQ8Mhty8d9keY/e5v7RHwaugJ899m9/Pz6eQDcsDiLV/Y3s7HieIrcolwHcVlBpZK4Y03xsOdo9gRxmrWJtBsl0ej4GAqJnlNV7T46/X17rxWnWQhEYnjDoteaQDBelKVb+cl1c1mcNzUWyB56v3pUIkijkihKsbA4f2qMfzoihNAZijcU5f4N1awvb6PNGyYmK2jVKkrTLFyzIIsPLMoaVARNN84rTiYvycTBpoQVrlGnJsNuoKk7NMkjm/68frCF9462sSjXyaJcJ6tnpJySbXo0LvOXtytOezQIoKk7xPV/2cjcLDtfuKB40oxABKNjbpadpflO9tR3Ez5hgeM7z+5lfraDu6+dM27CVqc53vjUYdLy2G0rKEu38u1n9rK1upPKNh//78KSXiG0qiSZBz+1bFRpNCkWPXWdwT79P05GIiGwQtE4FoOWDl+413GxKMWMo8e9qrk71Bs1EggEI8ekU/OVdaXcvDK/X8PjySIal/nP3uZR7fOJntRawdgRQugMQpYV9jR088r+Zp7YUovNqOWKuRlcOiedOZn2Sc15nUgkSeLhW5bz7M4GHny/mkhMRhZWcuNGKCqzsaKDjRUd/PGtoxSnWlhTmoJJp0avVWPWqXFZ9MzOtA26Qh+XFd6v6OBHL+4f0BXrdLK3oZvPPrydi2el8fEVeRSnWsiwG0SUaIrQ5g1xtNWP1aBhTpadtTNSWV2awtV/3EDYl1gp9YRi7GvwsK/BQ36SmU+fXzgu575yXgZ/f6+SaFxhYY6jt1i6MNnMv3c1kG4zcMPibGak2zDq1MzPHt11VVEU3MEY5xYlcaTVR9sgqW4KsKPWPaBbXEVb37YBImVueDLsBnKcJmQlEbmTZYWqdv+YGzsLpjeXzE7jB1fNnnK1z03u0Kh6lQFiQW8cEK5xZwDhWJwnt9bx+JY6FEVhbpadDy3NGdeGp9OFNm+YW+7fyt7G7uE3Fowr/3PFTG5b1XdCuq+hm7+/V8Xbh1vpCkQH2XPyseg1rJ6RwjcumUFe0sTURQmGJhaXeXRzLb99/QixuII3HOPyuel894pZOIxa7n2ngsp2P3vqu6ntDPTup1FJ/PWTizm/JGVcVna//vRujrR48YVjPP7pFb226+2+MJ3+CKVpgzszReMyO2vdvFfeRoc/QkmqhY8sy8WgVfOHN8r5x4aqPt+DNKuezkCEaLzvbdhm0GA3aYeMGkEi+q1RSXhP6itytqKSEnb5NoMWtUoiHJVxByPUdAT69WASluRnJ+tmpfHBxdm4zDpmZ9qnlHmOoigs/cnrtPuGF0NatcTygiQ+uCSbaxZknYbRTS+Ea9xZhlalYlVJCjcuy50yId7TQTgWp7LNj0WvIS4r5CebSbHqWZDrEEJoEsiw919dK02zYtFrprQIgoQb2Ut7mvAEozx86/LJHs5Zx4aj7fzohQMcbvFi0auxG3WE4zLvlbcTjyuY9Rq+cvEMAAKRGJ97ZEdvg9OYrHDLA9tIsep586ursRpOzSK9JM3C09vrAVj20zcoTbPwwKeWcbjZy4t7mqhq93H1/EyuWZCF06yj0x/hzUOtvHmohXePtPeaIBzjvvVVGLQqVJJEjstEUcrxa7SsKOQlm6ls8/VOfvKSTCSZdeyodQ871mAkTkmqBb0mMqLJ05mA1aDBadJi0WswaNVo1CokICbLNHeHRhxxbnQHWZrvTESJJIloXKa8pa9NsV6jYnamDY1aJUTTGcKJJkFXzMvgjx9diCRJeEJRnthSi16jZmaGrU9zUllW+O3rR7jzotIJzayRJInlhUm8tKdpyO0+v7aIz60p7jW4EpwaIiIkmLZ0+SMs/cnrxGSFT52b3ydPdlNlB999dm+/NBLBxDFYk9ZAJMaiH79GKDo9DCw+u7qQpXkuLpyZetZFVCeDIy1eLv7Nu/2e16olbl9dxFd7BNCJJhdvHWrlUw/0b3D6xQuKe7cfCbG4jFol8c6RNg41eylJtfD7N4/2msoMhdOk5er5WTy2paZfRGe0rChIotkTJByTx1TbmGLVk+sysbfeTeQUxzKVmZtlY2+DZ8KOvyTPyeEWL5l2I1aDhoNNnl5htDDXQW1HQKTTnWHkJZlYnOdkZ627t28XwB1rivjKulI0ahWhaJyvPb2bG5flsvKkZsvjzcObavjec/uG3Gbzdy4kTTQIHxIRERKcFTjNOn77kQV899l9nFvU9+K0ojCJr108g889umOSRnf28fK+Fr592UzMJ61SmXQa1s5I5b/7RlcEOlnc+04l91LJPdfP5cNLcyd7OGc8pWlWVpUks768vc/z0bjSa4AC8KtXj/CPDVXYDFpi8sCi+m/rq7hhcfaQ6Y3dwSjP7qjntYMtbK7sJCYrLMx1sHMEEZgT6QpEOdTsOWURBFDR5iMYieEbpGniUKhVEtkOIzFZJtdl4ugZvPgTjSuYtCoCE7SocqwFw+GQt99rO2vdWHRqCpPNVLafub/j04lFr2ZWpp1wNE5XIEogEiMuK6hVEuk2A2a9Bn84xr7GiRO/NR0BajoC/Z7/89sV7Kjt4ifXzuUj922izRvGqFVPuBA6pzBpwOeteg3FaRaW5buECBpnhBASTGuunJdJklnPk1trOa8kuU8z0OWFSVw1P5M3Drb0No4VTBztvjC/fOUwd13d38Hmktnp00YIHeNo6+SaOpxN5CWZWF/e9zmbQcO3Livr/bdJryYQiQ/5XQ5G41z9xw3M6klt+fK60n7b3P3igd7Ut979xnh9GKzH0WixGjUoKGMSQnFZId5jlHMmU5JqQVGUSW2N4IvE0QWjpNn0o+7zIuiLuqeea7CUwxNTPTPtBrRqiZphaubGm02VnWyp7uw1NXntYMswe5w6RSlmsp1G6k9wg1xVksxDtywTGQoTxIQWlNx1111IktTnJz39uMOFoijcddddZGZmYjQaWbNmDfv3D96sTiAYiHOKkrhjbTFvH+7bm8Zl1vGHjy5kx/fWsVR47J8WHny/mjcP9b9ZbK2efvn1tlOsNRGMjJf2NPHIpuN9gnQaFetmpXH/p5ZRnJpwIWxwBzHrNNiNw/9NuoNR3q/s6GOocIwdtV39RFCSWcfR1v4RgJGwraaLwnFoOmw3aMdc45PnMmE3apnXYzO+OM/JwlwHLvPkNoYcT2Zn2lCAwy0+JtsQtNMfQadRYZ3C9RkGzdSvFY4rjDgNtLE7hEF7+n/fKikxTz1G/DSknUqSxAVlfXs4XjQzTYigCWTCP1mzZ8/m9ddf7/23Wn18xf4Xv/gFv/71r3nggQcoLS3l7rvvZt26dRw+fBirdXBnHoHgZErTrIO6ORm0aiKiweppQVHglge28eElOXzn8pnYTVqOtnp5cmvdZA9txJxfmsLNK/OJxmWicRntWWRAMhlYDBq+f+UsWrwhZqbbuHBmaj/DgwONHv65vR6dRoUkJT5nQ5FhN/CzD/StV+vyR/rl3i8vcFHd7udULg8Ww6nfRlUqiUW5DoLROJ3+CBISZr0am0GLVq3CH4kRl2Xqu4KYdBpae1aojzmf1Qwg+pbkOUdtxTuezEiz4jAd/zvG4gpHWr1jcriLxRWsBg0qiUkXQgB1nUHK0q1UtPnGJTVyPFma72RvQzeL8xzIskJ3MEaDO0A4NrXGmeVIpL6NNLJ2uMXL0nwnW6u7Jnhkx/nqxTNYNyudn/3nEN5wjKgsE4rG+2SeTASXzk7nofdrUKskbltVwIeX5kzo+c52JtQs4a677uK5555j165d/V5TFIXMzEzuvPNOvvnNbwIQDodJS0vjnnvu4bOf/eyIziHMEgQjYcPRdj72t82TPYyzimSLnqX5Tl470EJsKsxeBqE41cKqkmQW5jqZm2Xj/g3VPL6llo8szeXH186Z7OEJemhwB/njm+VsODpwtOdEClPM3PuxxcjA/sZu3j7cRlW7D5VKos0bRpYVXGYdVoOWzafgBpafZCLFqudQ89gm+McwaFVY9VrafMNPCg1aFQ6TjmhMRlaUQR0ZC5LNpFh0tHrDVA9QAzFRFCSbsOg1A5oaqCQoS7dh1qupavf3iYIlW3Q4TTqOLXxXdwT6LWBlOY00uYNTQgwBLMxx4A5GEz3VNCr2NnQTjSvoNCqyHAaaPeExp12OhWX5LrYMEH1XqyTyXCaMOjX7J7DeZqTYjRpMOs2ojUFUUuJzfTpMkGZm2Hjpi+ehUkn8/b0qfvziAQB+/aH5fGBR9oSeW1EUvv/8fj60JIe52fYJPdeZypQySygvLyczMxO9Xs/y5cv56U9/SmFhIVVVVTQ3N3PxxRf3bqvX61m9ejUbN24csRASCIbjgQ1VyArcddUsWjxhdtZ1savOPW1czKYr7b7wlK4L0mlUfGVdKbedV4BGrUJRFL74+E5e3NPEucVJ/OCqWZM9REEPL+5p5DvP7MXTIzZWlSQTicmoJImSNAvFqRaSzHoUFDQqFReUpfLczga+8a892IwaipItNHWH+ky8mz3hQQuTh0ItweI8J+2+CJXtfqo7ArjMusRz3hD1XUFGGyQIRWXmZ5tHJIRC0YRN9HBUtfupaveTn2TCZdLRGZjY6JBBq2Jmuo2dQzjuyQocaDo+ES9Lt2Az6ghEEg1yT/z7WA0aFmQ7QEqko2lUEuGYPGVEEMDOOjdqid6/9zFb7/quIFXtAfQaiZJUC+VjqDcsTbPgMOlQFAVPMEpXIEosLtM5RCuCwbKn4rJCZbufhbmOUY9jIsiwGznUPPp0VFlhwqMxx8h1GXutsleVHDdI+MeGKq5dkDXhNtpiEe70MaFCaPny5Tz00EOUlpbS0tLC3XffzcqVK9m/fz/NzYkJUlpaWp990tLSqKmpGfSY4XCYcPj4zcLjmfzVDcHUJi/ZzBce3YE/EkevUZHlNHLF3AyyHCbufbeCsEibm/bcdE4eS/Jd2Ixa1JJEXJaJyokJRIsnTKs3RKs3jEGjJtWmJ9WqZ3VpCoUplt5jvLCniRf3NJFi1XP1/EwONnmZk2UTudmTzLtH2rhvfRW/uGEeRp2GSEzmomGszctbvDy0qRoATzDGzjo3LpOOeVl2jrb5CEXj6DQqtOrR/W2LUsy0eMJsOSk9p9MfodMfIdWqJ8tpoisQIcthpNUbHjY9zWrQkJ9kYnvNxNTRHYsGFSSbcZi0dPojI+5TNBLmZNow6TSEYvEhRdBAHGoeXCB4Q7EBoxtTjRNFb1cg2idCF44ptHhDLMt30uAO0eAeutjfZdJRkmahvNU7aD+kRbkOOnwRIvE4Xf5or3mEy6zr18PqZHbWunGatBSmWJBIRIqCkTjecBR3IIpRq8Zl1qHVqEbtoliUYu5djNhR0zXoYkB+komKtrEb0exv9JBu09M8wWYVJ9bYhU9YNN3X4OH53Q1ct3Bio0KC08dp7SPk9/spKiriG9/4BitWrODcc8+lsbGRjIyM3m0+/elPU1dXx8svvzzgMe666y5++MMf9ntepMYJhkJRFOq7gnzlqV29OcYXlqXyvStn8cDGah7bXEskLgTRdMOsU/P9q2b1s7kub/Hy+zePUtsZYH62nRsWZzMv2zHocTr9ES769Tt0+iNo1RLRuMKqkmTu++QS/OEYgUicHJdpgt+NYLR4QlFe2N3I9Yuyqe8K8tKeJl7a2zhsU81sh5HCFDPdwSi760futiYBqaNwDLMZNOS4jHhDMWpPcLwyaFSEYjJOkxabQXPa3bCOYTdqyUsyYdSqx5QiuLzAdUqphWcTLpOOwhQz4VgctUrF/sbu3vqi/CQTyRY9u+vdo645SrcbSLXqqekI0B0cv8bV+UkmonGZBvfA0UeVBKlWPSlWPQoJgdA7JpsBnUZFpt2AOxjFZtASjseJxZVxSc0rTbPgNOkIRuI0e0K9NXPjyS9umMeHliRqczZWtHPjfcdT6zPsBt786hqMutMTnRKMntGkxp32hqrr1q2juLiYr3/96xQVFbFjxw4WLlzY+/o111yDw+HgwQcfHHD/gSJCOTk5QggJRoSiKOyodfOdZ/ZyuMWL3ajlg4uz+dDSbB56v4b3KzqmVOrFeGE3aunyhydtwjXerCh08YkV+Vw4M5U2b5hX9jfT5gvjCUZJsRq4bVUBNoOWpu4gW6o62V7TxerSFC6cmdbvWKFonC89vpNXD/R3uzNq1agk8EfiXDI7jXs/seR0vD3BKFj7v2/T1B0cc6rrvGw7Rq2aaFymuiMwbARHo4LFeccFgFGrJt1u6NOMEcBh0pJk1vXWM8zKsFHV7sdi0NDuC5NhM1CcamHD0fZRp9KNN2NN3zrdxetnEqtKkpGALdWdUzZN26rXkOU0AmDUqXuNY9q9Yao7/EPeK21GDWpJGrSGbTyZiGa3JzYt/dWrh/nDm0dZMyOFq+dnsqO2i3MKk7liXsYwRxFMFlOqRuhEwuEwBw8eZNWqVRQUFJCens5rr73WK4QikQjvvPMO99xzz6DH0Ov16PX60zVkwRmGJEksznPyxGdW8NrBFt490sY/d9QTVxTuvnYuv3j5EH9+u2Kyhzkh5CeZWF7gQlYUfKEY9V0BvOHp11/pI0tzuOvq2bx1qJXPPLyd9eVt/VzE2n1hfnLtHDLsRq5ZkMU1C7IGPFaXP8JH79s0aL56MHr89yMh8cSWWj6yTDRZnQx21nbx69eOcKTFiz8cpyDZTGGKGbVKOqWJ5J6eiFCmw0AoOvz3ISZDiydEcYoZl0VPTU8tTpbDgMOkw2XWUdcZoNUT6lPUfaDJQ36SiSSLHolEGtWehu5hRZBaSjjTdQfHbsYwHLYR2JKfTJbDyIEpUHg/nXCatKTZDBi0ataXt5PrMqHTqKasEPKGY2Oq5QEoSDKPKtp6KuysdWPUqSlKGdpIwWrQjMjUpCzd2qdp6TFzlttXF7GiMGnCzRIEp5cJFUJf+9rXuOqqq8jNzaW1tZW7774bj8fDTTfdhCRJ3Hnnnfz0pz+lpKSEkpISfvrTn2IymbjxxhsnclgCAU6zjg8tySHbYeRoq49oXOadI23csDj7jBVC1R2BPu5RKglmZlix6rUEe2omVBIEIjHMei2+UAyrQUNlm39ERdyngzvWFLFmRiqrf/nWoOlJ376sjM+cXzii2p52X5joCFMiX97fzLvlbVw5PxPLFO4hcqYiK7CxoqO3ienehm72jmMT0Uy7kcZB0oBOxGnSUt8VSFhunzDpStSAhJiRZiEqKwR6Jrfzsu0YNCr8kThHW72930GTVkWO00SKJYZJp8EXjtEdjNLui+Ay6ShIMaEoEInL7GvwMDcrUYtzoMlzSg51A6EeQ+G3PxIjx2Ua80T5bKQk1dqn7qm2M4DdqGVpvpPKNv+4RjQmk5I0Sz8RNCPdSmNXEO8wdUxjJRiJ9xP0SWYdxakWPKEoDV1ByjJsgzZwPUayRc/vPrKwz3PpNgMz0qwsL3CN+7gFk8+E3s3r6+v56Ec/Snt7OykpKaxYsYJNmzaRl5cHwDe+8Q2CwSB33HEHXV1dLF++nFdffVX0EBKcNs4pSkKjlnhkUy1Pba3n9a+sxmbQ9LpTncnIChxsGn4SI0kwt8c0YG99N5ORxaNWSfzgqlloVBI3/WMzwSFWUE069YgNDuq6AqwuTeW8YpmYrKAAFr0GtUpid52bbTVdJJl13LaqkB+/eIBAJM4/t9Vx87kF4/TOBCNlcZ6T3T+4mG3VnWys6ODh92v6ROzGikWnJsuZsBZeXuCi0x/B2ePW1eAOkmJLRHB0ajVxRUEtJRqzDkSaVQ9INHQFyU8y4QnFeiNOJ5PpNOELx/qk1KlVEpkOA43uEJ01iUmxVi1RnGLutaMer3S02Zk2uoNRWrpDw04OB8IdiOINxZibZUejlihv9uI7jVbR05GY3P+61R2M9v49c11Gki36cTOymCzKW3wU9dTgpVj1BCNxDjd70akllhe42FrdOSEp6Hvqu8lPOl7LWd8V7E1hLUg2sWMYQ5IMu4FHb1vex0QHQK9V0xWIUNsZIC/p1BsoC6YWp71GaLwRfYQEp8qDG6v5wb/3A4nJwaFmb++qs6AvqVY9BclmjrR4T0vuNyTce759WRl76t0cbvHR3B1CkhjU+Wp1aQr337yUZk+ITIex3+uyrBCOycMWuj67s57XD7Zy9zVz2NPQzU3/2ALAy3euoixdXGsmm+p2P3c8uqOPHfNoUUuwKG9gYbG8wEVlm4823zE3OCOhaHzIxYNjDU6Hw6xTYzNqR9xHxWXWYtJqqO9xHVuQ7WBXvXtE+55MYbKZxXlOStOt+MMxHnq/Zlwar87JsvUpmIdEX5vOQISjY6g/mu7My7ITVxTMOg0KCpIksbW6c9hmwGqVRFm6hf2NZ26kbaDPykSi16gwaFVDppem2ww8ffs5A5rifOOfu3lqWz1ZDiNP337OgPcVwdRiSpsljDdCCAlOlSMtXi7+zbuTPYxpRWGKGUWhX4H4RHCsm/zJK+F2o3ZAlySVBPd9cgl3v3SQ714+k8IUM7KikOsyo9Oo+Ol/DrJuVhpL80ee5tDlj/DGoVbUKoRt6hTCHYhw432bxyyGlhW42FPfv6eYVa8mFJNJsxno6hEJ/kgco05NaaoFQ4+5gi8cQ69RodeqkWUFWYGGrgBtvsGFhVqCGem2UY95QY6DXXVushxGPKEokgQZNiM3LM6mwR3kgY3VA+6XZNbxoaU5FCabSbUZOK84mV11br742A4aR9nQcihynEa06kR7guUFLq5ZkNU7qezyR1CrJR7dVMs9Lx8at3NOVfKTTKfUxHawxqjTkdmZVoxaDcFoHH84RlRWsOg0HG45fUJvfrZ92HqlX1w/jw8tzRnwtW8/s5e6njTGsnQrX7ywZCKGKRhHpqxZgkAwFclxClvk0VLZUxuxJM/JoWYPvgk0XTgWnBtJ/cax7X/z+hFuXplPgzvIU9vqOL80hWynkb+tr+av71ayvaaLe66fR3GqZfgDkqgpu2GxEEBTDYdJxyO3LefK368f06R+V20XOS4jHf5EH5UleU5kRaErEKWmw099V1+XxWAk3juhWl7g6mPTvazAyZaqLtQqiWX5Lmo6/LR4w2Ta9eS4zMQVBatew/5Gz5iEm1YtkW4z0B2I4IvEseg1/PHGhZSkWYnGZT6+IpfyFh8HmzzsqO0iEldo9YT41+dWkmTpazBUnGJBp1GNegxD0eAO8uhtKzinqH+TWmdPT5bClLMjrSjFqj8lIVTTMfELTBONRCKddVvN5LsKSgydKv3RZTl8YNHAhjoA1yzIZGaGDZtBM+IormD6IISQ4KzHqFPjNGlPW6rXmcS2mi5mZ9qQgH0T5CClUcGivP4pR/5wjJkZ1gFTlfY1eNjXsB+rXkOyVc/7lR38z3P7gER63wcWZZGXJATwmYDLrMNm1I5JCEXiCjUdAXJcZiIxedhJm1Gr5qPLcllblsI7h1sJRuLotapE2lPP5zMuK72r+Q6TFq1axd6GbgI99TMLcx1j6nvS6Y+QbtfToZHQh+Pc/6mllKQl6mm1ahXFqVaOtvrYXtvV2wZAp5Z4bEstF5al4QvHWJLnpM0X5tMPbTulifqJLM13cseaYmakWwdMGVIUhVZvGLtRy5ERGCtk2A1k2o1EZXnQ+qqpTFGK+ZTc9LRqCe04i9TThVYlUZRqwWbU0uELTwkRdCySOhgjMddJsxmw9xgxiLS4Mw8hhARnPdG4fFaYI0wUxxrk5TiN1HWNvk9RWk/9BfRfudOoJfbUdw9YdxGTFcpbfNx5UQnnFieTbNETl2We3lbPY5tr8YZjvT9FKWauX5TNecXJnFucLBrhnWGcSkNFo1aNJxjtFSpDUZpm4ftXzQJgW3UXH16WQ01HgL++W8ncLBtGnYZOfwSzTo1Bq0YBvKEIBQZz7/dkZ617TIYHx2yBk8w6vnbJjAEbBM/LdnDNghj7Gjx0B6NE4gov7WmitiPA4jwnVoOG2x7cRoN7fPqJLchx8I+bl2I1DGy/rSgKi+9+nU5/BJUEes3A37tl+U4icZnaziBN3aHeVfccp5E0m4FddV0Jl74pSFm6FbtRSzgWp6k7NKR980iIxhU6/RFKUi1YDRq0ahWyohCIxKZU3dCiXAcqSaIrEKHJHWROloMjrd5JdxFcVuCipt2PSgVJFgMVbQPXp+k1Kn7z4QVcPnfoXkCxuMyH7n2fjy/P40sXFo/YiEcwfRBCSHDW0+gOCnOEcSDNZhiVEDrWmHJrdSctY5jIusw6PnlOHp9YkUeSRc//vVPB/71TgbsnsleaZuHGZblcMiedDLtYxTtTicTkUyr294bjpOiO3wo1KglZUQZ0tTKfYJt+50UlSJKENxRle00XrZ4Qje7QgBbIJ6dg7q7vZlmBEwmp19VqJGQ5jGz41gWDvp7pMHLlvAye3dFAqk3PTSvzWZjj6DN5+++dq3h0Uy3/2dt0yvbjP7x69qAi6DevHUGvVfX+bWSFQV3+DjR58Q1gq1zXFaSuK9hrg7yzJ+VvKmE3akf1NxwJgUh8wAa3hclmzHo1+xo8k+LeeYyydGs/o5qpUtPkC0V77ydN3QPfV5ItOu775BIW5jqHPd7uejdt3jC/ef0I9V0BvnFpGSnWRKppNC6jUUlCHE1zhBASnPUca5YmODVGc2NOt+kx6tSjnkAkW/SsLk3hynkZnFuc3KfO4YkttbgDCbvWH149m8vmpIsb1FnAeDiSqaVEStP8bAc/uHo2/nCMp7fV85+9TX2KujdWdHDvOxXcfG5+b3TDatDyhbXF3P7IdnJcJsIxud+kXqvu+zmMxGS2VHWxKNdBWboVdyBC80l9sYpSzCRZ9ETjMlq1il21XSzJH37iZtJpePwzKwZ93WbQ8rk1RXxuTRG76tx8/endA066R8Idj+7gyc+uIHuAOsvzS5P52tN7RnSc4doYdfgjdFR1MiPdSn1nAP8Usuk+1OzBpFOPKKJ4qlT2mNPoNSpK0yy9luqnm8o235gzACaawYT5MYpSzDzwqWUDusMNxK6644sFT2+v5/ldjaybncayfBePbKrhHzcvHfGxBFMT4RonOOv5zWtH+N0b5ZM9jGnPYPU6LpOWwhRLIurWM+Fp6g7RPIqaDotew32fXMLyAheqQWZN/93bRIM7yAcX52A3DX0zFEw9jrb6+N0b5Rxp9lKQbCbTYex1DHSZtRT31B74QjEUEuJCJUn88IX9VLWPbDFDo5IoSDbT7gv3qQn88JIcPru6kIJkcx/xvLO2i+v+vLHfcXJcRh781LI+/Ua213Ryz8uHaXQHMes1HO5JEUoy65ibZeftI239jlOQbKLdF8EbimHRa7AZNejUCXF/cg1PjtPIvZ9YzKxM+4je60gJx+L88c2jbK7spCsYocMboTMw8gjbFXMz+NPHFg342n/2NnHHozuGPYbDpO2N5A5HUYq5Jw1WIRSLE40rRGIyEmA1aIZ1B5sIlhe4xj0qNBzFqZZJsSVXSQmTnIop2gB2qLTTpflO7v3EElw95h1D0eYN0x2M8rP/HOSNQ62DbveXjy3ismHS6wSnH2GfLRCMkGhc5rx73qTFM/YaA0GCeVl29gyQaqNRgVGrOaWO4g98ailrZqSeyvAEU5j7N1Tx4xcPjKnJ4vwcO7KsUNHqIzBIo92l+U6+cWkZc7PsGLSJSI4nFKW2R2zMyeorLg40epiRbkUCLvjV2wMaC5xXnMzDty7rF3Vs7g7xm9cOc7TNz67aLtJsBpo8IeZl29FIKrzhKKFonNrOIFa9hjSbnqMjqCt59o6VI0rlGSubKzt4ZX8Lj2yqQUEh1WYg22GkxRMa0ljh6vmZ/P6jCwd8TZYVHny/mjcPtbKpsoPoIGltLrNuXHoZASzIsfdZxR8KlQQmrbq3EeyMNCtdgQgmnZo0mwFfOIax5/OikKh5isZlQlGZDl9CMOa5jDhMukkRYMvynWwZh+a6IyXLYcSsV/dxS5wKmHVqdBoVTpMOg1bNeSXJXLcwi+8+u5fDzV5WFidzy7kFrCh0jShLYF9DN1f/8b1Br0erS1O4aFYaszKszMywYdKJ5KqphhBCAsEIicRkVv78Tdp9QgidCieviOrUEjkuE8kWPYdbvCNe7R2Myp9ePmgkSDD96Q5Emf+jV0/pGCoJCpLNqCSJaFwmxaqn3RfBoldz3cJsbjmvYETHeWZHPV97ejev3Hk+JWlWWjwhPv3QtgEdzK5ZkMnd184ZMB2nrjPAf/c18n/vVGHQJPrr1HQEaPWGcZq0SBKUplnZVDl8JCHNpmfjty5EfRq+A1urO/ng/73f57lZGTYicRmTTo1OrernBnbP9XP58NLcIY/79/cSYhdAr5EIx45PPVIsetpOuAYvznXS4Q+TZjNQ2ebv89pwpFr1IzLPmJVho6LNRzgmk+kwkG4zEBymYe6J6DQqFuY40GlUrC9vH/H4xhunSYusJD7/DpMOq0GDXpNwMozLCqFoHLVKwqBV0x2IDtu/R6OC/GQzDqMOlST1RvFbPCFqxslpcDxJtujIcRpp8YaZl2Xnf66cNWCq5mi47cFtvH6wBUgI/Synkcc219IdjLK6NIW/3bQErXp6OvudLYg+QgLBCNFpVFyzIJO/v1c12UOZtug0KvY3dqNVSyzIcdDiCVPbGaCizX/KDkrHeGxLLcWpFlYU9u9RIpj+KCgsznMS74nsZDmN+MOxUdUgyAp9Pm8nRjEunTPy+o2KNh+yknAlhIQJyNO3n8P/vnKY+9b3vU48v6uRnbVuPnN+IQatmmsWZPZOkHJcJj5zfjFXzc/iJy8d5MU9TeQlmVia76SqzU+7P8L+Bg8z0iwcHmCF3aiRmJ3lICYrqFUSL+9v5ophUnBaPCE2V3VS3uIlJivE5UTvomsXZo24jmFJnpNMu6GPHfnJfY+W5bvoCISpaE38vr/9zF6sBu2QDlw1HX4+tjyXkjQLP3npIItyHexr6CYSVzi2SD8/2040rrC9NiG0qjsCqKREGuRg0aSTickyi3MdbD+pmP8Y+UkmnCYdeo2KcI8VXaM7NOI+ZccwahNubpMtDk5M8RxJC4j8JBMpVj2hHuOKpu4QXf4IC3Kc+MIxKtt9HG31A1Ovl9GxVFlIRHnbPGGqOwPEZIX7PrmEOZkJ58ZT5ZhVtlYt8Y1LZ5DtNPGlC0p4cU8jl83NECLoDEMIIcFZzzEHGMHYiMRk9BoNRq161JbAQ+Ey65iZYWVWho1WT4iZGSLie6Zi0Wuo6fDT7kukRx1q9pJm1SNJcCo5CxqVxJfXlXL76qIR7/Ox5XmoJKnP502vUfPdK2Zx8ex0fvjCfvadUKRe2xngf57bh1mnJsWq5/yS5D7pNxl2I5fMTufFPU1Y9H2/I95wjFSrAU8oSqrVgF6jptUbotEdZFamHZUksasusX2bN0ynP8J1C7Ow6PveuvfUu/n5fw+xsaJjwPf069ePsLo0hRuX5XJ+aUpveuDJhKJxntvVQJbTSIbdgKSS2FXr7hWFRp2aJLOOLdWdzMu2syjXwZ56N6VpNn70wgG0ahXrZqUNeOxZGTYum5uB3ailqTvEve9UMj/bTkWbD6dJh1qVmMifbF4jK1CWauFAkxeJ4U1ZOv1RfGEPWpVE9ITcJpdJR36yiR21brRqFYdbgph0apxmHQ2jENx6jURZho19DZ5xvd6dLqo7An0WCax6DUkWfa/4nKqoVRKzM23IioJJp8ETjFDd81n58kWlLM13jdu5PnVuPucWJyEB5h5hZdSp+eCSnHE7h2DqIISQ4KzHJ3oInTLecfodmnRq5mXbmZFm5ZI56awsSh6X4wqmNhq1iotnp/PY5tre55xm3Zhs1QG+cekMFuc6KU2z4hxBYfQxqtv9bK3uZHd9N62eEKk2Q5/Xl+a7eOEL5+GPxHllXzPffnYvkZ6ogj8S56Z/bKEoxczHV+Tx0WW5vYLjWA+hilY/S/KcROMyapVEdzDK+qOJtKoOX5RZmTbm5zhIsugJROJ0BRJRimsXZDI7044EPLGlhr++W4XDpMVh1CFJDFuoryjw9uE23j7chl6jYlmBixWFSfjDsV7hYTNqeXV/c68YPUaGXU+yRU+rJ4yiKJh0agqTzUTjMnvqvdiNWqra/QSjcb74+A5e/OKqfnbhADcszqa2M4BVr+HLF5VS0erj9YOJIvTh0rUONHnRaVREYjJzsmx9hOhARGIyWQ4jeo0Km1HDrrpusl1G9tZ3U5BsRq9RoZYgFJNp6AoyJ9NGdzA6aATSoldTnGolGInR7ouwe4Q1SNOBY73WJgutWmJJnov3KwcW8QAlqRa0atWA6amSxKi+4yPBbtTyoxcP4A5EueXcgt7eYYIzEyGEBGc9AzXrFJx+1s1K4441RaTaDGTaDcL6+izjZAessYrrT56Tx+dWF43p82PSq/n6PxOWz995dh9/u2lJv20kScKi13D94mwunZPOH986yl/erjh+DJ2Gl/c18+TWOr5/5SxWFiej67HPDsVk4rLSW1ivkmBulp29Dd3cuqqAr188o7cWbnNlB3c+uYtffXA+0bhMJC4Tisb589uVdPojY24iG47JrC9vH3FdS1N3GFmmV5Sm242Ud/p6ewJ1B4+nY4WiMrc8sJXL5qbzlXWlfRqo+iNxLvr1OzhMOqIxedST72OCc1+Dh9mZ1mGbi57YNDbVqudwsweLQUNVe0KMesPx3td0GlUfEeQyaSlOsyLLCiqVRCQWZ1ede1TjFQyNSoKbVubz+bXFJFv0fPfZvTx6wkIIJNwEc52mAU14IGHecN8nlzArc3yzBf7+XlVvXeszO+v5xqUzBo2iCqY/QggJznruXFfCp+7f2psvLpgc0m2GCXXFEkxd/OEYW09oyJifZBrSqWwwLpmdxg+vnj1mEZ1IT0vUjozkEGa9hq9dPIP52Q4+/9gOdGoVf795CalWA9Xtft463MrK4mQ+t6aYFk+YIy1edp40of7TjYt4blcDOo0KTyiKw5RY3V5emMTfb1rCZx7eTv0k92uRSRiibK/uZF9jN1mOwXvIrJuVxlfXzejT4wsSNt13XlTKr187csrj8YXj5LmM1HSO7PfS6g2zrMCJJxijMMWCWiWRZtMTicm4g9E+onJZgYvddW6xQDaBlKRa+M2HF/S6Nf5zez1PbavrfT0vycS8LDsHm70DiqCVRUl8+vxCluW7+jQ5Hi9SbcfT5d2BKO9XdrBWuJaesQghJDjrWVmUzPLCJN4doM+HYGIxatU4TFo0aonPry2e7OEIJomvPrW7Ty3QiZGE0XD7GCNBJ2LQqonJChl2w/Abk6hduHROOretKuDedyr5zEPb+cfNS8lPNvOp5IRTnVGn5ofXzOaS37zTZ19ZgR++sJ8/fWxRvxXncCzOFx7bOekiCKDDFybLYWRJgQtZgWZ3kEW5DnbUulmQY0etkjjY5CUQiXN+aUo/EQQJkVma1j9lbizUdARQqySWFTjZVesmMpgtt0lHttMIEmyp6iK7J10uEJHJc5kJRuN4QlHMOjV6rRq9WsWhFq9YFJsg9BoVRSkWHrxlWZ/a3A1H21EU+OIFxdxybkFvqpsvHOO98nZuf2R7n+Pcc/28CW1immzuWzcsj8XXXzBtEEJIIADOLRJC6HRi1qnJcho50uLj55fNZWGOk/QRTjwFZxZxWeG1HqvaY9iMY7s1vXag5ZSjij+5bg7zsx0jFkLHuHllPn9fX0WqVY9Z31/IGbRqfv/RRXz0vk0EIsdd7MpbfUTjcj8hpNeo+fPHF3Hpb9eP7Y2MI7ICXYEwNR1BlhW4yE82IysK87ISPXuKUhKi4obF2awqHryu75LZ6Tx86zI++Y8tp2SCAYnPzZaqLnJdJoxa1YDOezFFxqBT96a11buD1LsHF5Yqid6+QYLxI9mi5+Fblw1oeNPpj3BBWSrfuqyMtJNq8ix6Dd5Qfye8rz29m//94PwJEUOKovDI5pref8/MsLG0YPyMGARTD+EBKBAAn15VyPWLsid7GGcNKpXE3CwHAO8eaSc3aeJW9wRTG7VK4pPn5PVxQhupVfKJpNsMXDbn1Du8XzkvkxyXCc0oLHJD0TgPbqzhktnp/PWTSwaNaM3PcfDbDy/o81xtZ4BbH9xGRVv/ifz971WPZugTSpo1MUndUtXJu+XtvHe0ozdtqbqn7uYDC7OG7PclSRIz0q2nLIJOpLYzwOEWHzPSrSzMcWDUHv+7eYIxtlR19otEpdn0LMt3YdD2/RvLCmTYDSzNd6IfIKolGBuRWLzXfe1kXGYdV83P7CeCIJEye9/6yj7PpVr1dPojfO/5fTR3j87yfCS8dqCl15QhL8nEQ7cswzZAnzDBmYOICAkEJCbm91w/F4tezYPv1wy/g+CUsBm0fPKcPDyhKN+9YuZkD0cwyfzgqtkEI3Ge2JqoExhL39BbzytgbrZ9nEfWF0VRuPbPG1FJidXqdl+EFk+IhTkOrlmYxS3n5Q97jHWz0shyGHuL+TUqCZ1axd/WV/GzD8zts+0V8zJ47WALnf7IQIc6rQyVLhZXYGt1Fy/tbWLlEBEhgFbP8Xocp0lLSZoVSNiDm3Vq9Bo1u+q6GK0WPtycME/QaVQszXf2sbYORvr2kbIZtGyp7mRhjqNfzdbRNj+0+Uky6wjHJv/3fibgCcX46H2buKAslc+uLuxteNrqDdHujQxqdhCOyZSl28h0GPEEo6gkiZ11blq9Ycpbffy/J3by2KdXjEujYUVReHxLHXe/dKD3uQ8tyRHtNc4ChBASCHrQqFV8bk0xT2ytEzniE0yDO8jRVh+fOb8Q1zhbnwqmJ8eiBGadmkPNQzuCncg5hUncsbZoXPuINHUHOdDoYU6Wvc9KtazAp1cV8MyOBt450ka8p3bg4tlpXD0/c0THliSJaxZk8ucep7nlhS5+eM1sCpPN/bY9vzSF+29eyrV/3jCuUZThUEkJR640m4FwTKbDH6bDH0GnlgatxwF4els97b4wS/NdfHxF3oBOW8WpFgqSzLgsWuo6gwOaEqRa9eS4TKgkRtWrJ9dlwmpIiKnFeQ46/VGcJi0HmjwUpZhxmXU0uoOU9zgUak+I+szLtqPXqJAkKdGvSIEOvzBMGC8a3EEe3lRDTJa5Y00xGyva+clLB/GEYiwrcFGaZuHLF5WSZDkuPFxmHb/7yAIkSaLDF+bqP27o/c5Bwjb+/g1V3LaqcExj6vJHEjb9nhDf/Nce3j7cNz1e1AadHQghJBCcQLrdwB1rivnN66fubCQYmlcPNPOXjy2e7GEIpgiL850UpJhRS7A4z8n+Ji8/eH4fJ85FdGoVMTmxSKFWSczNsvO3m5YM6hwVjcu0ecM0e0J0B6P4wzEC4TiZDiPeUJSHN9VQ0eZDVuCCGamk2vTsqnPzXk/x9pXzMsiwG/jY8jzyk82oVRJXzsvkynmZdPojbKnq4B8bqkdt0PCpcwv49+5G6ruCLM13UZQyuInA/BwHH16Swz+316OSJCLx44s0apWErCiDiqRcl4kWT6h3Ycdp0hKKyhSlmDFo1dS7g8iyQrrdgFatotUTIq4ooCT6y9TVHBchRSlmFuY42DyEMInEZV7Z38Ir+1t4els9t64qINtpJNthwhOKUt7q5VCzl5pOP1WDt42h1RvudXKbm2WnusM/rJ36jDTLCXVCx4W0v8ceu6LNT0Wbv88+nmCUxblOwnGZNk8Ih1mHSachJic+N0vznWyr6TqtIvRM5/EtdTy+5bhDnCQl6oT84ThdgWgfIZR4/bj1/LpZaTywsbrP649sqhmTEHr7cCv/74ldfPKcPB56v6aPDfwx5kxwhFkwNZAUZXp/xT0eD3a7ne7ubmw20XlecOqEonEu/s27/TqcC8af17+yesDmiwIB0NtbJNtp5GcfmMuqkpRh99le08m/djTw9qFWmjyhUU1iZ2VYOdDUNxr1rcvKuH110ZD7Hes3MxrCsTjP72wE4ENLR9axXlEU/rO3mV+8coi4rPC7jyxgUW7CFvrnLx/k8S11aFQSDpOWS+ek84OrZhOXFbZVd3H7I9spS7eyvaaLoX4l83Ps1HcG6RggHc+kVaHTqnt7rJwuki06MuxGuoMRagewzM60G2jqDg35vgaiONWCRiVR3e4nNEgWwIIch+ghNEHoNSoe+/QKFucNb3Dy8r7mfu5xx45x+O7LRnXeSEzm0t++S2W7f9BtshxG3vvmWtHPbpoyGm0gIkICwUkYtGr++snFfOSvm077Df9so6bDL4SQYFC+d+UsclxGFuU6WVaQNOA2iqJwoMnDkRYv75V38K8d9WM+X3ewf9Sh0R1EUZQhJ0SjFUGQcIU7JoBkWUFWlGENGiRJ4op5GVw+N73PeOwmLT/7wDy+d+UsjFp172uKoqBVq1he6GJVSTL/3dc87LgMGvWAIgggEJXJT7bgMuuobBt8EjnetPsitPsiLMxx9BFCS/OdRGMK+xu7Ry2CIDGJ3t/oGXIbTzDK/Bw71e2BAaMGgrGxblYaX724lLL0kS1gXzQzlUy7gcaTDBJGstChKAotnjAqCVJtBh7YWDWkCALo8IeJxhV0GiGEznSEEBIIBqAs3cbDtyznxvs2jboDumBkWPUa8pL610UIBMd4bmcDP//vYTQqiVvPK8Bu0hKOyszMsDI7005XIMLP/3uIjRVD5FmNAn+k/3f9pT1N/OiaOeNy/ME40url/96uoDDFQlcggt2oZXVpCgtyHAMKsMFEWTyu8Kf3juIPx7hgZhqLc51IUsJ965X9w4sgSEwah+JAkyfRm2cSiMZlluQ5ifcIvFNtejoSZ7gTJ8yripOod4eoGmYSLRiab15axufWDB1lPRmNWoVa3f9zf9nc9AG3r+8K8IuXD3O01Ud1h7/Xsj7ZoscXHl7Qfv2SsgH7YQnOPIQQEggGYW62nWsWZvLIptrJHsoZx6wMG9+9YqaIBgkGxR2I8L+vJmr1YrLCve9W9ttmfrad3fX9O8+PlcJkMztq3X2eO6do4EjUeFKWbuO3H1lIJCbz/K4GrAYtsjK44BkIdyDC5b9fTzgq88lz8piTaeuNVJn1mkQ90Qis2Go6hk4J1qokUq36097oNdWqZ98w0ZvRYDNoBoz4W/UaHGYtTe4QsZ4CNbVKYkmek/VHO3CZtANGJgQjw6hVs7xw9MYmoWicup5ooMus46Zz8llR6GJ+jqPftvsbu7n1gW00e/r/jdp94X7P6dQq9FoVNoOWi2encf2ibGYP4mQnOPMQNUICwRB0+iO8fqCl1/FmKtjYTmfOKUzi1x+eT4Z9claUBdOHrz+9m6e3D5/mlmLR0zbA5Ga0FCabcQcidJ4wOV43K42/fGzRqHoKTSayrBCTlX4r2S/uaeRLj+/EYdINeg0z6tTMy7KzeZgoy9wsG3sbxk+QjJRlBa5TjgCdSFm6tZ87oSRBttNIXWcQtQQZDiNxWabFE+5j2pFh19PUfeqfubOZdbPS+L+PLx6V9fU/t9dj0Ws4ryS5T9+xYzS6g9zz8iH+vbsRRUnUjl27MIt4jyHIhTPTOP8Xb/Vuf/vqIr56cSnaafL9FowcUSMkEIwTLrOuN4//9tVFbK7q4NvP7KVJrAaOinMKk7hmQSbXLcoatNmkQABwtNXLz/97mNcPtoxo+xTr+Aghp1nXr26gtiPAqwdauGxO+rQomlapJHQnTSy7g1G+88xeFuQ4+kW7AOxGLWXpVg40dg8rggBUk/R76AqMzyJUWbqVaFymdYBogaKA06SjrjNIXGHQqFcwKtornCqvHWjh3SNtrC1LHfE+NywevOm5JxTlpn9sYWGugx9fM4dMh4H/7m1mU2UHu+rcyErCjXJZvos9DW5+ecN8rhqh5b3gzEYIIYFghBh1atbMSGX9N9byvef39bEAFQzOikIXj9y2fFya3gnOXA42efjVq0dGLICOYTGMz21MUZRE/5gTnjvc4uWOR3fww6tn8+GlOQP2xZnqPLW1jjlZNjZW9BU5dqOWBTkONlW2j0gAHWN3fTeL85xsrxl5f5/xwGHUjtuxmtxBAoOImfgIeseEIvE+TXEFY+Pv71WxZkbKKS0yRGIy//PcXl7Z30J3MEpNR4CZGTYiMZmnt9dz+dx0/rJ6MXWdAeZlO3jysyto84ZJPaE/mODsRgghgWCUaNQqfnrdXHbUuDnc4sWiV2M36rDo1Sf0sRDoNCpuX13E51YXCREkGJIDjR4+8tf38QzTK2YgjrZ6SbXqe/vOjJUdtW7K0q1Utvn6NQ39wb/387s3ylmc52Rulp1AJM6cLBurilOwm0Y3Qd9S1cn2mi4sejWFKRZmZ9pwmCamqXAoGudPbx+lNNWCJCUiHnqNigU5DvY1dHO42UM4Nvrs+D31bpblu6jtCtB8mqLjXePg4Lkk38m2YRq07m/0DFt7FonLZDoMQgidIu8dbeeZHQ1cP0SkZzh0GhUqSep19IvEZd6v6ODua+dwy7kFfPGCYpwnNO2WJEmIIEEfRI2QQDBG7t9QxY9ePNBr3ylJMCcz0Z38SKsXzwBWvGcL+Ukm/nbTUmGGIBgRH//bZt472j6qfYw6Nek2Azajhsau0LikxwEsyXNysMmDv8dlChK9dXbX9Z8Ya9US5xUnc/vqIpYXDm2qEIzE+drTu3lpb1Of54tTLfz0urkszHWMe63ChqPt/Pb1I3T4I3QHohSkmKlu99PuO55mNifTNmYTAomEuNg6jLgYD5aOw3kKks0jdnwbqiZpXrad6nb/mIS7oC9Wg4ZnPreSkjTrmI8RlxUe21LL957bB8A/bl7CBWVp4zVEwTRE1AgJBKeBGxZn8+tXj/Taa5t1CWembTVdqFUSMzOsWPUaajsDNHsGnqS5TFoKT+gq3+AOTvv6o1Srnqc+e45YdROMiFZviM1VI7e/TrHqyXWZONLsmRAb4201XSwrcLKlqguNChblDT4hjsYV3jrcxpEWH29+bfWQ9W//2FDVTwQBHG318aF738dl1pGXZOLqeZl8ZFkucUVBo5JOKR3vkU01tHnDBCJxOvwROvwRjFoVc7LsmHRquvwR9jV6cJi05CWZiMbkfg1lh0IhER1Ktuj6iKuJYKxGNQ6Tlgy7AUWBthFGDZfmO9k5ROqfQasSImic8IZi3Hz/Vv7zpVWjjq4eQ62S0PcsIqTbDKwuHXndkUAghJBAMEasBi1fuKCYn/33EJCwhH7ysysIx2Se3dnAj144QDCaWFXOTzKRYtX32V8CwnGZbSfccF1mLfOy7OxpGD9L4NPN1y+ZIUSQYMQ8uaWO6AhsnY9RkGRmS/X4uYcNRKinfqQoxToip7IGd5DPP7qDC8rSWFHo6rO4cYzheu90+iN0+iNoVSp++OIBAFQSLMhxsLo0lQtnpjI704YkSeys7eLulw5S3uJFVmBtWSq3nleARa+hKCXRm+vdI228cbCFOZl2qjvcveeZm2Vny0mRFXcgijuQuOYUp1owalUjdoYLxxR0p8E8oKLNT47TiM2oYX/j8GJtQY4DvUbFwWYPB0ch7gA8wRjRIWqF9tV3jyjNTjAyGtxBWr2hMQshSCyQFKaY+dHVc0QqtmBUCCEkEJwCN5+bz2NbaqnpCLC9totoXMGgVfPRZbk89H4NB5sSk4nqjgDVw/TnAOj0R+n0d7M038mOmi5GMT+cMszNtk/2EATTCO0ImxY6TVpKUi3UdU18M8tjvXRi8sgn+K8fbOX1g61AIgXrgrJUProsh+JUK4qisKvOPaLjhOPHU/JkJVG7tKPWzW9eP/L/2bvvsLbO6w/g36u9N3svG2NssLHxduJMO3vv1axmthkdSZu0Sdr80jSzTds0aXbSpEnbNHs429vYeBsb25i9QUJ76/7+EMgIJJBAAmHO53nytEhX974Yge553/Oeg3SlCBqZAPuGBCkf727Dl/s64PL6IBfxIBXwYOlfqXZ5g7+HqgbDiGlmR7r8+xwrctSoaTNGVCGtJF0RVcGFsWo22LFQqR71uPIsZcT/3kPl6SRo7Rv5b7XN7cP2BgOKU2VgwaC2I7pAixzDMMDPTpuJLI1kXOdZVZw87sILZHqiQIiQcRDyuLh/zSzc8lY1vD4WDb1WzOjPdb6iMgsPfrh/TOfd1mCIed+MSK0o0uHMOWlQivnosbpgtLmQohBBKuThw12t+HK/v6oXl8OAAQJNBwcc7rSgOJX265HIzMkYPXAuSfP3fBm6khEvRrsbS/K12Hw08pS9wep7rHh5Qz1e3lCPU0tSYLC6glZ+RxKqrPOANqMjbCPPgYDH7PDA3J+2VZGtCjk7Hkl8V91oQLpKhAw+F0e6wwefXA6Dtj47kuVCnFScjE/3tEMi5KIzTDrweCzIiWyfkGCMJfqzNRIYbG5YnN7RDwZwsMMfNM5Ok0MhFsDl8cHq8gzrT0TCY1lgRoo8JhUZKQgiY0GBECHjdPrsFKwo0mH94R78/D978NYNlZCL+LhkYRbeqWpGTfvYNiLXtJkgE3Bh6d+0rRDzMCtVARbA4U5z1FWUBFwOKvM0KElXwOr0YP3hHqgkfFgcnqD+KXk6KS6rzA55jjWlqfjH+qPoMjlx3bJccDkMrnxpK44OulH6Yn8H9WcgEdsTojqXWMBFjkYCmZAHt8+HA20mRFDVOKZ8Maoj9FVNdOXA/Umz0RPyOEhRiNCkP7aaYXd7g6rpLcrToFHvX72ORFufA1wOg0V5mpArPrPTFahpM2FWmgIPnlWCLI0EvzuvFF4fi1VPfh/T/Y4KEQ8M418ZHPq3j89l4PaySJILkaeTojVM/5+RCHkcuL1e9I2hOh2XwwkKmsuzVGjSW6G3jr/S3XRw85vb8ccL5+LiBVmTPRQyDVEgRMg4MQyDl69diHe3N+N3H9fgin9sxevXV0IjFeCPF83FWc9tGNN5LU4PkuVCzEpX4FCnGZlqSeBmRCrgojBZiiNdkaUJnVycjKcvLYcyRC8Op8eLZ78+jB2NBuTppEhTht/LwDAMbl5ZEPTYmzcswoV/24SO/pnstfs70GV2IFlO+4RIeCzL4sV1R/H4FwcDj+lkAuQnybC/1Tjps+oTVRZ6qCyNZEwBhNPjw5J8bVAgVJAkg0TAQ36SDD4fO6b0NW//64pT5RDxuPCwPni8PjBgYHW4wQJo6LUGUpv4XA74XH+6073/3h319cIxOTywubww2NyYkSKDmM+F3uqCgMfxr+I43Og2OyMuiDBUeZZqTP8+pemKYXs6dzX3Qcz3lyk/0G6C0xObPVR8LoOyTBWcHi9sLi/kQj6aDFM/4GJZQCqk21EyOeidR0gMCHgcXL04B3laKW54fRuuf20b/nPLEpSkKXBOWTo+2t02pvN2mZ3oMjvBMP7+FgOsLi9sTi9EPA4cI3zIqiV83LgiH7eM0MtHyOPil6uLxzQ+AMhQifGL1TNxz3v+mx63l8Wjnx7Any6bN+ZzkuNbu9FfXGBHU1/gsTkZ/tWFKsvEp4OGMlkbrsdzVYvLg2yNJBAMzc9WBwovjFe4wLQkTYE2ox3724yYnX4szfH8eRl4a2sjdg76GY/X/jYTFuVpsKPRMGIxg2iVZSmxbYwFOHgcDtKUomHBq93tw65mf28quYiHgx3mQMrimMaYqUSX2TEsxXJBrhp669Qu2sBh/KuVhEyG2DYtIGSaW1KghVLMx67mPjz8cQ04HAZPX1KGi8bRMA4AQmXptBkdmJulCnk8hwHuW1OMzfefjNtXFcb9po43pP/JR7vbMMVblJEYc3t9ONBuwmd723HeXzcGBUGAf19HIhUH0Ujj0+Q0nj7d047LK7Mh5nORp5OCBQt5nGfaa9pN6LO58fKG+qDHORwGz1xSDolg/Hs/Bttar4dczMeMlNj0KCvLVGJfi3HMqZe7WvrQbnRgboYSeTrpsOcPdpixrcEAlmWxKE+D4lQ5xIP+TbgcBiI+BzIhD5V5GlTkqJGhEkPQX0SEYfw9jXa3GNFuHL7aZbZ7UJGjxuJ8DUrTp97ezFytBPecOgNamXD0gwmJA1oRIiRGqhsNePbrQ4Gc/A92teKaJTkoSpHjiYvm4pYT8nHTG9Ux7X1SVa9HZa562Cbyh86ZjWuW5MbsOqPRD2lmybL+sY3WZJJMD3qrC9e/tm3ESl7CCKvHTZRY7RGaaB/vbsNrP1oIhmFQmadBZZ4WF/xt07DqcbH20a42XDQ/E0sKtIFN67k6Kf5182J8tKsNH+9pi1kBBb3VhfwQQUckBDwOZqbIUNthhlzEx97WsQdBgw2kx83NUMLHssOa1Fqc3qDUO6WYB7VUAIPVhaJkOQw2V1BxnGS5ELPS5Kjrto5YNKe204xZaXI09lghF/GRr5MG7flMZEIeB69ctzBkuXlCJkpcP3kee+wxLFy4EHK5HMnJyTjvvPNQW1sbdMx1110HhmGC/lu8eHE8h0VIXMzPVmFOhhIivv/Xyuzw4MdvVsNgdYFhGBQmy3HtkpyYX3dncx8k/OBf5fGuQEXr4gVZSB3SO+ifW5uGHeeO880YSUy//6RmWBA0sEjJMPDPkvO5mJ1AM9pDVzmnipp2Eww2Fyr7U41KM5T49Zmz4n5dj4/FFS9txYe7gtOA52aq8MBZJVh71wk4ZdbwRpccBijNUKAszOp2OF1mJwqTo7uBFgu4KEySYW+rCS4vi16rK+ZFOPa0GrGvzYQ0pQhzMhRYkKNGeYjvzWj3oNVgh8XhAZ/LoG5IZb4usxMtBjtaRij8kKOVYFGeBnIhDza3D51mJ4T8qfO+/fnpMykIIpMuritCP/zwA26//XYsXLgQHo8Hv/71r3HaaaehpqYGUumx2ZzVq1fj1VdfDXwtEEy9lARCGIbBL1YX46YV+Xh5Qz3e2tqIoz1WnP2XDfjPLUuRqhThumV5kAh4eGJt7Zg39Q7l9rIoz1IFlZXlTHAZUamQh9+cXYLb/rkj8NiWQVWUbn2rGhyGwTllaei2uHDV4tgHhCQxfbGvHe/vbA16bGaKDIe7LEiRC8HhMDjYYYZMxMP+NhMqctQ41Dm+/RQxMTUXhAAAz317BKfPTg2szFyzJAeb63rxxf6OuF/7rnd34UC7CfefERx8KSV8vHj1Any2rx3fHezGtgY9Ti1JwU0r8pGq9E+iXPnSFmw8ElnJcrGACybKHxKXYQITVfHWbnQE7RtakKMGGMDi8KBJb4PN5YXby0Il4WPzUT1yNGIkyUXos7vA53LAZRhYXaHLeMtFPMxIlqG6qS/Q82qAd6LLK47R3EwlfrQsb7KHQUh8A6Evvvgi6OtXX30VycnJqK6uxsqVKwOPC4VCpKamxnMohEwYtVSAn50+E9cty8WDH+zD5/s68J/qZtxxUhEA4JKFWXB6vGPuMRTKvlYTKvM06DI50NBrw9FuK0omeHZ9TWkqTpiRhB8OdQMIrgL03OXzAjPsf/7m8ISOi0wOlmVxz3u78b8hQdCCHHVgw3fnoMmAgdC9utEAjYSPeVkq7BxjU8zx4nMYtBhGb4CcqPa3mfD1gS6cWpICwD9J85uzS/Dtwa64p8gBwKY6fzDT0GNFklwY+FvA4TA4a246zpobXF7/zc2NOG9eOs4pSx81ECpJk0NvdY2pianF6cHuFiO4DCZ8P9rQIgcaiQBe1odcrRSMFjDYXNjVbEAkBeaS5UJUhylCwZ8CK5kcBnj0vDmTVpCEkMEm9DfGaPTn0Go0wdVBvv/+eyQnJ2PGjBm46aab0NXVNZHDIiQudDIhnr6kHAIuB+9tb4HDfWx2TykRBDbDxoLd7UVVvR4NvTYky4VonYSbOIZh8NQlZVic7//9Lkk7FogNTjO67cSCYa8lx5/1h3uGBUEFSVLobS6I+BxIBVwoRDxopAIkyYRBN7Z6mxs7m/tQlqmETjbxGQJuHzvuTveT7Tcf7oPZcayscrpKjP+7YM6EXNtod8Nkd+Oql7fiuW+PjHjsm5sb8M3BDshFfKyZk4Zfri7G1YtzsKxQC7lo+FytkMdFxzj2Gnl9LGZH0MQ33vQ2F4x2DwRcDnY296Gh14aKnMgqp2mloQsLyATcKVGk5sYV+ZiTOfk/A0KACSyWwLIs7rnnHixfvhylpaWBx9esWYOLL74YOTk5qK+vx4MPPoiTTjoJ1dXVEAqH/7I7nU44ncf+CJpMY2tWSchEEAu4kIt4aNLb8Ny3h/Hz0/1lqs8pS8fifA0e/fTAsJz68eJzOVhVPDwXfyLoZEI8cm4pXlp/FNcuzQ167rvaLhQmyab8DSaJzOEuy7DHtFIBui0uONyRrUo09NogE3DDNvSMp631+kCjzqmo3ejAX749EpSidlFFJj7c1Yr1h3vieu0mvQ2//7RmxP0tLMvima8P48/fHEaawv9ZrxDxceugiRKfj0WT3oYjXRYc6bbgSJc5UAQiSS6EkMcBh8OAyzBQivlIUYqQohDB7vLimpe3oi1MP6YD7SYUJEmH7cuZDHtb+zA7XYH9bSa09tlRmaf2p2UyDDxeHw51mANNtQEgTydBVYhS3zIBF1q5EDXtk9t/azQLc9X4+ekzA1/rrS688EMdbltVGLLPHSHxNmGB0B133IE9e/Zgw4bg5pKXXnpp4P+XlpZiwYIFyMnJwaeffooLLrhg2Hkee+wxPPzww3EfLyGxcnZZOt7a0ohXNzbgZ6fNDOTtJ8tFeOKiMnQYHTG9yTtlVvKkbvSekSLHHy8qG/b4axsbkKuV4OFzS0O8ihxPHG4v/lvdEvTYjBQZatpNSFFE3mjX5vTAaHej1ehAcaocJocbbX0T1+i0LEuFbrMTTXpbyBL2ie7F9UexuECLVTOPTYwsKdDGPRACgPd3tKIyT4PlRcMrR3p9LO5/fw/e294CjYSPdpMTX9d04pT+VL4BHA6DXJ0UuTopTkHKsPOM5F83L8GaP60Luc/G7WWhkwkTIhDK1kgDPeKGFkcQ87kQ87nAoO9BJxOivmf4in+GWoLazsQOgtKVIvz1ivmB9L0eixOXv7gFh7ssuGll/iSPjkxXE3K3dOedd+Kjjz7Cd999h8zMkatZpaWlIScnB4cPh95HcP/998NoNAb+a25ujseQCYmZh86ZjQ/vWIZsjQSXvbglqHqWgMfBGzdU4opF2TG73uCmhonkyYvLhvWOIcefHosTq59dh5r2Y6v1lbka1HVZYHF6AxMBkdDJj2UFHOwwo8fsxKI8DSZqa8H2BgMae23I10mRoRZPzEVjiGWBn7yzM6hk//XL8nD/mmKoJPGdfff4WFTV6/HPLU34aHcbnlpbi6fX1uKv3x3BHW/vwHvb/YGyVi709z17f29QgZXxytZKcGF/9cwsjRiZajF0MgF0Mn8qZk2bMWbXGo9OsyNkCmCOVoKSNAX0NhcAf78dqYCLpt7Qac8igb+xa6heRongoopMfH7XSiQPmgj53Sc1ONxlQWWeBjrqI0QmSVxXhFiWxZ133on//e9/+P7775GXN3qFkN7eXjQ3NyMtLS3k80KhMGTKHCGJbHa6Ev+9dSnufGcnbnx9Gz68YzkyVP4bKyGPi/87fw7ydVL8/tMD476WIkHTC5LkQjw2QXsUyOT56b92omHQzVplniaoD0o0QYxKzA+qvOXysthar0dBkhReHxt0nXiq67YiP0kKmZAHi3OSq9lFyezwgDfoH13E5+LHJxTgtNmpOPPP62ELU5ksVqobDfh8X/hqdVyGgY/1B9CXvbgFuVoJ5mSqcHFFJlbOSBrXtR86ezbOKUvH33+ow9cHEnPvscfjC0p9G8BhmKB2AzwuA4fbG7aS3O5mf2CXlGABRbpShN+dV4qTZwWv6O1u7gukhV88we0eCBksritCt99+O9566y28/fbbkMvl6OjoQEdHB+x2/9KvxWLBz372M2zevBkNDQ34/vvvcfbZZ0On0+H888+P59AImXBSIQ/PXFoOj49FfYiUjBtX5OPmGKQHyOLcSX6opl4b1u7vwJNf1uLxLw7i+e/r8NL6o9jXahy2cbc0ATYpk/jZ0WQYVvWrtT/VZ362CjqZIOTeoXDEAm7Ix+u6rWjW27AoTwM+N/7LQ7PTFfB6WdhcHsxMkWNRniZQxIHLYbAwV40kmRAVOerABEciaQ+xVyZPJ8X1E1C+uMvsREW2GqIQxWEKk6U4OKT6W0OvDR/vbsMNr29D9ZBKa9HicBgsyNXghasX4N5TZyRklTKLy4u5If4uSoVc9FicKE6VAwCsTm9Ele66LU5U5qpDrjKFkq2RoDRdgfnZqpg2NeZxGNxyQgG+vveEYUEQAHh8/iBPIuDijDmhJ74JmQhxvWN6/vnnAQAnnnhi0OOvvvoqrrvuOnC5XOzduxdvvPEG+vr6kJaWhlWrVuHdd9+FXC6P59AImRRKMR/rf7EKclHoVZv7VhfjQLtpXDn82RNUjKCu24IH/rcP2xv1+PHKAijFfLyw7ih6LMeKmczJUOKZS8vg8rCQi3hUKOE419gbHOBrpHy09tnB5zBjSoscqRSwl/UXNMhSiyEWcHGoM/IAK1LZGgkUYh72tR5L8xvYh5EiF2Jhrhochgns8evuf+/Py1bBYHVN2IrVaK55ZSt+f96cYY2Wb1qZj+d/qIt775nqJn9Ak6oQIUkuhFjAhdfrg0zEx5Gu0Pt03F4Wt75VjT9eNBcnzhxf8Rcuh8GdJxchSS7Efe/vHde54oHPOxagFSXL8Oxl5djTYsT97+9FplqMPJ0k5L6gcKoaDMjWSIb14srTSaCTCeHxsfD6WJgdHjT1WtHU/+PnMEBZphK7W6JPG8xQicEwwK0nFiBdJUZRsgyZ6vB/72enK5GtkeDEmUlBrRYImWhxT40biVgsxpdffhnPIZBB3F4f/rejFZcszJrsoUxr4YIgwD+D+cvVxVh/eEPYY0bTbLAhWxvfgKOmzYR73tuFE2Yk4YGzZmF2uhJeH4tsrQRHuixo7bNj7f4O7G014pSn1wHw74d64MxZuHpxTlT7RMjUcKjTjCe+qA16rCBJBr3VALePhVrCh8HmDvPq0HwRVCho7l9xqszTYG+LEXb3+FO9NFIB8nVSVDcawrbs7DQ70Wl2hizvvbM/6JuboYTd7Y1qFYzHZTA7Dj3AXt1YD73ViZtXHqvKJhPyJrQBZ4fJgQ5T8OrU/GxV2CC5y+wcsfJcNFiWxcd7YluhM1bsLi/KMpWwubxYWqDF7HQlZqcrsbmuF5vqepCjjS4QkoZYSV2Qo0Zthwk2lxedYcqP+1hAyA+9ChtOulKEe06biTWlqfD42Igrv4n4XDx2wRwUJcuiuh4hscawU6Ho/AhMJhOUSiWMRiMUioltIDmVOdxevLapAT9emU83pQmGZVnc9EY1vj7QOabXV+Zp8O7Ni8f1c+00OVDXZYGAx4HN5UWaUoSilGOrtG6vD06Pb8Q0PLPDjQ2He7CtwYD6Hgu+q/U3Wj2tJAWPXzgXaunE94ch8fOzf+/G9gY9eFwOeBwGMiEvqIlkUYoMh6NctZmbqcSeKGanU+RC6OTCQBWuaPE4DCpy1NjT0gd7hCW+AUDC58A2wvElaf7fnUhKG8ezVLiIz8GOB0+FRHDs93bB779Cj8UVl+tFojRDiX2toX/GczOV+N9ty2KW0na024KrXgpfVnuiSAVcnFOejqJkOdKUIqSrxCjLUgUmjwf+dn9d04kHPtg3LHiMVHmmCnyev7y4xeXBvlYTZqXJcWCU92FBkhQ5Wgkq87SQCnmoqtdjc10PeiwuqCV8FKXIMTNFjjPnpqEyVwNOAqYckuktmtiA1iOnKRGfi3PL02FyuNGkt8HjZVGepaKgKAEwDIOZqbIxB0JV9XrUdVtRGOVMm8nhxl+/PYJP9rSjtS94FvaMOan425UVga/5XM6oHcwHGiSumZOGHosTpz79Aww2N9bWdGJX8zrMzVTiqsU54057IYnB62ODbtgYMP7Sv/1/UuqiWBUZYHFEV5hgYJWmIkeNQ53mYalBI8nRSoLS3KIxK1054n6WgQCoKEUGMZ8bVXAXSw63D/taTajMO9a488L5mXhh3dFJGY9CxAtbvW1OhhJvXr8opvt68pNk+M+tS3Hdq1U41GlBslyIyyqzsShPgytf2hqz64xGJRHgsQvmDnt86OfvnEwlUpXCMQdCu1r6UJalRJfRCbXUv1JzoN08ajC0MFeD+9fMgrK/suDVi3Nww2vb8M3BLrx07UJU5KjHNB5CEhEFQtNYmtK/qbc0nY//7WxFtkYCbYJVnJmODFYXPtsbvspSJP67owW/XF0c3WuqW0LeEIn5XNy0YnxFHHQyIb68eyX2t5rwysZ6rD/cg68PdGFPixGFyTKsmZOGyxZmjRpckcT1m7NKcLDDjAPtsWty3Wsd20pFdaMBGgkfOVoJGkfZp8Mw/hu/HY16eCJfBAqyp6UPczIU2Ns68vc+sCKWp5NCJeZjV0vfhPYnYhigLCt4Y/49p83AD4e6hxUtmAgzUuRBq4YDFuSocd+a4sCNeCylq8T48q6V6LY4oZYIwOdy4POxE1oRcNGgQHQkKQoRTi9Jxa7msQXOZZnKQDW59kHBVIvehsz+PT1elg305uJyGPz9qgqcWjK8uEGOVopUhQjzslRjGgshiYruOggYhsEF8zPxyZ52/OXbw0ElO8nE43EZ9NnGl6ry/Pd1wxpajqatL3Qu/t2nFmFe9vhnAJPlIhQmy+D1sSjLVGJetgoCHgc9FifWH+rGkf4VgxaDDV1mB1iWRZ/NhRaDjd6TU4BaKsAtJ8S2KaLR7h5zVTi9zQ0eh8GMlPAroxkqMQqTZaiqH3sQBPg39oui2FtR32PFzuY+ZKjEqMhRg8thUJImx/xsFVzjGcgoWBZo1gcHhkIeF+/fthT3nDojbtcNRScThFyxW1Oaiv/cuhQLciMLFsaCYRgky0WBiRcOh4Eiwipr4yEX8nDriQX4w4XDV4PCueXEAlyyILry0slyIUrTFdjbYkRpiP1mZqcXLX12NBvsyFQd20/62AVzQgZBXWYHStLlOKc8HT8c7o5qLIQkOloRIgHf13bhu9puqCQCXLU4Z7KHM23JRXw8c2k5fvTatnHNFv/+0xqcOTctohs0lmXxw6HQH3D5uthtZs3SSPD2TYvDPu/zsfhwVxv+9t0R8HkcFCTJUN1oQKpChDPmpOHBs2YBGJ5CQhKD1Rn7njRJcmFgxjpadf1l6suzVEGNjPN0UiTLhdjVbICzLzZLMmMZY4vBjhaDHakKIXwsJqTh8I6mPhQmB1dllQh4+MnJReAwwJNrD8Xt2jqZAPlJMvTZXDjUaQm5N2myGoLGc2FOwOPgrlOKcNXiHChGKJYTCsMw+ONFZVgzJw0/enXbiMcWJcvg9vrQaXKgy+wviMDnclCSJg+5P21Rnibwe7FqZhIuWTC8kNI7VU341f/2Bj6LfD4WqyidmRxHaEWIBJw1Nx0vXl2BKxdlT/ZQpr0TZybjo9uXY0WRbsznMNjcePyLg6NWb2w32nHHOzvDlh9OGdQJPN44HAa3ryrE8iId+mzuwNg7TA68srEehb/+HK9sbIDRHl31MTIxZqbGvu1BpFWoRtJqsKMyV4MFuWqkKoSo77Fia70eTk9sbn/FAu6wfXXR6DA5wZmg4P6rmvB7D69fngdJmN5N0eJxGGSoxCjNUGBpgRYzUmTosbhQVa8P+7emOFUek5/3WMTrujwOg79dMR+3nVgYdRA02MJczag9quQiHhp6bUGFPnY290EsCD3n7fGx0PZXPSwJU6nw7a1NgSCoMFmGX50xawyjJyRx0YoQCbiQujsnlDmZSrx5wyK8vqkBv/1o/5jO8erGBny8ux2L8zX4+ekzkaESY0dTH+q6LTjQbkJVvT7s3oCyTCW0MiFKM2JTjXFPSx929acDzctWQzOoapzD7cW97+1Grk6CTLUEczKU+L62C016G3gcBnIRD0IeF0lyIV7dWI+aNhOeuqQMAPDmlkY43V6kq8RYPTuVKhhNokx17JuJSvjj/5jqtjjRbXGOWt1trLLU4nH3MZqoRc51h7rxfW1XyCIlEgEPlyzIwmubGqI+r1rCx4wUOcwOD3otTnSZnWjts6O1z46iZNmoJcTvWFWIe06dMWm/vwty1THfJ8UwwNOXluOUEOlm0ZIJeXji4rm44h+hizpU5Kixqyl0wY5w763qRgM4DLAwV41XNjTg/HmZw4rsLMrT4GCHCYXJcvz+vNKY/ny6TA58sb8D5VkqJMtFSFVO3KQbIQMoECIkwV27NBcnzEjCVzWd2NlswIbDPTBFUQ2rx+LEJ3vaseVoLzw+Fn0herkIuAxEAi5Y1p8mV5gsw8EOM9ZfuyBmaWgWpwevbWpAQ48VczNV+MOFc1Cc6g+yRHwurliUDZfH179BWo7ZGUq88EMdLlmQhRVFSZAIuJD29z0ZvGdoX38FrsZeG1bOSBqxpDeJr0i72UeDO8Y9QhMpFqsJExUIOT0+XPfqNtx+YgF+HqKgyr2nzcCX+zvQHkWJ6dJ0BQ51msNW3DvcZQlbqSxDJUaSXIgrFmVP6iTGghwN3trSFLPzSQRc/OmyeSH33IzV0gIdlhfqsOHI8IbbDPxNhkPx+VikK0XI1Ejg8nhhd/nQ2GvFnEwltjUYsKu5D+kqMe58Zyc+uH0phLxjq4IPnFWCO08qgkzEi2kFPwB4d1sznvrKn4pZmCzDV3evpLRnMuHojoGQKSBXJ8VNK/0b0Q91mvHA//ahqiG6Mr8j9QqZl60OuonpNDkhF/GRJI/dDN3SAh2+uecEmOyekNWglhUOTwPM10mRpZYE3SBxOQy4nGMf1I9fFPnGYxJfY93LM5Kp0OkuFmltE3X7J+QxKEyW459VTTixOBkLhxQlkIv4+N9ty3Ddq1U42GFGeZYKZocbEgEPHAbQW11oNzrg6W/EKhfx0G50wBXuLrxfqH+j4lQ5PrlzOXgJUC1yXrYqZueak6HEkxeXxSVVdH6OOmQgtKPJELZXl9nhQZfZMax/0rYGA8qzlNjVbAQD4EiXvynyA2eVBB0Xj+p9APDNwa7A/++1OGF3e4N6XBEyESb/rw8hJCozUuR498eL8ep1C3FScfK4Z5LlQi5MjuBVIq+PjUsVJYZhovpQzdFKKdVtCtkQh4pSTnfsCjDEax9OLGK1iZgJz1SLwedysb/NhD6bG3/6+nDI41KVItxyQgEA/81xXbcVe1uN2N1iRLPBDo+PhZDnbz6bqhBFVOZ8f5sJBUlSCHgcXLkoGz9alotHzi1NiCAIALI1EqhjcMN/wfwM/O+2pXEJgoDQvw9Jcn+xjW6zE2nK4S0wDndZwlZFFHD9k0oNvTbMy1LhpQ31WBemcE6s9Vqdgf9vsLmxvSF8Ly5C4oVCb0KmIIZhsKo4GauKk9FlcmBPixEf7m7DJ3vaop5BNzu9ONBu9vec6E8zszg9MU3pINPDxrpelGcpIeBy4fL4wOcxqG40wDeOSMHoiF1hjOI0Rci+NeORLBeia4wNLwebiIygNKUILYZjRR02HOlBh9ERcm/GefMy8H1tFz7f1x7yXE4PO2IT2aEuWZCJC+dnYmaqHCqJYPQXTDCGYVCWpcL3tWMPAnK1ElxemR3X4G5odc9LFmTit2fPxkV/34wD7SakpsrRbnSGefVwdvexNOuqBgMqctS44+0dePT8OTi7LD1m4x7K4fbCOChNW8jjYEEuNWolE48CIUKmuGSFCKeUiHBKSQruOqUIa/d34rvaLlTV6yHmc3F5ZTbOLU8Hj8vg65ouvLqpPrBPSCMVIFcrAQMGffZjs7qnzErBPafOwNFuC+xuLzJVEvTZXfiqphPpKjH0VheWF+qQO0mlbkliMjvcw5o/6mQCZKkl2DmofHU0mvU2yEW8kD1nopGlFsc8CCrLVOJotyVQqng8JmJdxBsiIv1wVyt+3L/6M5THx8aksl5xqhyPXzg34fd/LC/URR0IaaQCnD47FWfMScWyAl1cV7C9PhYl6Qq0Gx1QS/h49Pw5gZTia5fk4L7396JJb4OIx4Ejwn5Ue1tNWJSnCaRGVzcasCBHjTvf2YntDXo8fG5pXL6Xn/9nD8z9DWzzdVI8d8U8Sosjk4LedYQcRwqSZLj1RBluPbEA3WYnFGJe0MbX2elKXLk4Gze+vh27mvuQp5OGnNX9Yn8H2o127GjqC3nzBAAcBrjtxELcfEL+uMrCkuPD97Vd2HJ0+L61HosLRpsbM1JkONRpgVrCR7pKjAPtJshFfOhkAuhkwek8g99xPh87pgAmSy2GXMQHn8dAyOPC7vKi2TD2EtdD5ekkgRXU8ajM06DL5MDRHmsMRjWyIyEqt/3hi4PgchjcsDxvWKCijyDlbTRlmUrceVJRwgdBAHDNklz8p7olqupxNyzPw+2rCuM4qmO4HAZPX1IOlmXhYxFUvGCg2ltpujLq/aNb6/XI1UrQ0Otvtnu0xwqGAV7f3Ii5maq4VJS1Oj2B7IXTS1MxO10Z82sQEgkKhAg5TiXJh+eKA4BOJsRbNy7CDa9tC1lBDgCSZUJsGyFfWybkwe724qPdbTA73HGbNSRTw75WI3753z1hn3f7WLQbHcjVSpCiEGFrvR4qCR9GmxtGuzvQ+HQsVP1lm90eH3hcBlwOA5+PRVWDAUDsAp+hkuUi1PfYxnWOPJ0UVWEqrcVaYbIsEAilKoSwODywuLxgWeD3nx7AusM9eOKiuYG+YSzLRtSMeSgOA8zPVmNVcTJOnpUcqAw5FQh4HDx5cRnO/evGsBNAQ83JmPgbeIZhMLSYYp5OCoWIhx1N438/6a0uCHkcOD0+/GP90bgEQmeXpeHb/mIJkjG8zwiJlcTYpUgImVAyIQ+v/agSs9KGb+gty1TCx4ZPq9BKBeBz/b19mvQ2NOnHdzNIpj691QWrc+SiBmaHBzwOJ5CC02dzj7vIwIIcNWwuL6rq9djZ3IdtDQbora7+ICi+DLbxr5ZopRO3V8bp9mJuphKpCiEy1BLIxHwUJsswM0WOBTlqmB1urHl2HTYc9lckYxgGVy/Oieoa+TopvrhrJf5z61LcvqpwSgVBA0ozlDh7blrEx9dPwEpeJLQyIXQyIebnaEY9VinmY2aqHBXZapRmKFCWqUST3oYMtRiL8jSYna6Asz+17mCHOSYrg0OdPy8TL12zAOlKEb4+2IVOkwOHO81BrREImQi0IkTINCUWcPHMpeVYMycNm+t60W60w+zwYMvRXkiFPFTmqeH1sahu7AOPwyBXJ4VWKkBDjxWd5mMfjKfPTp3E74IkgpUzknDzynw83d8TpChFBpPNjW6LE1yGgbt/dn1wlajxkAm5mNVf+GBocZDRNuKnyIVQSwXw+NiQqWKRco9SLjoSXt/E3fQpxHzs6U/l6zCF/jnk6aT4yTs78NcrK7CkQItF+RpopIIRb4TlIh5uXJ4PqZCLSxZmHRdpsiuKkvDBrraIjh3PeyjWlhfp8MbmxqDCN0PNTldgf5sJRntwNsC8bBXMDg+21uuhFvtLpQ8silXV67G6NPZ/59VSAXosLvRYXDjtmXUw2t1IVYhw7dJc/GhZ7phWJAmJFgVChExjDMPg9NmpgWCmvseK72u78OX+Dmyt16MkTYFUhQgyEQ9Huiw4EuIcSwuG9/8h08/KIh3+t7MFHIaBQsSHSsxHqlIEi9MTSH0z2NyYl63Czqa+MV1jboYSfB4HNpcnbOpmVb0e5Zkq7GoZfo352SrsaOpDZ39xg3SVCDqZEHtajEiRC2Fze4OKMiTLhRDzOdDIhOg0OdDW58DcDCV4XAaHO82Ym6HEwQ7TqD10wgkXkMRDJI2G63usyFKL8Yv/7sZfLp+PsiwVMtXioEBIxOdgeaEOaokAM1PlOLssPZBOd7woy4o83S1WwX0sXLMkF/+tbgl8XZ6lQnmWCh/sakWfzQ0Bj4PWvtDpooN/Jw12D7I1ksBq/67mvrgEQke6zLhjVQFuXJEPh8eHu97dBZZl8fgXB3F5ZRYFQmRCUCBECAnI00mRp8vDj5blwe7yggWLJ7+sxef7OsK+xjOBs9okcZkcHhhtHjg93hH3/Oxs6oNSzB82Ix2Jlj57RGk6XpYNupEb4BqSdtPW50CnyYksjRjtfQ5wOQwW5Kjh9vog5HOxrUEPlgUa9f6bxxytBHta/TPtC3PV6DI7h+3ViNSsNDkOtEe+KX88uAxwuCuyazUb7JidrsANr2/D4xfOwfxsNfa0GCHgcZChEuOpS8owP/v4LnOcp5NBIuDC5hq9h1Ui3awXJstw0qwUHO70/6zPLU/HtUty8d72ZgCAy+ODiB/ZjojBveWEvPjsoshPkuG+9/diRqoCq0tT8fqPFqLP5sbP/r0br29qxE9PKYrLdQkZjAIhQkhIYoH/A/7mlQWobupDu3F4rxQBlwMeJz4fkkabG/+ubsaVi3ICYyGJa26mEoUpMlidHnSbneBy/IUL0pVi6G0uaKQCsCwLDsOgrtsSSL1h4G8SXNs58o36SOk+Q+3tD1ZytRIYbG7Y3V5kqcXY12oadqzXx6K5P9DxjFKhrrH3WGB1oN2MedkqpPYXf4hWs96OhbnqEYuSREvE48DHskErVAyA+TnRXWd/mwlLC7R44stDuP+MYly3NBc6uTCiVaXjAZfD4MpF2fjH+vpRj412H1W8Ge1uHO2xQinmQdO/B+2Hn6+Cx+fDm5sbseFwTyCYDydNKQzqRaSJ0162hbkaPHBmCZbkawH4MxTUUgFeunYBukxO/PRfO+H1sXjy4rKECjjJ8YWKJRBCRpSqFOHdmxdjZsrwwgoFyTJkayUxv+aBdhMu/8cWPP99HVr7/DefP3lnJ6zO8fWSIfGjkghw1tw07G8zocvsRLvRgRaDHSz8e3Gq6vXY1mDA1no9fCyLXK0UlbkapChEqO00Y94I6Uiz0xWoaR8exIxGIebD6fYiRS5EaozTtyxOD3Y1Gca8kdzi9ERcmSwSxalypCpFmDdktWbBGIKtyjwNNtX1Qi7iIVsjRa5OGlUQ5POxeHVjPZ7/vi6q6yaSO1YVQS0Zeb+TTiYc9u892ZLlQrg8PsxMUWBFURI4HAZJciHSlGL8YnUxrloSPnArSJJiXrYKnUNSNlWj/DuMxw3L86CU8FHbYQbbv+GPYRikKEW4ZkkOPtnTjq9qOuN2fUIoECKEjErE5+JfNy/Gghw1BIPSJErSYlcVal+rEXta+vCHzw/irOc2QCXm4+FzZ6MgSYb9bUbsbDbgx29W46GP9qPLPHx1iky+qxbl4O9XzUdphgLzs1XI00lD3oTrrf5Z66oGPTpM/p/lkW4rxGHSdoQ8TtTFCSpy1DjQZoLD40OzwQ6HO/YpnLPSFBGlT4Wzv80U6P8yXh0mBxp6bUHBVbpKhB1j2I9l6k9btDg8ONQxcgDKsiza+ux4af1R/P37Olz3ahXmPPQlHv64Zkr/niolfDx2wZwRj+HFsXnqWF26MAtJciGS5IKQKznnz8tAplo87HGNRIA2owM7m/owOD6/qCIz5gVx+kJUXHxx3VEsf/w7vLjOHzxbnR78d0crcrWSCSsxT6an6bHOTQgZN7VUgJ+cXIRb3tyOwjQ5JAIeTA43nB5vUNPWaLAsi+d/qMMbmxrRY3HC0/8JPC9LiR3NBqycmYQTn/w+kJLUrLdjw5EefFXTibV3r4S0f5Z68EziwNc2lxdWpwcOtw9eloVawsfamk6UpClQOgm9P6YDDofB6tI0nDAjCY99dhBvbGmM+LUyIQ88LhNIUxsgFXCxq7kv6DGdTIAsjQQ+Hwtff7qdw+1FikIEvdUFuYiHzUOauzbqY1vmeEGOGlUNBqQoQvfrGk1BkhR8LgdKMT9kEZKoz6eTorqpD5z+m3M+15+W2NYXfTBitLuRrRaDx+Xgrnd348s0ZWDl1+Rwo7HHhnajHZvqevHp3nZ09xefqMhRobqxL3AepXhqV5A7fXYq8nTSsCWyE7FH7Fc1nchWS3B2WXrI5/lcDv5wwVxc88pW+FhAIeahOMU/odVutKPZ5f/9S1EIcd+aYpxXnhHTZrh9Nhce+aQGT19SHvS4xemGUsyH3eXFukPdcHl8YFkWt60qxJo4FGogZAAFQoSQiLEAbG4fagZt8n5jUyNuWpk/pvPtaDLgj1/UBj2mkfCxr80Et5dFrlYStC9jQGufHWf+eT0EPA4sDg+6LU6cV56B+9YUQynm45mvD+Gv3/lnFvlcBu/ctBhmhxu/+M8ePHlxGQVCcSYW8PDLNcV4d3tzoB/JaNqNDizJ18DnA7pMDszNUoLLMLC5PPD4/P1MBkiFvJCV57ot/pnmXN7wdE1tf6neWMjRSAJ7iTpNTizIUY+4t2ioTLUYLQY7nB4fxAIuCpOlONLlv9lOVQiRrZGi2WAN2qcxGJfxp6y29gc5s9MV2NEfLFY3GrAgRw0OhxnzTHq70QEOA4BhYHd7ceHfN+GEGUk40mXBnpbgFYORnDAjaUzXTxQMw+Ciikw88WXtsOc0UgHOn5cxCaMamd3lRUOvBauKk8Mes7xIh+oHTkVNuwlPfFmLqobg98nNK/Nx1ylFkAhif4v452+OhGxC+/PTi5GuFGHBo18jSS7EM5eW45olufh8bzvkx0FJdpK4KBAihESsLFOJC+ZngMdh8N52f5nW//v8ACRCLq5cFP2m4V3NwzftpqvE2NdmwsnFyVhdmoYrFmXj7a1Nw45rGBIg/bu6Bf+uboGIzwlKg3J7WTz2+UEUJEnx3OXlWF0aebNEMnZSIQ8f3L4Md76zM9BrZWGuGj0WF1iWhdvLDivl6/Ede2zwygLgL2ns9vggF/Fhd4dOR9NbXSjLVGJPixHFqTIc7DjW40UZw30OqUoRGvU2VOT4e231RVkBT8znBgJEu8sL6aAbTrmIj6oGPfJ1Uoj5bjjcvqDGszIBF0WpcuxtMWJRngZWpwcdJkegn5LXx0JvdYE71nJ2/Xysv2gAn8ug2+zEfwaVZY5EhkqM8izVuMaQCM6ckxYyEHrwrFk4f14mmvU2ZGliv09yrBgGmJetGXWVXi0VYFmhDhU5aiz7w7fo7d/rdvcpM+JWre2dqibMTlfgworMYc8VJsvws3/vhs3lxfnzMgKVCWelKWC0uWP6+0vIYBQIEUIippII8NTFZfCx/lz0x7+oRVW9Hh/ubIPL7cWPlvtXhliWxaFOC579+hC2NRiwrFCLRXlaXLowC9z+1J2NR3rwv53Db64G9iBtOdoLg9WF+hFKMYcSai9IdaMB1Y0G/Lu6BQ+d7ca1S3Oj/M7JWMxKU+CfNy7CmX9ejyyNJGi/UFmWclggZHKEL4axe0jQnKUWo9kwvCcKh8PA42OhEB/bHzEnQzEssBorlYSPfa1GcBjA7fGNWoFrsAyVCMlyEXYOSfUbqIiVphTicH/QeLTHijSlCDaXF0a7v/8Sn8tBi94WWA0LV62u09S/ojNO9T1WlGUqcajTEjb4HMAw/kqPA5YVamOaUjVZcnVSlKQNL9aRofIHP7f+sxqL87T49ZmzJv37ZVkW3x7sglzER3WjHnMyVEF7OkM52m1Fr9UFAZeDX585C9eMUExhPON6cd1RGGxu3LemOOxxq2enYluDHjetCM4wuPDvm/CTk4twTph0P0LGg4olEEKiwjD+ssgVORr85fJ5/Y8BT399GFe/vBUvrT+K617dhtOfXYfGXhueuqQMbq8Pv/rfXtz6VjUaeqz4b3ULrn2lKmQ54x1NfZidroDV5cWCR7/G5qO9MRs7ywKf7m0P7Cki8ZeiEOHhc2YP2+fT3ufA0NvG2g4ztBGW6k2Sh96bI+By+s9/LEjqtrhiVqGtMEkGq8sLHwsc6DChMk8z4vELc9XQSgXIUovRbnQMC4IAwOzwIFMlQpoyeBN7u9ER6Le0s6kPVfV6tIUoYz+U1eUFE6ON/P6S5SwqstWYna4Iuy9mYa4GRwZNWlxUkRWT6yeCG1fkBf7/ojwN1v9iFSrzNOg2O7Gv1YSXNtTjkz3tkzhCv8ZeG1oMdhxoN+HC5zfj491to76mIFmKFUU6/PfWpbh2aW5cgrmP97QjRysZMQgCgFNKUvDFT1cE3mMbj/Tg8he3oElvw+ubGmI+LkIAWhEihIyDTibEQ2eX4HCXBXIRH1vre7H+cA8A4LKFWbjntBlIlouwtECLduNmrK3pxO7mPnSaR+7G7vT4Z59jWV54QFW9Hvn3f4abVvobxw69+SSxV5KuxNDYs8vsxIoiHSxOT2CFozJXg+rGyPa18Lmh5/Ga+5uoDqw8SvgcdEQQPESiPEuF3S19ga/dXhZV9XrMTJGhttMy7Pg5GQoc6bLAYHOjd4SFzZp2EzQSfkxuQguTZVBL+DHtT2R3+1Dd5D+fVipAQbIUXSZnID21PEsVtB+pJE2BhbmJVVZ6PC6Ynwmry4tHP63B/WfMCqTCbarrCRzz+09rcPrs1FFXYOKpzWhHWZYKu/uD7dc3N4RMQxtMyOPizRsWxW1MLMtiZZEOKsnoExz1PVY8+WUtWvrsWDUzCe9uaw70rxsorz3Zq27k+EOBECFkzDgcBtctywt8QHWaHLjj7R2objRAJREgWe7v3cLnciAT8pAsF0ItFYwaCFlGSJGKhbIsJV5cV483NjfiH9cswIqiqb2pO9HlaiVYVqjFxiPHVvcq8zSBoLk4VY4+mwsenxeRVsnusYR+DynEfLQZHYHqae4YBtNmhztkGW9Jf/XCPJ0UTb1WFCbLoRTzsb1RH3FhAb3NDX2jAZW5/mp0Y6WVCsJWOYuFXqsLvfX+/SRpSiFytFLsaBy+2f54u2G9enEOzp6bFvaGvtPkxAe7WnHJgslbCZufrcZr1y3E8z/U4cV1R7G31QiL0zOpjXAZhokoCNrZZMAFz28Cy/pX3f78zeGg3x1Lf6Pm5Bj3AyOEUuMIIeM2cNOTohDh37csxU0r8zErTR6Ugvabs0qQqRYHVf8Kx+r0YHb6sR5FsbynYuDvYwP49xPd/EY1ukxTt9/JVMAwDJ6/qgIrinQA/KsWg1cQxHwuOAyDmrbR3xuAP3CqC7N3bOCmj9v/phHGaIZ+pGtKBTwUJcvQYrCBz+OgttOMqobIg6DB9reZQlbVitTWej3cXh8yVPFf6RTzedjXYsTgVkq5WgnOmnt8FiQZekOfqQ4ukrCzKXarcGMh4nOhlgpw/5pinFaSApYF/lU1vNBMInp1YwMur8zGG9dX4u2bFuOeU2cEnht4Lw9t9EpILFAgRAiJufvXzMK5Q/pPFKXIcf8ZsyJ6vdnpxZEuMzQSPriMv3Hhgpzxp9rwOMDCPE1QgGZ3e/HM14dilj5FQlOI+Hjj+kq8et1CFCVLg57b2dyHbosTIkFk/agUI/Sn0fdXv3J7/UUzBGPscZWpEiNFIcScDCXmZSkD6ZpDJcuF2Frfi8NdFri97Lgbt1pdXuxtNWLBOFLLDDZ/TxadLLL9VmORpRZDb3PBMqSh7O2rCsELk7Z4vMnVSoKaquZopSMcPXEYhsHtqwqhFPPw+08P4IEP9mLjkZ7RXxhj9T1WXPdqFY50jT7B8aszZuH/zp+DlTOSwOUw2DKoD9i/bl6MpQVaFKXEpvkwIYNRahwhZMIszNUgVSFCRwQrME4PC6fHv3Lj9bLY3mjAojwNzA4PfCwLIY8Du9uLQyH2ZoSTJBeG7K3yTlUz1h3qwevXV6IwmT5s44VhGKwqTsbCPA0Mtm1BNztCHhdZajH6bKOXonaNEGwc7bFiZooM9b02rJyhQ4ZKHNgvxONw8PWBTrSEqDY32MJcNQ52mGF2eEadhU5WCNE1SqrnWFQ3GJAsH/u5a9pNyNVKYtY7abAUhRAOt2/Yz2puphIXzh95T8rxRCsT4kfLcvHWliacMCMJ55UnTl+hsiwVfnv2bPz1uyNYf6gHb29twuMXzsWF8zMDaaPx5PWxuO+/e7C1Xo/2Pge+vHvliMenKoNT3s6bl4EN/cHbjiYDnry4LFBdkZBYYtgpXj7JZDJBqVTCaDRCoVCM/gJCyKRxerw47Zl1IZukjkW0jSxnpytwoN0UNmWpIkcFEZ+LomQ59rYacbTbgjSlGCtn6LCsUIfF+dqwm/RJdLw+Fq9tasATXx4MWkWJZI/M3P5eQUMJuBycUpKMixdkYXGeFuIQK0wdRgeuenlroLfRUCIeB0I+N1CtbSRCHgOnJ34foUUpMoBFoKT2WFTkqGJWOhzwNxIV8Tlo6xs+mfHfW5eiIgYrt1OJw+0Fh2EmtUhCOAc7TFj97HqUZ6kg5HGwo8mASxZk4ffnlcZ1D5fD7cVP3tmJtTWdAPypzeeWpeOKRTlYmKuO+NoHO0x47psjuGJRNpYV6uI2XnL8iSY2oECIEDJhHG4v5j68Fi7P+NKHBqQrRRGVEx5scb4Gbi+LXc19w6rSVeZpQq4YVeZqUNWgh1LMx09PLsKPlsWnzOx0tK/ViJve2B6oDlWSJkdN+7FUGoYBMtViZKkl4HM52N9mQo/FCTGfA3t/ACURcHHnSUW4bGEW1BGU3950pAdXvLQ15HMLctXYHmGxAiGPgccXu+qGEgEXdrcX87PVYFkWNpcXDPwbxUP1TBqNiM/BjGQ5RAJuyPd1tBQiHtQSPhr1w8dyeWUWHrtg7rivQSJz7StV6LO5kKEWI1MtwYkzkrB0SLCwt8WIs/+yYdhrHz2/dEwNsCNxoN2E57+vw0dhSnevmpmEV39UGZdrEzIgmtiAUuMIIRNGxOdidroiUC55PFQSftRBEADYXV7sbjFCI+UHiiYA/kpFVQ2hbxZ39ZdMNtrdeOSTGuxtNeKxC+ZQqkYMlGYo8eHty/D4F7X4cFdroNjB4nwNrliUg9NKUoL+nX0+Fka7G3XdFnx7sAu5OilOnZUSUQA0YEmBFqfMSsbXB7oCjzGMP3XT4408SHd6WMhFPJhHqHI4I0UGm9MLnVwAm2t4KufcDCW4HAZWlwf13VbkaCSoHrLKmaeTgs9lAhXrRHzOqHuRxAIucjQS7Gk1Dnt9NCrzNGjoscLl9cHq9MCkH/69FqfK8duzZ0d9bjJ255Sl495/7+7v8wS8trEBr12/EEsLjgVDczKVWFOais/3dQS99pmvDsclEPrn1kb89sP9mJetCvn8FYuy8ZuzSmJ+XULGg1aECCETxutjMf93X0WUdjQaPtff2HXoDaGAx0GWWoy2Pgfsbi8YBsjRSJCsEMFgdQXSjIpT5UEV7DJUYrT2hZ51z9ZI0KQPTue765QiXFGZTeVcY6itz98MckaKPNCrJV4sTg9eWn8UPh+L1aVp0MkESFaI8MOhblz7SlXE5ylNV2Bf2/DGwIC/gh2PywTtpZmboYRYwIXN5YWAxxkW9IRTmCyFkMeF3eVFa58N6Sox6ntCp5hqpHwUJMmCeglpJAJIhFwky4XYEWIiIkkuRJpChD2tRshFPMxKU8Dp8WJ38/AUxMHkIh4+vH0Z8pNob91Ee21jPR76uCbwtVzIw+s3VGJ+9rH0xJfWH8XvPz0w7LV1/3dGYO9cLKzd34GXNtQDAJr1VmSppWDhv71kAKQqxbjlhAKUpNN9Gok/So0jhCSs+9/fi3diVNK1Mk+NqvrhN5KVeRpsb9BjVpocVqc30PhxsOJUOWo7zYFGnxU56rA3pXMzlNjTeuyGUC3hw+NjccmCLDxIM5zHnU/2tOH+9/eOuNIzWJ5OGujdIxdyUZQiR7vRAbWEH5TmF0siHgcl6QowYODy+uBjWciEPPhYFnVdVqilfBzttiLUB3x5pgoWlwcmuxtdZicq8zSobtDDy/onDeQiXtjgbjAeh8Hr11fS/o1J9M+tjXj4oxq4+lcyRXwO/nTZPJw+OxWAf3Lh3L9uRPegohupChG2/OrkmI3hQLsJl/x9M8xO/+8Ln8uAx2ECqaslaQp8dMeyaVNNkEy+aGIDelcSQiZMdaMB726LXV8Ld7iN6izgY4H9beaQQRDgn8kePA10qNMctkT30I3Q+ToZzA4PPt7dBl8MG3aSxHDW3HT89OSiiI93uL3I1UogF3KhlvpXXNqNDgjjmDrp8PhQ32NFdZMBe1uN2N9mwtZ6PbY1GKC3uVDXbQ1bAXFXSx+OdFnQZXZCJeGjql4faGSbqhRFFAQBwP9dMIeCoEl25aIcvHfLkkAZb4fbhx+/WY2n1taCZVmkq8T402XlQa/pMDlgcY6/abXT40V1owHXvlIVCIIAoDRdGQiCAODGFXkUBJGERe9MQkjc+XwsPtzVip/9e/eYmkyG4w2zoG1zjf4hP7Rgg9nhQbfZEUgXYZhjAdDgzfBaqQC7mv0rR11mJ3Y2941l6CTBaaLYc9RudEAh4mNWujIohZIX5zLFo+1Ri+R7GJy2l6ESY2sERRW4HAYPnV2CSxZkjT5IEnflWSrcuCI/6LHnvj2Cv31fB8Bf7KUyTxP0/MdhihlEYuORHpzxp/Uo+c2XuPD5TUEl3tNVIuxrC06nfGrtoUB/L0ISTUIEQn/729+Ql5cHkUiEiooKrF+/frKHRAiJoR8Od+On/9oVSB+KlcOdZqQohMMe39dmgkYqwJyM8EvioWKoRr0dFTlqiPgcKEQ8uDw+5GjE4HMZlGepUJwqh04mxOA951/u7xh+IjLlNfbasCBXjYW5apxQpMO8LBUW5WmwIEeNpQVaVOZqsChPg+JU/6pLh8mOHYNSKzVSfsTV58aqz+ZCcao87POHu8yIJhYT8ke/JVBJ+Hj9R5W4blle5CcmcXfPqTNwywkFGFzM8okva/HS+qPY1mDA786djd+eXQJR/8/4gQ/2ocUQeRsD76AiIv/c2oiadlPIaolZasmwohytfXa8vqkhum9oBD0WJ6b4rg6SQCa9aty7776Lu+66C3/729+wbNkyvPDCC1izZg1qamqQnZ092cMjhMTAZ3vax30OLocJSl1jAbT32ZGuEg9reslhALAs9raGT/E52mNBfpIUR7utkAi4KE6Vo9VgR5vBhiy1GEe7/UFbo94eslzwgDc3NwLwd0YnxweWZfH+zhY09//c52Wpglb+8nVSHB0U1KslfKQoxOgyH5v1ztPJoLfGNxCak6FE9QgVGL0+f28lR6Tl6ke5tzy1JAWPnl+KZDkVCEk0Ah4H960pRlGyDPf+e3fg8YFCCQwD3Le6GB/evgy3vLUD9T1WvFPVhJ+fXjzqub/Y14F/bWvCrDQFesxOfHewO/Dc0GqEDWEmu9qNdni8vqhS5Hw+Fk16G3J10qDHf/mfPbiwIhMrinSQi/gRn4+QUCZ9Rejpp5/GDTfcgBtvvBGzZs3Cs88+i6ysLDz//POTPTRCyDh5vD68uaURR3usyNaIx32+LrMTVfV6bK3Xo6pej2aDHQwDSPsbZ6YqRajM1UAnE0JvG7kyncXpRXOvDXMzlWBZFjua+tBpdqKlz4HDXVZEWmnY7vZi3aHu0Q8kU4bB5oaQ5w+OZ6bIh+0Rs7o8yNVKUJ6lChy/tzU4HSiWFblCKctSoqrBMGIPo5kp8siDIISPgxQiHv50WTlevLqCgqAEd968DOQNCRwA/wr4Y58fxHe13fjwjmX4/XmlgYIKI/H6WNz97i409drw7rYm/Lu6BW6vD8lyIfJ0Uri9LIqSZViQo0amSoxOszPked7b3oLrX98eVDH0QLsJv/lwH7Y36IftWeoyO3DNK1XY3d+6YIDb68PGuh7c9s8d+Hj3+CfYCJnUFSGXy4Xq6mrcd999QY+fdtpp2LRp0ySNihASC0abG6c9+0NgtYbDjFyZbTRaqQBJMgG6zQ5YnN7A41uO6pGrlaBYJkCrwR62F1Aobh+LPS0jlwcejYDHwcPnUA+V44lEwEWz3gZnmCBi4D2dNUJ6TrxTdwzWkQP92emKqH4XwilKluGlaxcgRzv85pokHi6HwUUVmXjiy9qQzz+99hAW52tx1eLI+gh1mf1tCI72WKGTCZCmFKHd6IDe6gzsDRpoSRCOgMvBX66YhyyNJLBvbsvRXtz4+nZYnB680b+qLhfyoBDz4XB7YXZ4cN2yXJxbnhH8/TEMRHzuqH20CInUpAZCPT098Hq9SElJCXo8JSUFHR2h8+6dTieczmMzDiZTZNVtCCET60i3OShlzcf6q8alq0TQSAVweXxwe9mI9w3laqVhb+waem1hq8PF21lz07AoXzsp1ybxsflob9ggaECuVjLie26klZpYGGl/B5/LoH0MzYaHrgnNy1bhjesrKf1oijm3PB3/WH80qBDGAJfXh4ue34Sfnz4TPz6hYNRzMTi2stljOZb6GcVCI84pT8dpg1afWJbFS+vr8fxV85GrlUIm5EHI54DH4aDZYMPBdjMKk2WYkTK86iGHw6AiW41TS1KwckZS5IMgJIxJ3yMEAAwTnELAsuywxwY89thjePjhhydiWISQcXj8i9Azkm19DrT1+W/SGAYoSpFBKeJj+ygrRZ1mB3QyQdCHcSJ4f0crvtzXAa1MCJ1MgJtX5gdSTsL9HSOJ7ZMIUm4a9TbMTldgf5hS0y2G8PvKxqswWYojXeEnEEQ87piqdA1exCpIkuKVaxdSEDQFZaol+NfNi3HVS1XosQxPVfP4WCjEkf1cUxRCKMX8cTXBVg251q7mPuhkAqwoGh7IFCTJUDBKc97TZqegMFmOdFX4dOsNh3sgFXIxJ0NJpbvJiCY1ENLpdOByucNWf7q6uoatEg24//77cc899wS+NplMyMqiEp6EJJKdTQZsiyAth2UBIZeD7Y2GYRvSh2rstWFhrjrhAiEAsLq8sOptaNLbcKDdjE11vfiutgsnzkjGSbOSsbxQBz59GE8J7UY7/rezZdTjWDb8PqCFuWpsi2PFOI1UCMAKuYgHpZgPn48Fl8OAz+WAz+VAxOfgUJcFdpd31HMNZnN5wWEApZiP16+vhDqKEuIksRSnKvDC1fNx4fObQz7fZXLC4vRAJhz5NpBhGNy4PA9PfXVoTOPgchjMHFLZ8LO97fhkTzsuWZiF+dlqrD/cjZ1NfWjS28BhgD9eVDbiOS+uyMJn+9oBBPd9+2h3G6ob9NjdYsSu/s8SmZCHE2Yk4bnL54ET5317ZGqa1EBIIBCgoqICX331Fc4///zA41999RXOPffckK8RCoUQCoeXyyWEJI6/flcXsjz1UBopH4c6zQCAnc19WJSnGbGPyVTIC39x3VHY3f4b0De3NOLNLY3QyQQ4tzwDFy/IRHHqyF2uyeRSSwRIU4rR2jf6io4tRKCxIM5BEOAvDrIwVw0GTNh0UY1UgNlpClQ3GSL6XQT8xUgW5WmwvFCHTLUkhiMmk6EiR4PVs1PxRYgS/898fQjP/3AEe357+rBiIEPduCIfe1uNWFvTGdX1dTIhXri6AhVDGlWvremExenBNS9X4aTiZHy0uw1cDoOnLi7DefMywpztGA6HwVlz04c9rhDxsLO5Dwfaj63SWpwefLq3HbeeWIDSDGVU4yfTw6RPUd5zzz146aWX8Morr+DAgQO4++670dTUhFtuuWWyh0YIGaM83eg3UXIRz79XaFB5th2NBqQqwlelGq2BZCIYCIIG67G48PKGepz93AZsPdo7CaMikRLxuXjgzPCl0OWiY/OHQ1N+FuSo4947SCcT4LvabmxrMIy4T0hvdWF7owG5WilK0iILvhUiHtaUpuK2VYWxGi6ZZD9fPTPsyqXD7cP3tV2jnkMs4OLFaxZAGWE63YDyLOWwIMhod6Oxf2+dxenBR7vbsKxQi3W/WBVREDSSE2cm46M7luPbe0+ERBD8WTEw4TbYlqO9uPrlrTjjT+txzStV+HRPO9zexJ9sI7E16XuELr30UvT29uKRRx5Be3s7SktL8dlnnyEnJ7KKJoSQxKOSCDAvWwW314d9IXr5qCV8KMX8Yfsc3D4WMhEXlVoNfCwLh9sLPpcDHofB9kYDmNEanSQ4t5fFt7VdUIj5qG40oChZhnnZ6lFnZMnEWl2aivPK0/HBrrbAY1qpADlaCdqNdsxMlcPjZdFmDF416jCNpUBBdHK0UvRaXajM1YDHZdA2SlGEgWIkZZlK9FhdaA2zdylJLsQzl5RjeZEu5mMmk6cgSYZbTyjAX747EvL5hz7aj4MdZpwyKwUl6SMHzGlKUVR7hYQhJq7+Uz087XRPsxHeSPsVRCBLI8GXd63EzuY+1HVZ8NnedtQOCoTcXh/ufHtn8EpZO7DuUDcy1WJcuyQXZVkqFKfKoBDHJj3U7vLC7fNBQXvuEg7DTvH2vCaTCUqlEkajEQoFpZwQkihsLg8ufH5zUJpCWaYSDMPgQLsRTk90f3pmpyvAskBN+9SuFCngcuAaNOsoFXCxOF+L+f0zp/4eHSJcVJFJAdIksru8uOSFzYH+QCVpctS0D59VHpCqEE1IILSiUAuHx4dtDYZRU0mH4jJARa4GB9pNMDuC+7a8cX0lVeE6Tjk9Xlzxj60jti5Ilgvx+U9XQCsLv/Xgb98fwTcHuuDtb3Q6WkGO+9YU45YhlelOffqHQLnt3507G2trOrH+cA/KMpX49y1LR/ybN3C7yjAMXlp/FLUdZri8PsxMlWNFYRLmZCoDxz300X683l+WGwAy1WI8eXEZFudr8btPavDyhvoRxw4Ai/M1UEsEuLwyG8sLdePaY3Sky4LXNzVgZqocl1dmx73P2HQXTWxAgRAhJOa8PhZPflmL53+oCzxWmq7AvjAVtkZTnqXErmYjNFLBmKphTUW5WgnuWzMLp89Ooepzk6TP5sLVL1dhb6tx1AIISXIhusM0k4ylZLkw0L9lQe7YUvEq8zSoGhRAZWnE+PynK0fdOE+mLqPNjUtf3IyDHeGD+fW/WIUsTWR7w6obDVh/uBunzEqBiM/ByxvqUdthxo6mvsAxH9y+LNB0OPDYzlY8+/UhNPTasPn+k3Dn2zuxvdEALodB1a9ODhuIPfDBXry9tQmPnFuKyyuz8fRXtfB4/dXvei0ufH+oC09dXIZ52f4JJZ+PxS1vVWNtTSckAm5gP180kweVeWpU1ft/vzLVYpxdlo5TS1JQnqkac1D0XW0X/lXVhKcuKafftziiQIgQMmmsTg9ueasaDrc3cOPI5TBQifnoHWMQk6URQ8LnorZz5MZ9x6Mz56ThqUvKpsT+qOOR0e7Gbz7ch492tYVNzBTwOJiVKsfucTbnjYSIx4HD40Nhsgz13RaMJaMoWe4v9T6wwvX0JWW4YH5mjEdKEk1Trw1r/rQO1hBFPpRiPnb95tRxTbo4PV78+M1qLM7XojxLhQU56pClq9/c0ogHP9iHz36yAj6WxU1vbEe70YH71xSH7W3EsiwOd1mQq5WGXDXy+li09dmDArn3tjdj3aFu/O7cUvzxy4N4p6o5qu8nXNCUJBfi7Lnp+NnpMyARRBfMsKw/pfb+9/fhhasqIBbQ3/V4iCY2oLwLQkhMvb21CesP94Bl/TPPADAzRT6mIKgoWYZFeRoIeRx4p/aczZh9urcdV720FYZpshKWaJRiPn6xuhgqCR8yIReFyf4eJ3MzlNBKBRALuMjTSickCAIAh8fXX0beOaYgCPBXh6tpN6MyV4PSDAVOLg7droIcX7K1Erx146KQjUoLkqTjXnkW8rh47UeVuOWEAizO14bt35PZ3//H7vagNEOJC+ZngMMA725vxqa6npCvYRgGM1LkYVPnuBxm2GrWJQuy8Jcr5kMtFeCxC+biv7cuwfnzMlCZp4koNS3cOkG32YlXNtbjnL9sRFOUjbyvfGkrHv30AErSFKjrnn4Te4mIAiFCSEwNNPDb3mhAVb0eczOVqO+J7g9+lkaMkjQ5DndZsLVejyNd1hEbSB7vtjcacO5fN+KNzQ1o7LVOm/TARJGhEuPZS+chSS6CVirAzBQZ9rQaoZMJkKMRB23EngjdZif6bGNvcDmgqkGPP182D0oJbeCeLuZlq/HJnStw9ykzMDjumcgV54G9Sk6Pf6/kVYtzsP6XJ0ErFeDdbdGt2kSjIkeDZy4tx3s/XoJ1v1iFH5+QD4VopBWdkYOlI10WXPD8JthcnhGPGyjFv/FID452W6EUC3DXKUWBct4sy8LkGP/vMxkbCoQIITF108p8iAd9qO5pMcIeRf8frVSANoN9xI3p01GT3obffLgfJzzxPeb/7is8983hyR7StHLCzCTIhDxsrdcHUjRrOy042DHxs7qxClwW5qqRnzR8dYAc3wQ8Dn56ShGevqQMAwsjE1mYhcP4J7sG9sikKcXQSARQivlYU5oWl2s29lrh8hz7HMpQiXH/mlnY8quT8eOV+SFfw0ZQpbTH4sRrmxqCgiG314c3Nzdg05EefLy7Db/5YB/+/kMdrn9tG8qzVLh9VUFQ4MkwDJ796nDUDZBJbNAeIUJITB3psuCMP68P+tCJxtCN3CS0NKUIm+47iQopTKC3tjTig12t4ICBxxf8/mbAgMNB3JupAkBxqnzETe+R+sXqmbjtROoZNJ1V1evRYXJAJebh+9oeCPkcJMuFuGB+ZtR9gxLZFf/YgttXFWJZ4fDy8G6vD6ufXYe67uCsg9EKpAwmFXBxxpw0XLs0FzNT5fjnlka8sbkRR/vL1xcmy3DnSYU4tzx0r6Rnvz6EJr0NT11cRn/TYyCa2IBKVhBCYipXK8Fvzy7BY58dhMU5cspAKL6pPTczYdqNDtR1WwN7Vkj8zUqT47cf9cHrC/0e1Uj5YIC4d7uKVS+Sfa1GONxeKsQxjQ3s47z73V34387WwONPrz2EU2en4A8XzA1aLfpiXweyNRIUp8rHVU56ogl4HMztL689FJ/LwVWLc/DwxzVBj0fz3VldXry/sxVNehv+dfNiXLcsD9cuzUVtpxkujw+l6coR/71uPbEAFz2/Gb/63z787tzZ8LIshDz6vZwItCJECImL2g4zbnh9G1rCNHAMJdq+KNPdQ2eX4LpleZM9jGnliS8P4q/f1YV9fl62CjsHlRAG/LPF6Wp/+k+s3t+VuWpUxWD1aXG+Bv+6eUkMRkSmKofbi68PdKKqXo83BvXeAfxlo9USAaRCLqQCHr6t7QLLAhqpAEvytfjdeaXQSGPTdDSejHb3iCtc+1qNOOu5DUGPRbMiBAB/uGAOLqvMHvMYTQ43DnWYMTdThWe/PoSLKjIpdXWMqGocIWTSzUyV47EL5kR8vFTAxdHu6VsQYSyaowgySWyES20Z0GqwQyYMnsktSpHjcKcFu5r7kKkWI0MlRrI8fOPKSOxpNUIuHP+M8cJczbjPQaY2EZ+Ls+am41dnzMJjF8zx34DrpOAwAMsCB9pN2HJUj28O+oMgANBbXfh0bzse/fQADnWaYR3D6v9EGikI6jI58M+tTVGdTyXhD9tX9fKGerQYoqsiN5hCxMeCXA0EPA7uPW1mIKPis73t+L62K2wVOzI+tCJECIkblmVx6YtbIt7zU5gsw5EuKikaqeevnI81c+KzuZiExrIsTnzyezSOUDZ3boYSIj4HHh8LDsNgR5MBQ7PpZqXJcWCcBUFisYL6xEVzcfGCrHGdgxyfXB4fBDwO3F4fthztxWd727HhSA+a9aEnYJLkQly1KAfXLc0dVtCjx+KEbkizVJZlg/bDGG1uiAXcCS3cAAA//ddOfLirDXIRD0kyYWBfT6iGxZV5Gv9eowIt7G4vvj3YhZfW12Nvq798vkLEw/NXVYTcizRWPh+Lt6uasLmuF4+cOzts01lyDO0RIoQkBIZh8OLVFVj5x+9gcow+Y8jnMuAyGHN/lOlmYR7N5k80hmFQmasZMRDa0zp6TyH5iGV7Q0uRC5GuEqPP7kK32YVmgw0V2WrsbB4eaEWKftVIOAMBCZ/LwYqiJKwoSgLgTzPrNDlgsLrgYwGGAX441I0Pd7bih0NdSFOKcPGCTDAMg811vfhwVys+2NWKXK0UF87PxE0r8/Gnrw/jzS2NKM9SYX6OCkc6LajrseJ/ty4NGsOhTjO+qunEoU4z9FYXLlmQhbPL0mP2Pfp8LNaUpuHsuenIT5IiP0kGk8ONe9/bjT7b8DYFf75sHlKVIgCAnMvBueUZqMhR4+SnfoDT44PJ4cHd7+7CN/eeAHmM9vJxOAyuWpyDM+ekodlgg0zEw2OfHcRD58yOyfmnO1oRIoTE3VNra/Hct0ciOpb2CUVmfrYK79+2bLKHMe10mhxY8fh3cHnHVhVxwNxMJfZE2YS1MleDqobhvxsKEQ+FyTL0WpxoDDNbH05BkhRr7z4hogaThIxk6AoP4E8XM9ndmJ2uwKw0BTJUYnA4DNqNdrQa7Og2O6GSCFCSrghKX9NbXfhPdTO+2NeBDqMDF1Vk4opFOYEgJN48Xh/+/kMd1h3q8e/d6TRjdroSf7ty/rDGrYC/ouQDH+wLfH3BvAycPz8jEDzGysC/8e8/qcFlldlULCeMaGIDCoQIIXHXa3Fi2ePfwhFBP6HZ6QqI+VxsbzyWkpCvkwbSFYg/P/3jO5aH/EAm8eXy+LD0D98GGgeP1VjKxI+2eZvH8TeN9PhY7Gg0RLza89I1C3BKSUpUYyFkLJr1Njzz9SGABX6xujhkYNOst2HNn9bD5fXhxasqsHJG0qRXqLM4PZAKuCOWtn57axMe/HBfoKpklkaM+1bPwqklKTFL9zvtmR9QnKrAw+eU4NVNjbj7lCIqtx0CFUsghCQUrUyIyxZGVk1nf5sJ2xsNWJSnwcJcNeZkKEasSlSUIkNphn+msSJHHashJyy1hI9/3riIgqBJIuBxcMWisVeGGrC9QQ8BN7Y3MB4f0Ga0o7rREFXa5IvrjgY1hCQkXrI0EtxyQgEsTg9+/Ob2kMf88ctayIQ8PHtpOU4sTp70IAgAZELeqAHHFYuy8eb1lajIUUMt4aNZb8d97+/BKxvrxz1xMuA/ty7F9cvzADC4Y1UBBUExQCtChJAJ0W6048QnvodzDI1WQ6UE5WjE0MiE2N3cF9gfEW2506lGIxXgnzcuwqw0+ls3mfpsLpz13IaoSsPHQiSrSHwOAy6XQbJchCZ9ZBWsCpNlWJSnwaPnR17lkZB4MdrdUIhGDzwmktXpgVQY3b4+o92NI11m/GNdPU4qTsYlC2NblGTdoW68uaURf7hgDhVQGIKKJRBCEk6aUozrlubihXVHo35tn92FhblqiPlc2N1eMAyDA22mYfshIkm9m6oEPA4FQQlCJRHg1JIUvLqxYczn4HIYVOSo4fOx0NtcyNZIUNdtgcHigsXlDfkapzv044OVZCiwu9mIZoMNYj4H9hC/E1zGvwG+IFkGEY+LXS19kAioeSNJDCOVuo6EzeXBrqY+zMlUxqRgwdFuC65/bRu+vHtlVE1OlWI+KnI0qLg6PkVtVs5IQlmWCiI+JXeNBwVChJAJc+uJBXi7qgnmCCrIDXao019Sm8MAGWpx2PKtXh8LBsdnJawbl+dREJRAXGNY2RzM62ODVneSZMLA+3p+tgo7+puy5molaOivUGe0u0c978CNGssCFTlqmB0eCPlcON1ecDgM+FwOmvQ2dBgd2N9mCrxOxKdAiBwfeBwOOs0O3PxYNX65phhXLcoe1+rS+sM9aOi1ocVgR0GCNTgdb9BIKBAihEwglUSAW08swB+/qB3T630soJEIwgZCNe0mlKYr0NBjDTurPhUly4W49cSCyR4G6ef1sdjZH6jE8pwDdjT1QcznQiMVoKHXhvnZKrQY7OBzOShMlqHD6Ag0WxzK13+eTLUYG470Rnx9UwRB1mhqO8xIVYro5oxMCpZlcbDDDK1UALVEAKfHiwc/2IfnvzuCxQVaKER8nFScjE/3tKPX6sLPT5+JmanyUc/53vZmAMDjnx/Ei9csmIhvhUwgCoQIIRPqhuV5eH9H65gbp+5tNUIp5sFoD30juK/NhFSFCMVpCnA4DPa19ME2hVPmRHwOXrxmQcx6UpDxe+arQ6hpN41+YBSGlq+2u71o7fMH/Dua+sDnMlBLBKjtNGNBjjqoqmKo8/C50aXLRLqfaCQPfbQfCjEPL1xNN4tkYjncXtz8ZjXWHeoe9lyb0YH3d7QCAF7b1BB4fFVx0qiBkMvrQ1P/iuy6w9040mVGYfLIryFTCyUWEkImlJDHxeMXzsFYMxUKk2Vhg6ABHSYHtjcaUFWvR7JChMpcNaRTcA9EikKIN65fhPIs1WQPhfR7f0cL/vJdZD2xRrIwV400pQgZKhEyVGIc7jSPeLzby6LH4kRhshThimhJBVzsaPIHSA091qj2DthcXoyndpLT40WT3oYv93diZ9PxW7CEJKY3NjeEDIJC4TDAKbNScHHF6MULatpMMPevvjrcPry7rXlc4ySJh1aECCETriJHg5I0RdAehUhFs1kVABp6bWjotSFZLkRekhQSAQ+7mgxweRN/J9HFFVmojKIMMokvh9uL331SE5NzMQyDdqMjqtf0Wl3otboAhO6plaeTYl//7xQLf0+uVoMDHabIruP2shDwop+hqO0w49WN9YEVrE/3tGNe9vFfyp5MPK+PHbZ6eqjTjH9VRR6gzExV4KVrI1u1rO0InqCwOI+flGviRytChJBJkaYUj+l1Qz8EI9VldmJfqwlV9Xrk6aRjOsdEy9KM7d+IxMfXBzphsI1/Lw0AxLowcJ5OCqmQhwU5auhk/r5b1Y194HEZ8CL8nbGPcV/d21sb8a9BM+XU/JjEUrfZif9Ut+CkJ7/Hyj9+h28Pdgae8/lY3PffPVG9584uS4v42JQhDV831/XA4/UNC5DI1EWBECFkUtx72gzIo+zLAAD8GDShVIrDN2hNJMdzOfCpKNLUm4kgE3JRkaPG/GwV1BI+6nus2Fqvx/ZGA+wuL3K1Egi4DFoMdpRFmFq5vXHkHkWhVDca8N72lqDHGigQIjGy9Wgvbnx9G37279042mNFa58dN7y+HR/uagXLsnB6ogtKZqUpcPOK/IiPH/pp09BrwylP/4Az/7w+KCBLZG19dhhjNIFzPKJAiBAyKWalKfDBHctQlBx5OVIuhxlzkYXB2ClSYNseQd8YMjFYlsXWUZqZRnW+cb4+SyNBdaMBO5r6hq1SWV1etBkdEPQXTIhkFVXA40Sdzvbyhnpc+sLmYe/Toz3WURu/EjKaum4LbvvnDuxuMQY9zrLAT/+1C3n3f4alf/gG3ij2tnUY7VG9N5PlomGPNfTa4PGx+PGb1XBMgb/RR7osuOvdnZM9jIRFgRAhZNIUJMnwyU+W4+enz4SQN/qfI6mAG5Myv4nUsXwkg0sqk8m1vdGAxt7xV1YbLyGPg0V5GsiEPAh5nLC/NzkaybES8hG8ja5clA2NdPSVUpZlcajTjCe/rMXvPqmBZ8h7VC3h47KFWdSglYyLy+PDRc9v6t8TF57B5o5q5dxgc+OKl7bi5//ejf1txlGP/3hPW8TnTlRzM5VYkEt7TcOhQCjGqFoOIdER8ri4fVUhvr7nBJxcnDzisSaHB7PSleO+ZrfZgdnpChSnyjEjRYYUuXDc54yHqbKXaTqoDlOueqx8Y6zQlq2VYGu9HtsaDHB6fHB7fajM1Qzr3dNrdULC52BGigxHukdeRc3TSfHTk4tGPOZghwl//6EO5/51I057Zl3Yynlmhwe/WF2M0ozx/56S6amu24K3tzbGbD9eKP+ubsGZf96A+9/fO+LeuO9rw6fDur1soEpjIlNJBDi3PB1vb22K2zXsLi/+U90y+oEJiKrGxdiMFKovT8hYZGkkePm6hdhytBdPf3UobPqCOIqSwOHU9wTP7FfmqtFpdo77vLFWPEqPCzJxWgyxXQ3a3mBARbYa1RHeSOVoJXC4vDjcGRzU+FigqsH/u7IwV41tDf7z6a1uFCbLwGEY6EeYVV+cr8GfLpsHlWTk1aDXNjYEFUQIx+Nj4fHS3jYSvYYeK97f0QIWwHPfjr9EfSTeqWrCvlYjHjqnBGWZKvAG9d863GnGgVH6hX2ypx2L87TgjLGIz0TJVEtQkq6Az8fGfKwPfrAPO5oMuKwyO6bnnSgUCMWYdAybvwkhxyzO1+Ldmxdjc10vnlhbi51NfYHnMtRi7IjxzDyA2JfwigEhj4McLa0IJYo8nRQLctVo7rXB7WVRlCJDXbcFQh4XHAbgMAwYxp92yen/3z6bCz2W8EHIntY+lGUpsafFiFytBF5f6MamBUlSdJmdMDtG7p81NHUv3H46EZ+DC+Zn4toluaM2lASA1j47PtodWYrQzSvzkawYvq+CkJF4vD7c+MZ2NOltuH5Z3oRee2+rERc+vxkFSVJ8eMdyyPrv4/4ZwQrK21ubsHp2KlbOSIr3MMct1v3oPF4fPD4W9542Y9SJlERGd+2EkITDMAyWFurwF50Upz+zDpb+hnZFyTK0Guwxv15VvQHzs1XYMSjommyFybIxlwonsScX8rG94VgQHknhBCGPQWWuBkaHG063FzaX/z+vj0WOVgKFmA+P1weFkIf6Hn+vqxNn6GByeGBzedFudEAs4EJvdY0aBEXqwvmZePCsWVHduOxt6YMtwtLaBUkUvJPoWZyeQOD+9x/qJmUMdd1WLPm/b7C6NBUGmxtfH4isKtx3tV1TIhCKpU11Pbj+tW3gMgzeunER5mVTIEQIITGXoRLju5+diCfX1qKhx4rva7sxM0WO2s7Y93DY02IEh/GnGiWCe0+bMdlDIINU5KohEXAjDggAwOlhA2lrA/J0EuhkQjDwp6zVd1tQnq2CyeHB4U4LusxOLMrT4GBHHxgAJrs74gpzKgkfXSOkeF63NBe/Oask6tQYnSzyPXSzY7CHj0w/OxNkEsrs9ODfUe51mY6FQVIVIpw1Nx0qMX/KbwmhYgmEkISWJBfi4XNmB2bgVRL+KK8YmzSVKGGCIIYBlhXqJnsYZJCCJBmevbQc4y04mCwXYVuDAVUNehzpssDL+hufDt77U9NmQpZaDBbRldkOt8ojF/Lw4Fkl+O3Z0QdBAFCaoYQogr15uVoJZqcroj4/md421fXgx29VT/YwxuzL/Z3wJcqHxwTJT5LhyYvL8MBZJVN+SwgFQoSQhCfic5GhEgPwV68abxGBNKUIM1JkKEySYqA/a1oC7WtIU4gg5E2/WcZEd9rsVJw/LyPu1zE7PVCIxxDwh7gXkwt5eOvGRbhhed6Yy8aL+FycVz769312WfqUKU1PEoPZ4cbvPzkAl2fqFtg40mXBeX/biLX7O6ZdQHQ8oECIEDIlZGskAACj3QOFOPoZqHlZKuQnSSHkcdBudOBQpwVHuq1IUYowJ0ORUM1LTylJmewhkDAump85IdfZ32bC/GxVVHU8PL7gm8n8JCn+e9tSlMVgk3RuBKXcz40gWCLTG8uycHt9aO2z452qJlzwt02oGaUy21Swp8WIm9+sxqUvbkZjr3Wyh0OiMLXXswgh04ZcdOzPVavBEdVrxXwOGnqtIftStPU5wGEY9JijO2e8zMlQ4ldnzJrsYZAwlhRo47ZPbagdTX0oz1KhrssMs3P0QH1w6V8AWFmUFJP8fZZl8e2BrhGPmZOhRGGybNzXIscns8ONzXW9eGHd0Zj35Eok2xoMOP3ZdfjVGbNwzZLcCb9+bYcZL6yrwz2nzkCmWjLh15+KaEWIEDIlDM5DTlVGl8ZWkCwbsTlfi8GOggS4iZOLePjblfMh4lNaXKJiGAY3LJ+48r67mvsgiSAHXybgYldzX9Bj1Y0GeGOQqvPR7rZhRR+GOmtu2rivQ44fPh+Lz/a24853duL+9/dg2R++xc1vVh/XQdAAh9uHVzc2wOqMTaXHaMxIkUEm5GHNs+vxVU1kVe+mOwqECCFTwuDgoNPoiGrTuoQ/+o0kJwH2NizJ1yJLQ7N4ie6C+RkTWhSg0+REUcrIgXpJunLYPou9rUa8G0ET1JEcaDfhlQ31ox63ppQCIeLXZXbg/Oc34bZ/7sDHu9vwTlUzTDEq/z5V1PdYcfe7uyb8ugzD4KGzZ+PCikzc/OZ2/OXbw7RvaRQUCBFCpgS99VhZ4JY+O2YkH0v50UgFKE6VBxrhAQjqwWO0h18NGuD2Tv5m3eI0qrg1FfC4HDxxURmkUZTNzVSLMT9bNeZZ4rouC3K0EswLsd9nUZ4m7IrNB7tax3S9Aa9tbMDuFuOIx8xOVyBbSwH8dKa3umC0u/GbD/fhpCd/wO4hq5PT0dqaTrQYhjdIjjcOh8FD58zGkxeV4R/r63H969sCvfjIcLRHiBAyJTT2Bn+gDJTRlot4kAu5ONjh37NRmqHA4U4LVGI+Os1OpCmEMDpGD4Tsbh8W5KgB+IMis8ODoz0Ts+lVJuTh4XNm47wJqEhGYqMkXYG7T52B3396IKLjM1TiiJqwhuNjgS6zE6lyIXI0Ymj6e/soRDz8cKgn7Ot2N/ehrtuCgqSxpX72WML3JRqwenbqmM5Njh/Pfn0IBpsbH+9um+yhJJRHPq5BcaocN63Mh1wUn9YP4VxYkYkTZibhhR/qsK1Bj1Uzkyf0+lNF3FaEGhoacMMNNyAvLw9isRgFBQX47W9/C5fLFXQcwzDD/vv73/8er2ERQqYglmWHBUJtRjsq8zQoTVegUW8PPL6v1YQ0pQid/Y0l201OuDw+5OlGnrFu7LVhe6MB2xsN2N1iBJ8b/wXzdKUImWoxrl2agwsrMoNWsUjiK5nA9LiFuWoIeRxsbTCgUW/HzqY+7GzqQ1W9HkJe+Peq0+MDO47MmMJRUvIAYFUx3WBNd816GwVBIayt6cSfvz0yKWlygL8Z8q/PLKEgaARxWxE6ePAgfD4fXnjhBRQWFmLfvn246aabYLVa8eSTTwYd++qrr2L16tWBr5VK6kxNCDmm2+wcVt66WW9Hs96OuZnD/140DAma9FYXnG4vStIUEZdqNdhcox8UJTGfi0sXZmFpgRYLczVQS0M3wCRTg2ACgmU+l8HcTCW2NYTeZG53+1CepRpWKGGARHCsB9dYXL4wGy+uOxo2mNJKBSihlM5pz0P7UEZ0sMMMn48dU0NjEl9xC4RWr14dFNzk5+ejtrYWzz///LBASKVSITWVltYJIaHVh0lRkwq4ONAWWWBjdXlR22FCZa4GHSY7mg32EWfKuy1OFCRJIRXwcKTLDJt77HuI8nVSLCvU4eaV+VQM4TgyEdX95mWpR63YxobqpNrP7vai0+SIqA9QKLk6KXI0kmGTCwNOmJlEN3fT3N4WIzYeCZ+eSfyVSX/yr5148uIyqgqaYCa0WILRaIRGoxn2+B133AGdToeFCxfi73//O3y+yd+0TAhJHEP36ogFXCzK00Aq5MEdxUyklwWqGvRo0tuRr5OO2PeEZYG6biv2tBoxc4wz3jNT5Pj4juX49mcn4nfnlVIQdJwpTJaBF8cgIEMtxu6W0csN7281gs8dPg6GAW5YloeccRYy0PbvRwrlkgVZ4zo3mfr2thpBC0Kj+2RPO674x5aI9t2RiTNhxRLq6urw3HPP4amnngp6/He/+x1OPvlkiMVifPPNN7j33nvR09ODBx54IOR5nE4nnM5jbyKTaep3JCaEjKyuyxL0dWGSdFwbzwF/kAMAFTkqmBweHO60hD12LJW+blieh1+sngkhj2b/jlciPhez0hTY2zpyVTXAn+ImFnBhd43eGBXw7wk60GaC0zP6HaaQx4V10HmVYj6uWJSNKxdlx6Sp4uWV2SH7v1TmabAob/jkJpleLpifgT98fmDalcgeix1NfbjyH1vxzs2LoaHU6IQQ9YrQQw89FLLAweD/tm/fHvSatrY2rF69GhdffDFuvPHGoOceeOABLFmyBOXl5bj33nvxyCOP4Iknngh7/cceewxKpTLwX1YWzUYRcryr6w4OUmI5+1jd2IfDnRYsyFWHfF4u5IVNzQvn8sosPHDmLAqCpoGKnNDvm6HcXhZzMoavLJakyVGZp0G66liT4FSlCNsbDLBEGDSl9b9WzOfiN2eVYPP9J+GXq4tj1ln+oopMfH3PSlxemQWtVIBbTijApvtOwns/XgImAfpvkckl4nPxk5OLJnsYU0Ztpxm3/bN6sodB+jEsG109mZ6eHvT0jJwLmpubC5HI/4e5ra0Nq1atwqJFi/Daa6+Bwxk59tq4cSOWL1+Ojo4OpKSkDHs+1IpQVlYWjEYjFArasEnI8eikp77H0e5jwcisNDkOtJtjeo1FeZqQq0zzslVo6LFCIxUEVpFGMjdTif/eunRCqs6RybeprgdX/GPrqMctytOgql6PZIUQnSb/Z1iaUoQeixNuLwseB8jWSMHlMKjrtkQc7C/IVQMssL3RgF+fMQs3rcwfz7czKpZlKfghQQ53mrG7xYg/fH6Q0r6i8P3PThzz3j0yMpPJBKVSGVFsEHVqnE6ng06ni+jY1tZWrFq1ChUVFXj11VdHDYIAYOfOnRCJRFCpVCGfFwqFEArD5ysTQo4/3ebgD1e5MLb9GLI0YuxoCr0Xg8/lwGBzIz/CD6wTZyZTEDSNVOZqIBFwYYtg9YYF4O2PcMqzlDjcaYHb6//a4xu+F240xakybO+vJleQJMWrG+tx44q8uAYqFASRoXosLvz+0xo4x1FQZjo62GGiQCgBxG2PUFtbG0488URkZ2fjySefRHd3d+C5gQpxH3/8MTo6OrBkyRKIxWJ89913+PWvf42bb76Zgh1CCADA4fbCPCT33O6ObS66iMcN3JAONitNjgNt/v0f3AiDG4c7snQmcnzgcTkoy1Rh89HeiI5PUYiQqhBhV/Po+4pGY3Z4oZHyobe6oZMJkKoUU6BCJlx5lgo6mRBHusLvsyTD8SJYHCDxF7dAaO3atThy5AiOHDmCzMzMoOcGsvH4fD7+9re/4Z577oHP50N+fj4eeeQR3H777fEaFiFkihmaapGvk6LVYA9z9Ni4vT5U5mrg8flgcXrAYRgoxHxUN+ghF/MxL1uOqgiLM7T1xXZsJPFdvig74kBof4Tl3iPR2mdHslyIwmQpttYb8OBZaTE7NyGREgu4ePS8Ulz64pbJHsqUYna6J3sIBHEMhK677jpcd911Ix4ztNcQIYQMtf7wsT2JUgEXVqcHeltsP0Aaem0h+6TMz1bhcJcFO5v6Ij7XLGouOe2cNScN/61uwQ+HusFhYlvMYzRdZie6+lNHS9PpvUcmx9xMFRgGI/ZmI8Ge/uoQzpiTRkV1JhmtyxFCEpbH68Pz39cFvp6VpkCneWI24y7K02BHU9+wtLzRnFScHKcRkUTF4TB44eoKnDU3DUkyIUpCBMO+ON8hyoU8FKdSIEQmh39VaM5kD2NKadbbobe6JnsY0x4FQoSQhFVVr0eT3r9So5bwsTNMQYNYq8hWR92nSMDj4I8XzqUVoWlKxOfigTNLYHS40WtxojJXjbmZSpRnqTAzRY5tDWN/7/I5DCrzNMhUi1GcKh/2vErCx58vnwelJLZFRAiJxsULMpGmFI1+IAHgb3isElMvoclGgRAhJGFJhMeyd/OTZAhRzyDmKnLUqB5DwPXspeW4ZCH1NZvOUpUi3LQiH51mJ6oaDNjTYsSu5j7Udo691Dufw6AgWYaqej1aDHYM/RUoTJbh05+swCpaiSSTjM/l4O5TZ0z2MKaMpQVaiAWUFjfZKBAihCQsnezYbJnXF//SrIvyNNjd3Bf1606ZlYI1pamxHxCZcn58QgF0sthVPS3JUOBghz+Qkot4Qb8HIj4HL1+7ABkqccyuR8h4KES0Khmp02fTZ0YioECIEJKw9rUeKzEc71KjczMU2FqvR65WgmR55DeyUgEXj5w7m8oWEwCATMjD/WuKY3a+3c1GLMrTYH62ChaHB0e6jvUauu3EQuRoqQ8JSRylGZQaHKn52erJHgIBBUKEkAT2fa2//5hEwI262WS0BP2Ve450W+HweFGRrcaMFNmor3vgrBKk04w8GeT8eRlYURRZ4/FIbK3XY0dTX1Ba3AkzknD7qsKYXYOQWMhUS3D67JTJHsaUIOLTLXgioJ8CISRhDazMFKfK415dp1F/rHy2ye5BdZMBhzotWJCrhiREHjeXw+CPF87F5ZXZcR0XmXo4HAZPXFQGpTg+aUInzkzC81fNB5dDq5Ak8dx72swJu5ZSzEdlngYnFyfj3PJ0nD8vI+Tf60SjlQqQrxt9oo3EX9z6CBFCyHgVJPs/KDqMjrheJ00pRLsxdFnu7Q0GpCmFSFWKcLTbvyqVoRLjiYvnYmlB7Gb9yfElVSnC3ExlUB+sWDivPB1PXFwGPpfmMUlimpEiR7ZGEqj4GWtlmUqsKk7GCTOSMDdTNWxCoNfixNtbm9BpduC7g91oTcAm11csygaHJjISAgVChJCEpZL4iyW0GR1IVQjRYYpPD6HRGtq1G51QS3xIVYjQbXHinZsWI1srictYyPGhy+xAiyG2N2B3nlSIu0+ZQTdQJOGxw+objo1GKsANy/Nw1aKcwDkHPhfC0cqEuPPkIgCA2+vDh7va8IfPD6LHMjE96EaTqhDh+mV5kz0M0o8CIUJIwtpc1xv4/9kaadwCIRF/9FQKPpcDH8vinLJ0CoLIqCQCHgy22KRz5mgleOic2Vg1k0pkk8THsiza+8a3ij8vW4Vfri7G/Gw1BLyxr37yuRxcVJGJmjYTXtlYP+x5mZCHdJUIhzot4xluxE6ZlYynLimPW9osiR4FQoSQhPXDoe7A/9/T2he360SSU87lMChOleORc2fHbRzk+CET8rAgR42vD3SN6fXZGgnmZipxwfwMrCxKAo9S4cgU0Gdz4fVNjfD4xr4ixDDAvafOxOJ8bczG9ZuzSyAX8fCnbw4HHhPxOXjluoX4387WCQmE+FwGvzuvlIKgBEOBECEkITX2WnGg3RT4mkH80oFmpMixo6lvxGM0UgH+flUFhBGsHhECACtnJOGbg11gh9wTMgywoigJF87PgFzEQ7ZGAqPdg9oOMwqSpPCx/jLEcurJQqaYmjYTnvn60IjHyEU83LGqEMkKIXK0UjjdPuxvM0Im5EEtFSBZLsS8OJSWvuuUInxV04madhOW5Gvx6Pml4DAMPtrVGvNrhfKjZXlIU1KF0URDgRAhJCG9sbkx6OvSDAW2NRjicq3CZBleuLoCFocHa2s6sLamM3DzyjDAGXPScN/qYgqCSFSuWZKLwiQZXtlYj68PdGFNaSp+tCwPxWnykI0nK3KorwiZ2pYW6rD27pV4/POD+OZg8GqoVirA1UtysKY0DTNT5UHPLSmI3epPOAzD4JSSFNT3WPHkJWXIUInxzFeHkCQXIglAQ298ijsAgJjPxU/79y0luupGAwxWF04pmR5l0BmWHTpXNbWYTCYolUoYjUYoFNTIi5DjgcXpwZL/+wZmpweAP3WNx2Vgsnvids0VRTo8fuFcpKvE6DI7oBDxcajTDDGfi6IU+egnICQMn4+FyeEedZM3IceTbw92YlezER6vDxyGwY0r8hLid6DP5oJKIsDhTjP++GUt7lhViA92teLVjQ1xu+Y5Zen48+Xz4nb+WDLa3Tj9mXW4ekkOzi1PR6Z66u2JjSY2oECIEJJw3tzSiAc/2Bf4Ol0pQlucS2gDwE9OKsQ9E9gDgxBCyOTy+Vjc++/d2N6oR7M+9qW21RI+vrhrJVIUopifO162HO3FNS9XQSrkYtuvT5lyexSjiQ2m1ndGCJkW3tvWHPS1rr+xarx1mBxwe30Tci1CCCGTj8Nh8Myl5Vj381X4yUmFMT//BfMzp1QQBACL87V49rJymB0ebD7aO/oLpjAKhAghCeVghwl7W42Br8uzVNg/6Ot4em97C/72Xd2EXIsQQkjiYBgGPzm5CBmq2BY0OKl4apa9P2NOGh49vxS/+6QGDT1W1HVPTInxiUaBECEkYTT2WvGnrw8HPcbnMvBOUAIvl8NgeVH8N+0SQghJPDwuByfMTIrpOYuSZTE930Q6tzwDTo8Pd727C7/4z57JHk5cUCBECEkY1Y0GfL6vI+ixeJbNHuqeU2egIkczYdcjhBCSWH60NBc62djTsRnGXyJcJxPisoVZUEzhvkEiPhcXzs/EruY+7G8z4ot97YH08X2tRnywc2JKj8cTlc8mhCQMdYiKRbs4jAAAM55JREFUQjZX/CrFDeAw/pmvW08oiPu1CCGEJK6iFDn+c8sSvLqxHt/Wdg0roMDjMLjzpCKsO9yN6sZjLR34XAZXL87Fj5blIksz9SqthcPvL5TgcPtwy1s7oBTzkaOVYH+bCRXZapw3L2OSRzg+FAgRQhJGaYZy2GMcZvwrQgyDoKaWAi4HKUoh0pRinFaSgnPK0pE8xTazEkIIiY9cnRQPn1uKh+GfjNvZ1IdvDnRha30vHjyrBIvztVhSoMX7O1rw7+oWaKUCPHf5PCzKP/5Sq/e09AV9bbS7safFv2/3lJKpuf9pMCqfTQhJKGf+eT32t5kAACVpCtS0m8Z9zrJMJd65eTF6LS5IhTyoJXwwMQiwCCGETG/1PVYoxXxopJPfIymWei1O3PnOTmyqG1417vTZKdBIBXjgzBJIhYm3phJNbJB4oyeETFv724yo7TAHvpYKuTE5b2ufA2I+97hKVyCEEDL58nTSyR5CXHA5DIpTFajtMKPX6go8LuJz8LcrK8DlHB+TiVQsgRCSMJ7/vg4e37FF6k5TbJqolmepaAWIEEIIiZBKIsBvzi7BpvtPQkHSsWBvWYEOx0kMBIACIUJIAqlpO5YGJxfy0DSGLt9CHgd8bvBfaaPdFeZoQgghJDoWpwff13ahx+IMPMayLDqMDhjt7kkc2fiYHW784fODcLi9gccEXA7S+3sr6WRCPH7R3ONqYpFS4wghCcHm8qC+1zru8/zjmgUozVDi491tcHt9yNFKccKM2PaFIIQQMn0Z7W5c/9o2MAyDFUU6aCQCbDnaizajAwVJUnxz74mTPcQxuee93fiqphMA0GNx4sSZSeBxOFh/uAcCHgdPXVI2rtLiiYgCIUJIQqjtMAdVdjM7PVCIeTDZoyufbXN5oZEKcO3S3NgOkBBCCAGQoRLjhuV5+Mf6enxf2x30nNkR/5YP8fDJnjasO+T/Xv7+Qx0A/36g3583By9eXYE5mUqkKcWTOcS4oNQ4QkhC2NNihFzIw8UVmRDyOChNV8Dj8UV9nlc21GPD4R488eVBmB1TN0WBEEJI4rrn1JnD0rCB0G0gEl1Trw33vLcbzkGfuakKEX5yUhEA4LTZqcdlEARQIEQISRA7mwxYlK/BExeXIUUhgkTIg80dfSBU1aDHne/sgMnumdK52oQQQhKXWMDFwlzNsMd/cnLRJIxm7LrNTtzxzg64BgVBciEPr12/cFr016PUOEJIQtDKhFhaoENrnx1NehvE/LGVzl5eqMOfLiuH9jjLYyaEEJJY/u/8OTjjz+thc3kxM0WO351XivykqVNO++uaTvzmw31oMx6r0JqiEOLlaxeiOHV69OakQIgQkhAePKsEAPDf6hYAQG2nGQtz1djWYIj4HAIeB6/9aCF4XFrsJoQQEl+5Oik+uXM5mvQ2lGYop0whgQPtJvzxi4P4bsj+JrmIhyy1BBmq4zMNLhQKhAghk87rY/F/nx3AycXJ2HikJ/A4J8oSnXlaKQVBhBBCJkx+kgz5SbLJHkZEvj3YiT9+UYuDgxqXD/jNWSW4rDILEsH0Cg2m13dLCElIR7steHlDPV7eUB/0+KFOM1QSPvpske31WVaoi8fwCCGEkCnL52Pxp28O40/fHA75/MJcNa5fnjfBo0oMFAgRQibdnhZjyMeLkuWoatCP+NqlBVr86oxZUIr50MoE8RgeIYQQMiWxLIuf/2cP/rujJewxd58yYwJHlFgoECKETCqWZfFdbVfoJ0fJjFuQo8Y/b1x0XHW5JoQQQmLl830dIwZBp89OwdJpnE1BgRAhZNJ4fSwe/HAfPtnTHvL5brNzxNcvKdBSEEQIIYSEUZKmwN2nzECf3YVvDnShSW8DAKglfNxz2kxcvjBrkkc4uRiWHdzLfeoxmUxQKpUwGo1QKKZHqT9CjhcdRgf+t7MV+9uM2FzXi16rK/CcRiqAftDX4dx6YgHuPXUGFUkghBBCRuD2+rC7uQ9Ojw+lGUooxfzJHlJcRBMbUCBECJlULMviX9ua8fDH++EY1EB1QY4a2xsjK52tlQowL1uNv145D0Le2PoPEUIIIWTqiyY2iOsUam5uLhiGCfrvvvvuCzqmqakJZ599NqRSKXQ6HX7yk5/A5Rp9FpgQcnz4wxcHcf/7e4OCIK1UEHEQBAC9VhecHi8FQYQQQgiJWNz3CD3yyCO46aabAl/LZMdqrXu9Xpx55plISkrChg0b0Nvbi2uvvRYsy+K5556L99AIIZNMb3XhtY0Nwx53e33DDw6DYYAz56Th7lOnb9UbQgghhEQv7oGQXC5HampqyOfWrl2LmpoaNDc3Iz09HQDw1FNP4brrrsOjjz5KqW6EHOc2HumB0xMc9DAMMDNVjm0No68ISQVcfHD7MhSlyOM1RELIceCv3x1BqkKEyjwN0pQi2lNICAEQ59Q4AHj88ceh1WpRXl6ORx99NCjtbfPmzSgtLQ0EQQBw+umnw+l0orq6Ot5DI4RMMrkoeC5GwOMgVyuNKAgCgFtOKKAgiBAyqn9uacS9/96NFX/8Do9+dmCyh0MISRBxXRH66U9/ivnz50OtVqOqqgr3338/6uvr8dJLLwEAOjo6kJKSEvQatVoNgUCAjo6OkOd0Op1wOo+V1DWZTPH7BgghcaWWBDdAdXt9qO+xRvTayjwNblyRH49hEUKOM79cUwyWBUR8Lpbkayd7OISQBBF1IPTQQw/h4YcfHvGYbdu2YcGCBbj77rsDj82dOxdqtRoXXXRRYJUIQMgeICzLhu0N8thjj416fULI1JCmFIHHYeDx+YtXsiyQqRKjpc8e9jXpShH+fnUF5maqJmiUhJCp7tzyjMkeAiEkAUUdCN1xxx247LLLRjwmNzc35OOLFy8GABw5cgRarRapqanYunVr0DEGgwFut3vYStGA+++/H/fcc0/ga5PJhKys6d0MipCpKlkhwi9XFwelqji9PhSnytGst8Hq8g57zW2rCikIIoQQQsi4RR0I6XQ66HS6MV1s586dAIC0tDQAwJIlS/Doo4+ivb098NjatWshFApRUVER8hxCoRBCoXBM1yeEJB4eN3j1t9vsRLfZCY2EHzIQ2lzXi6sW54z5eh6vDx/vacP2BgNWFOnw2d4OGO1u/ObsEhQkyUY/ASGEEEKOC3HbI7R582Zs2bIFq1atglKpxLZt23D33XfjnHPOQXZ2NgDgtNNOQ0lJCa6++mo88cQT0Ov1+NnPfoabbrqJKsYRMk3YQgQ7AJCjlUIudsLu8sHm8sDi9B/37cEu7GruQ3mWKupruTw+XPriZtR1WXDCzGTc8taOQDNWbph0XEIIIYQcnxiWZdl4nHjHjh247bbbcPDgQTidTuTk5OCyyy7DL37xC0gkksBxTU1NuO222/Dtt99CLBbjiiuuwJNPPhnxqk803WMJIYnH6vTgqbWH8K9tTWGDIgBIUQhx1aIcaGQCyAQ8nDE3DfwxlMBt7LVCJRZAKeGj1+KERioIuyeREEIIIVNLNLFB3AKhiUKBECFTn97qwg+1XTjYYcarGxvgGtRQVcTn4OmLy7DhSA/e39kKh9uH65fl4sGzSiiAIYQQQkiQaGID6ihGCJl0GqkAOrkQX+zvwGWVWVhZpAOP4w9yilMVcPtYvF3VDIfbHyBV1evxdlXTZA6ZEEIIIVNcXPsIEUJIpFYUJeH1H1Xirnd3obbDjBVFOqQoREhRiPDAB/uGHf9/nx6AkMfFOWXpEPBoTocQQggh0aHUOEJIQmFZFmtrOvHs14dxoD10w+TSdAX2tfmfS1WIcPWSHMzLVmFWqgJqqSDkawghhBBy/IsmNqAVIUJIQmEYBqfPTsVpJSnYXNeL1zY1YF+rEe0mBwambRgGWJirBgDk6aR47tvDcLh9KEyW4X+3LYVcxJ/E74AQQgghUwGtCBFCpgSr04NP97TjqwOdaDXYoRDzcF55Bi5ZkIU+uxserw9KCR9CHneyh0oIIYSQSUJV4wghhBBCCCHTDlWNI4QQQgghhJARUCBECCGEEEIImXYoECKEEEIIIYRMOxQIEUIIIYQQQqYdCoQIIYQQQggh0w4FQoQQQgghhJBphwIhQgghhBBCyLRDgRAhhBBCCCFk2qFAiBBCCCGEEDLtUCBECCGEEEIImXYoECKEEEIIIYRMOxQIEUIIIYQQQqYdCoQIIYQQQggh0w4FQoSQac/j9cFoc0/2MAghhBAygXiTPQBCCJkMLMviQLsZf/nuMNbu7wQL4J83LsLifO1kD40QQgghE4ACIULItFHTZsK6w92wu7zotjixdn8n0lUi/ObsEpw4IxnZWslkD5EQQgghE4QCIULIcatZb8OX+ztgsLnA43CgkwtxcUUmtDIhAODR80oBAAzDTOYwCSGEEDIJKBAihBx39FYXHvxwHz7b2w6WBZ66uAwXVmQOO44CIEIImR68PhYsy4LHpe3x5Bh6NxBCjhturw/fHOjE1S9vxad7/EEQAJxemjq5AyOEAAB8PhZ9Nhea9TYY7W6wA7+kJO48Xh9e21iPp786hG0N+pj927MsOyV+jo29Vqz843c40G6a7KGQBEIrQoSQKc/h9uLNzY14eUM9OkyOYc8/981h3LemmFaACJlgR7stWHeoG9saDTjcaUZDjw0ury/wPJ/LIFkuwuJ8LW5YnoeSdMUkjnZitfbZoZUKIOJz43odlmWxqa4Xj3xcg9pOMwDgz98cRq5Wgp+eUoRzyjLA5UT+t3FfqxGf72uH1elFn82FTXW94HEYnDwrBXefOgMaqSBe38qoWJaFx8eCZQEWLAxWNzpMDvSYnXhvezPajA48+WUt/nHNAnCi+J7J8Ythp0IYPwKTyQSlUgmj0QiFYvr8ASWE+D/0Ptrdhie+rEWLwR54XCHi4d7TZmJFkQ46uRAKEX8SR0nI9OP2+nDlS1tRVa+P+DWVeRo8cdFc5GilcRxZYrA6PTjvrxshEfLwxvWVUIrj8zfqu9ouPP75QRzsMIc9Jk8nxa0nFOC8eRkQ8I4lCrEsC5PDg7Y+O5r1NhzqNOOL/R3Y1xp+RUUq4OLiBVnI0kjgcHtRnCrHyhlJ4I+QjmZxevD21kasP9wDvdUFjVSAfJ0UyQoRlGI+mg02NOtt8PpYiPlcpCrFSFUIoZML0WKwo6bNhKM9FjT12mBxeuCL4K72vPJ0/OTkIuRqpeBwGHi8Pri9LDw+//+a7G7Y3d7+fwd/Wp3H5wOfy4GQx4FEyINKzIdEwKUJtgQUTWxAgRAhZMr6xX92473tLYGvGQa4dkku7jqlCCrJ5M1KEjKdsCyL6kYD3t/ZCqfbB6vTg011PTA5PGM639ICLa5enIOCZBlS5CIoJeGDhIFbmES4GfX5WBzqMmN/qwkSARdqqQAGqwttRgfa+uzos7khFXLhdPvwxf4OGO3+3mU6mQCVeRoUJcuhlQng8vjQ2mcHh2GglvAhFvDAZYA2owMujw9JciEW52uhlQpQ32OF1eUBywK9Fica/7+9O4+Purr7Bf6Zfc3MJJmQyWSPCAoRUEQISmlFQQuoT61rq7TXpfaWqn14Pb16XUDUq63WeqtVulge7XMf0VZttUWrWBZZFIQgMWwBsieTZJLZ9+XcP4JjIyFM1plkPu/XKy/N/M7MnPl9Z8J8f+ec7+nxI0utgNWoxnu1Nmw50pV0/1VyKdQKGeRSCSQSwB+OwR+ODfu86FVynFdoxIxiIwoMamTrlFDIpHD4w/i81Y2397fCNwLPMxRapQxxIRCMxM/cuB/5BhUeWDoNV820jnDPaDgGkxtwahwRjVv1dl+f35/69kx8u5+iCEQ0Mhy+MD46Zsfu+m7oVHLolHL87UAbjnZ4R+w5dh7vxs7j3YnfZxWbcMOcYiyZbklMu/IEI9h8pAsvbjkOuzeEC0pMOCtPj8JsDYqytSg0aWDWK2FQK0Z9ClQoGsNre5rxwubj/U7NPRO7N4yNNTYAtpHv3CCEonGEokNLCAbiDUWx60Q3dp3oPnPjMTbcRK/DHcLb+1sxq8jE7RfGKSZCRDRufX3qJOxpcCR+b3cGIIRIi6vDROOdEAKdnhCOdniwt9GBrUe78FmzM6mpRyNpf7MT+5udeOCtGmRrldCqZGh1BPr04x+1HQA6+r2/RALMLDLhtR/Mg0o+Mutx9jU5sOVwJ3ad6MZnLS6ERyGBoPFh06FObDrUiaJsDc4vycbsEhMuLMvB5En6UV//RcPHqXFElPZ8oShkUkmff1Q63EFc++LOPmuDAGDB2WbcMKcYC87OG7V590TpqtMTxGN/O4TGHj/OMutwz2VnJ73mJhiJYccxO96v7cDBdjcaun3wDHF6Wzq66aJiPPGtGcN6DFcggh+/Wo1tR5OfckaZy2JQoyRHi8JsDawmNYqztajI0yMvSwW5VIJWZwD/9XEjpluNWHpeAUeVRgjXCBHRhPBZsxP//vp+HO/y4exJeqz//hwUZWtxrNOLFX/YjVZn4LT3VcqlWD7DigeXnovsFFYxIhorLQ4/bnlpd58po1kqORZOzcOMIiO8wShUChluvqikz2di1/FuPL7xII7YPIjExvVXggHpVXLUrFk85BHjbm8IP/x/+wZVAIJoMBacbcbiafm4qDwX+QbVmEztnIiYCBHRhHDV89txoMWV+P2ishy8cttFeHHLcfzfD+uSeowZRUa89T8vHlR5WMo8vlAUGoVsWF86hBBwBSJwB6IIRmOIxgTkMgk0ChkmGVQjNi0L6B35qW1143iXFx3uIA7bPNhxzJ7UtDWtUoYrplswxZKF/U1OfFTXlbLF6mNBLpVgdmk2rpplxXfmlp62nRACnzY60GD3wR+OIRCJweYKotUZQL3dh8Zu34ROFCn9yKQSmPVK5BvUuPaCItxaVcqp30lgsQQimhC++gd/d0MPfvLafnx3XknSj3GgxYVffViHn1w+ZaS7R+NcLC5wqN2NrUe78Jutx6FVyjHNakCrI4C8LBUeu6YSZeYvp5UdbHPj99tPYMcxOxy+CLQqGaYVGHBrVSle2dWIfU2OAatPmbQKZKnlKDBq8PCyaagsNJ627Rf7oYSjcbS7Amjq8aPVGUSLw4/tdXbUtg19U0h/OIY3q1uHfP/x5MpKCx5aNg1Wk2bAdkIIrH67Fq/sahyjnhGdWSwu0OEOocMdwoEWF3677QRmFhtxyeQ8fOuCQq5BGgEcESKitOQNRTH/iQ/7LcH71LdnoNkRwK+SHBUCgJsuKsH/+bdKXk0bJxy+MAwaxYiM5EVjcbS7gmh2+FHT4sKnjQ4c7/Si2eEf8Aq/Si7FD79+FgxqBY7YPPjbgbYRHTlZOCUPCpkEdZ1e9HjDCEZjHHEYYTOKjKgsNGK61XDa0SCXP4LnN9fhdx/Vj3HviIYuR6fEjCIjynJ1yFLLEY0LSADo1XJoFDLE4gKxuIBWJYdRo0CeXoWibA0KjGrIB9jXaSLgiBARjSvhaBzbjnbh4xPdaHUGoJRLYXMFT7sPyYY9zfjzXVVo7Pbhr/vbknqOV3c34epZVsyryB3JrtMQtTkD2HSoAxIABo0CS6ZbElc3V//1c7y8qxFSCXBrVRm+O68EOpUc4Wgcjd1+NPX40ekJocsTRCgSh04lx8WTc3FFZQHq7T5sr+vCwXYPjnd60eLww+YODqnSWSgax7Obkk+2B2srF9yPugMtLnhDUayoKuv3+Ms7G/D0P47AE5o4RSEoM/T4wif3iRrc3xG1QoqZRSbMKjFhutWIi8pyYDGqR6eT4wATIaJxpLbNhb8faIdOJYfFoEauXgm9Sg69Wo5JWWpkaxWQSCTwh3urrI3kmoTR0uLwY/lz2+HwR5K+z5yyHEgkEvzs2hn456HOpL/EHOv0MhFKA6/sasDqt2vxr/MRys06nFuQBZVcho017QCAuAD+c2cD/nNnwxkf878+aURpjhYN3f5R6jWNRwVGNf70gyrk6lV9bo/G4vjlpqP49ebjKeoZUWoEI3F8Ut+DT04W/ZBKgP/9zXNx+4KKFPcsNZgIEY0jxTla+MMxfFRnR4PdB5VCCo1SBgkkCEfjUMql0ChkCEZjONdiwC+unwmdKr0/5haDGmuumo5/Hu5Ejk6JQpMGhSYN3jnQhq1HuiCVSFCRp8OU/CyU5GhRYNJg2YwCAL3T5wZzof/lnQ247sKicZEgTjSxuMCehh68uOV4vyMh9XbfKRvkDoYQYBJEp2h3BbHk2W2YW56LXL0SaoUMDXYfDtncaO45fdVJokwxq9iExdMsqe5GyozaGqEtW7bgG9/4Rr/Hdu/ejTlz5vR2oJ/5+i+++CLuuuuupJ6Ha4Roout0B/HIOwdRlKOBXimHRilDNC7gPzkKUpStRXmeDjOLTFDKhzfvVwiBX35wFC2OAFYtmYrCMywwToVgJIbaNhc+PtGD9TsaYPeGBnX/9d+fg29MnTRKvaMvRGJxHO3wYH+zE/sandh6tBN2bzjV3SIiopMWTsnDb26ZPeGKLqTFGqH58+ejvb29z20PPfQQNm3ahAsvvLDP7evXr8cVV1yR+N1oPH0lHaKhcvkjeP3TZkgkvVOrplsNpywY9IWieP+gDeVmPcpzdTBo5IlkPRyNQyrBmC8ynGRQIxSN4zdbTwzYTqeUYcl0C9ZcPR0G9ZcbiUZicXR6Qmjs9qHB7kezw49OdwgOfxgVZh3OL8mGVAK4gxFsP9aNdz7rXXPzZnUr8rJUKD9ZNcvhC8OkVeDOr52F8wqNUMl7R6P6+wPa4Q5i7TsHMX9yLhZPsyAYicHp762yVZ6rO22JYiEEmnr8qG1zo80ZgM0VRLcvjG5fGHZPCDZ3ED2+4X2Z/sP2eiZCo0QIgTf3teKPHzfiYJsb4djpK6gREVHqXHZuPp6/+fwJlwQN1phVjYtEIigqKsLKlSvx0EMPfdkBiQRvvfUWrrnmmiE9LkeEaDA8wQhq29w41ulFNBbH2flZmFZgSGwu2OkO4qXt9dj4eTs6XCEo5VKUmbWYXmDEwql5uLLSAolEgmgsfkpCFIzEsL3Oju3H7Fg+swCzS3NGrN9N3X7c+cdPcdjmOWNbhUwCnUoOnVKOcCwOuzeE0fyUZ6nkyDOoUGHW49yCLHiCUby2pxmBSP/VtQxqOa6otODGi0oQicbh8EfQ1OPDZy0u7Gt0oN0VHLW+6pQyPHfz+bj0nPxRe45M9lFdF1a9/hk6PYMbpSMiotGVpZLj5rklKDfrUJitwfyzzBN2f7203FD1jTfewPXXX4+GhgYUFxd/2QGJBIWFhQgGgygvL8dtt92GO++8E1JpclfdmQhNfE5/GIfaPThic8MXjiFHp4TFqEYsJtDlDaHbG4JRo0Bxjhb5BjWEAOJCwBOMosMdhN0bglohg0mrgEmjhFGjgFGjgEohRTgaRygaByAgk0ohk0ggk0kgk0gglQL+UBTBaBzeYBTb6uz4+Hg3Gnt86HCHYNYrMSU/C3qVHI3dftR3+xCOfnkF/L4rz8Htl5RDJpXgSIcHuToV8rJUp3+hZxCJxdHiCMATjOBohxeP//3goAoMZCqtUgaLQY0ZRUasWjwVxTnaVHdpQvMEI7jq+R3DWu9DRETDd16hEd84ZxKm5OsxryIXZv3Qv4OMJ2mZCH3zm98EAGzcuLHP7Y899hgWLVoEjUaDDz/8EA8//DDuv/9+PPjgg/0+TigUQij05dVGt9uN4uJiJkLjmBACwUgczkAYDl/v6MBhmwdHbB7UtLrQ4hi/C1qLczQIRXqnpkkkwOySbMwpz0GeXoVcvRLTCgyYPEnfZ61cLC7Q5gygwx2ETCqBUi6FVilHvkEFrfLL2axOfxg/frUaH9XZU/HS0l6hSYNnb5yFOWUjNzJH/QtGYvhHrQ1v72/DR8fsfS4IEBHR2FLIJLi1qgw/vWJqRhYHGtVEaM2aNXjkkUcGbLNnz54+64BaWlpQWlqK119/Hddee+2A9/3FL36BtWvXwuVyDer5mQillw8PdWB3fQ8au/2YVWLCkukWtDoCaHb4cazTi31NDhxqdyMUjY/qtK3xIFurQGG2Bv5wDIFwDHZv6LSbKmap5CgwqVGcrYVBo8Bf97cOaX+UicqsV2FuRQ4umWzGv53PXbdHizsYwWcniyDsa3Jgb6MDXu7DQkSUUgqZBCuqyrBifllGz34Y1UTIbrfDbh/4CnRZWRnU6i83Z3r00Ufx3HPPobW1FQqFYoB7Ajt27MAll1wCm82G/PxT5/FzRCj9RWNxLP3VdhzpOPN6FqLBkkqAkhwtpuRnYaolq3e+s0mDwuzestv9VaKkoRFCoM0VxPFOL47YPKhtc6Gm1YXjXZz2RkSUbn5zy2wsmZ65pbC/MKpV48xmM8xmc9LthRBYv349br311jMmQQBQXV0NtVoNk8nU73GVSgWVKjPmOI43oWgMPb4wXIEILps2iYkQjRidUob/cUk5ls4oQFmujiM9w+ANRdHi8KPdFUSnOwibKwSbOwBvKIZINI5wLA6HP4wuTwhdntDJNXRERJTOLp+WzyRoCEZ9p8V//vOfqK+vx2233XbKsXfeeQc2mw1VVVXQaDTYvHkzHnjgAdx5551MdkZZmzOAersPF5XnQNFPOeh4XMAXjiJLffrkNRqL40iHB/saHdhypAs7jtsRjPBLEw2sstCAtVdX4otxG41SBp1SDq1SBqlEgkis98t4PA4o5BIoZFLoVXImP0MkhMDBdjde3tmATYc6h11+nIiI0k9ZbuZOhRuOUS+WcPPNN6OxsRE7duw45dh7772H+++/H8eOHUM8HkdFRQVuv/12/OhHP4JcnlyOxqpxQ2P3hnDhY5tg0ipQVZGLUDQOTzACdyCKbl8YDn8YsbjAkun5uHFOCYKRGNzBCHp8EZzo8qKu04ujHR74w/2XSCYaiEouhdWkQYFRjamWLMyryMXFk83Qq0b92syEF48L1HV6sbu+G5/U92B3fQ/LWRMRTXBKuRQPL5uG784rTXVXUi4tq8aNFiZCQ3fdup3Y0+BIdTeIAADzz8rFr246f9yX92zq9sMViKCxx4cGuw9OfwQluVqU5eowzWoYsdcXCMdwvMuLuk4Pjnf60NDtQ2O3Hw12HzwsXEBElHFkUgl+e8tsLDo3s/fKYyKUwbbX2fHspqNQK2TI0SmRq1diutWIRedMSmwa+oVoLI73am344GAHPjnRA5t79DayJAKAh5dNw8xiI6bkZ0GtkMEXisITjEIll2KSQX3mB0hj3d4Qnnj3MP68t+W0baQS4OLJZnxnbgmuqCwY8nNtrGnHv7++n1NRiYjoFEXZGmRrlTBpFSjN1eLBpdMyanr5qBZLoPQ23WrA3Ioc/GbrCUT/pa6yTCrBkun5uGfRFEy1ZAEA5DIpls2wYtkMK4QQONDiwtPvH0G93Qd/OAZvKMr9QGjEaBQyfP/isj5V3UxaJUxa5QD3Gh/+dqAN979ZA09w4JGYuAA+qrNjxzE7XvtB1ZD3ONp8uJNJEBERQSrp/T6nkEqQl6VCaa4OZblaFJg0yNUpYdar4A/HMioRGgyOCE1Q9XYf3v28Hdvr7Dhi88CgUcCoUeC8QiPWXj096RLDoWgMLn8EPf4wenxh+EMxhGNxhKIxhCJxtDoDqGl14fNWF+xeLsKmgZ1fYsLCKXn4ztxS5GWlZgpc/OQFAql0+GW2faEofvbeYbyyq3HQ971qphW/uun8IT3v3kYH3tj35ciTBECWWoEcneLkVUAl1AopFDIpFDIJ/vRpCzbsaR7ScxERUXpRyCS497IpuGNBBZTyUwteZTpOjaMxJ4RAqzOAz5pdeP3TZmw92pXqLlEam1OWjTsWVODiyWboxrBAwvEuLx54qwZtziC+O68EdyyoSPqiQCwu0OEOornHj2ZHAHsbHXjns7YhbSSqVkhxzaxCPHntjEHfdygcvjD+488HsOlQx5g8HxERjZ5Hr6nELSyKcFqcGkdjTiKRoChbC51SjuNdXiZCNKA9DQ7sadgLpUyKyZP0yNH1zmXO1ioxKUuF8jwdys06VJj10CjPPJwfjwts/Lwdr+xsRCASg1zWW3Zbp5RBe7I0dzAax8aadsROjgi1OYNJJ0H7m524bt1ORGKDu26kUchQlK1BRZ4OkyfpcVaeHtOtRpyVp4O8n7L1Iykai8MZiKDbG0a93YdZxUY0dvtQ1+kd1eclIqLRc80sK66/sCjV3ZgwOCJEiMUFWh0BCIiTU2mkkEoAdzAKVyCS+MnPUmFmsSkxzzQUjaHe7sOhdjf2NTqxt9GBwzY34uP6HUXpRCIBJufpcX6JCeeXZOMcSxbOzs86bZntSCyOAy1OVDc5IZVIoJBLoZJJIZdJEIzEE+9lXyiKn14xdcB9sv6VEALNPQHsOmHHYZsHkVgckahAJBZHKBaHQS1Hnl6FvCwVzHoVrCYNirI1yNEpk062khGKxtDpDqHVGUC7K4A2ZxAd7iCc/t7X5Q5GElNZXYEIxvdfdyIi+lcXlJiw9upKnFtggGwEpndPVJwaR4MWjsZxtMOD6mYn/vuTJhxqd/fbTi6VYJrVAG8oisZuf+LqOtFYKsrWoCRHC4O6d+2bQSOHQa1Arl6FApMaBUY1CowaGNTyEU1ERoMQArVtbuxvduJAixMOfwRCCMQFEBcCsbiAwx+GzRXkOjwiIoJBLcfDy6fj27M5MtQfJkI0LEIIHO3w4kiHB8c6PPjgUOdpEyOidKZTylCRp8dUSxam5mdhqiUL5xRkIU+vGlKCFIrG0OYMotURQIvDj/puH453+nCiywubO4hYXECcTGDiQkAuk8KglkOvkkN/8r95WWpYTWoUmjSYlKXGf+9uwjZOJSUiokE6v8SEW6tKcenUfBi1yc1wyARMhGhE/enTZvzHnw+kuhtEIyZXp8Q0qwHXX1iMb55XcMoUg0gsnpj2edjmweF2N47YPGhzca8tIiJKL1IJMLPYhLnluZhdmo0LSkzIHeebkw8HEyEaMXsbe/Cd33/CPUtowpo8SY+nvj0DrkAEW450YXd9D451ehGO8T1PRETjU3GOBjOKTJhRaERFnh6luVqU5GgzYj8hJkI0Yq5ftwu7G3pS3Q0iIiIiGiaLQY3bF5Tj9gUVqe7KqGEilGKxuEC93YvSXB0UJ0vkCiFwvMuLbm8Ys0pMUMlliduPdnixr8kBVyACTzACdyAKTzACTzCKvCwV5lbkYF5FLgqMmpS8nmgsDoc/Aoc/jG5vGIfa3fjDjnq0OAIp6Q8RERERDd2UfD1ydSpk6xQwaZXI0SqRo1Ni0bmTUJqrS7QTQsAXjqHLE4JcKoHVpEn7inVMhFKorsODn75xANVNTihkElSY9ajI0+FguxuN3X4AgFYpw/yzzCg3a/Hh4U6c6PIl9diFJk2ijHChSYO8LCXM+t5yvWO5KSXQmxzZTpbtdZ5MkpyBCJy+MLyhKGJxgZjoXTgei4vE4nFXIIKNNbYx7SsRERERJeeCEhMEALs3hC5PqM/yCIWsd9/IkhwtSnO1KM3VoSxXi4o8PcrNutM/6BhiIpRCd/1xL96rHfsv+hqFDBajus8bszRHi2ydEkaNHFlqBQxqBdQK6SnVsoKRWOLN3uUJIS4AnUoG7cnNKHVKObQnf9coZElX2xJCwB2IotMTRIc7hE5PENuOduEv+9tG4xQQERERUQoUZWuw/X9dmupuABhcbjC2wwg0agKR3s1N6+0Djy4pZJKTSZEcMqkEdm/vxovJkkgAk0aB4hwtirO1KMrRoDhbi7gQaHcFYXMF0eYMwObu/f9QlAvOiYiIiCj9MBHKMJGYQI8vjB7f0DZmFAIn1wu5cKDFNcK9IyIiIiIaG9JUd4CIiIiIiGisMREiIiIiIqKMw0SIiIiIiIgyDhMhIiIiIiLKOEyEiIiIiIgo4zARIiIiIiKijMNEiIiIiIiIMg73ERph91x2Nm6pKk11N4iIiIiIxoRKPj7HVpgIjbBzCwyp7gIREREREZ3B+EzfiIiIiIiIhoGJEBERERERZRwmQkRERERElHGYCBERERERUcZhIkRERERERBmHiRAREREREWUcJkJERERERJRxmAgREREREVHGYSJEREREREQZh4kQERERERFlHCZCRERERESUcZgIERERERFRxmEiREREREREGYeJEBERERERZRx5qjswXEIIAIDb7U5xT4iIiIiIKJW+yAm+yBEGMu4TIY/HAwAoLi5OcU+IiIiIiCgdeDweGI3GAdtIRDLpUhqLx+Noa2tDVlYWJBJJqruTMdxuN4qLi9Hc3AyDwZDq7mQsxiE9MA7pgXFIPcYgPTAO6YFxSA0hBDweD6xWK6TSgVcBjfsRIalUiqKiolR3I2MZDAZ+uNMA45AeGIf0wDikHmOQHhiH9MA4jL0zjQR9gcUSiIiIiIgo4zARIiIiIiKijMNEiIZEpVJh9erVUKlUqe5KRmMc0gPjkB4Yh9RjDNID45AeGIf0N+6LJRAREREREQ0WR4SIiIiIiCjjMBEiIiIiIqKMw0SIiIiIiIgyDhMhIiIiIiLKOEyEaECPP/445s+fD61WC5PJ1G8biURyys+6dev6tKmpqcHChQuh0WhQWFiItWvXgnU6kpdMHJqamrB8+XLodDqYzWbcfffdCIfDfdowDiOvrKzslPf/fffd16dNMrGh4XnhhRdQXl4OtVqN2bNn46OPPkp1lya0NWvWnPK+t1gsieNCCKxZswZWqxUajQZf//rXUVtbm8IeTwzbtm3D8uXLYbVaIZFI8Je//KXP8WTOeygUwo9//GOYzWbodDpcddVVaGlpGcNXMb6dKQbf+973TvlszJs3r08bxiB9MBGiAYXDYVx33XX44Q9/OGC79evXo729PfGzYsWKxDG3243LL78cVqsVe/bswXPPPYenn34azzzzzGh3f8I4UxxisRiWLl0Kn8+H7du3Y8OGDXjjjTewatWqRBvGYfSsXbu2z/v/wQcfTBxLJjY0PK+99hruvfdePPDAA6iursaCBQtw5ZVXoqmpKdVdm9CmT5/e531fU1OTOPbzn/8czzzzDJ5//nns2bMHFosFl19+OTweTwp7PP75fD7MnDkTzz//fL/Hkznv9957L9566y1s2LAB27dvh9frxbJlyxCLxcbqZYxrZ4oBAFxxxRV9PhsbN27sc5wxSCOCKAnr168XRqOx32MAxFtvvXXa+77wwgvCaDSKYDCYuO2JJ54QVqtVxOPxEe7pxHa6OGzcuFFIpVLR2tqauO3VV18VKpVKuFwuIQTjMFpKS0vFL3/5y9MeTyY2NDwXXXSRuOuuu/rcds4554j77rsvRT2a+FavXi1mzpzZ77F4PC4sFot48sknE7cFg0FhNBrFunXrxqiHE99X/+1N5rw7nU6hUCjEhg0bEm1aW1uFVCoV77333pj1faLo7/vPihUrxNVXX33a+zAG6YUjQjQiVq5cCbPZjDlz5mDdunWIx+OJY7t27cLChQv7bCi2ZMkStLW1oaGhIQW9nXh27dqFyspKWK3WxG1LlixBKBTC3r17E20Yh9Hxs5/9DLm5uZg1axYef/zxPtPekokNDV04HMbevXuxePHiPrcvXrwYO3fuTFGvMkNdXR2sVivKy8tx44034sSJEwCA+vp62Gy2PjFRqVRYuHAhYzKKkjnve/fuRSQS6dPGarWisrKSsRlBW7ZswaRJkzBlyhTccccd6OzsTBxjDNKLPNUdoPHv0UcfxaJFi6DRaPDhhx9i1apVsNvtielBNpsNZWVlfe6Tn5+fOFZeXj7WXZ5wbDZb4px+ITs7G0qlEjabLdGGcRh599xzDy644AJkZ2dj9+7duP/++1FfX4/f//73AJKLDQ2d3W5HLBY75Rzn5+fz/I6iuXPn4pVXXsGUKVPQ0dGBxx57DPPnz0dtbW3ivPcXk8bGxlR0NyMkc95tNhuUSiWys7NPacPPy8i48sorcd1116G0tBT19fV46KGHcOmll2Lv3r1QqVSMQZrhiFAG6m+R61d/Pv3006Qf78EHH0RVVRVmzZqFVatWYe3atXjqqaf6tJFIJH1+FycX6H/19kwy0nHo71wKIfrczjgkZzCx+clPfoKFCxdixowZuP3227Fu3Tq89NJL6O7uTjxeMrGh4envvc3zO3quvPJKXHvttTjvvPNw2WWX4e9//zsA4OWXX060YUxSYyjnnbEZOTfccAOWLl2KyspKLF++HO+++y6OHj2a+IycDmOQGhwRykArV67EjTfeOGCbr44cDMa8efPgdrvR0dGB/Px8WCyWU65yfDFM/NUrV5lkJONgsVjwySef9LnN4XAgEokkzjHjkLzhxOaL6kDHjh1Dbm5uUrGhoTObzZDJZP2+t3l+x45Op8N5552Huro6XHPNNQB6Rx8KCgoSbRiT0fVF1b6BzrvFYkE4HIbD4egzItHZ2Yn58+ePbYczREFBAUpLS1FXVweAMUg3HBHKQGazGeecc86AP2q1esiPX11dDbVanSjzXFVVhW3btvVZN/H+++/DarUOK+Ea70YyDlVVVfj888/R3t6euO3999+HSqXC7NmzE20Yh+QMJzbV1dUAkPgikkxsaOiUSiVmz56NDz74oM/tH3zwAb9UjKFQKIRDhw6hoKAA5eXlsFgsfWISDoexdetWxmQUJXPeZ8+eDYVC0adNe3s7Pv/8c8ZmlHR3d6O5uTnxbwJjkGZSVqaBxoXGxkZRXV0tHnnkEaHX60V1dbWorq4WHo9HCCHE22+/LX7729+KmpoacezYMfG73/1OGAwGcffddycew+l0ivz8fHHTTTeJmpoa8eabbwqDwSCefvrpVL2scedMcYhGo6KyslIsWrRI7Nu3T2zatEkUFRWJlStXJh6DcRh5O3fuFM8884yorq4WJ06cEK+99pqwWq3iqquuSrRJJjY0PBs2bBAKhUK89NJL4uDBg+Lee+8VOp1ONDQ0pLprE9aqVavEli1bxIkTJ8THH38sli1bJrKyshLn/MknnxRGo1G8+eaboqamRtx0002ioKBAuN3uFPd8fPN4PIm//wASf38aGxuFEMmd97vuuksUFRWJTZs2iX379olLL71UzJw5U0Sj0VS9rHFloBh4PB6xatUqsXPnTlFfXy82b94sqqqqRGFhIWOQppgI0YBWrFghAJzys3nzZiGEEO+++66YNWuW0Ov1QqvVisrKSvHss8+KSCTS53EOHDggFixYIFQqlbBYLGLNmjUs2TwIZ4qDEL3J0tKlS4VGoxE5OTli5cqVfUplC8E4jLS9e/eKuXPnCqPRKNRqtZg6dapYvXq18Pl8fdolExsanl//+teitLRUKJVKccEFF4itW7emuksT2g033CAKCgqEQqEQVqtVfOtb3xK1tbWJ4/F4XKxevVpYLBahUqnE1772NVFTU5PCHk8Mmzdv7vffghUrVgghkjvvgUBArFy5UuTk5AiNRiOWLVsmmpqaUvBqxqeBYuD3+8XixYtFXl6eUCgUoqSkRKxYseKU88sYpA+JENxWnoiIiIiIMgvXCBERERERUcZhIkRERERERBmHiRAREREREWUcJkJERERERJRxmAgREREREVHGYSJEREREREQZh4kQERERERFlHCZCRERERESUcZgIERERERFRxmEiREREREREGYeJEBERERERZRwmQkRERERElHH+P+UtPkKJkEQjAAAAAElFTkSuQmCC\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "%matplotlib inline\n", - "\n", - "ax = gdf.plot(figsize=(10, 10))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `GeoDataFrame` contains the boundary coordinates, as well as some other data such as estimated population." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
pop_estcontinentnameiso_a3gdp_md_estgeometry
0889953.0OceaniaFijiFJI5496MULTIPOLYGON (((180.00000 -16.06713, 180.00000...
158005463.0AfricaTanzaniaTZA63177POLYGON ((33.90371 -0.95000, 34.07262 -1.05982...
2603253.0AfricaW. SaharaESH907POLYGON ((-8.66559 27.65643, -8.66512 27.58948...
337589262.0North AmericaCanadaCAN1736425MULTIPOLYGON (((-122.84000 49.00000, -122.9742...
4328239523.0North AmericaUnited States of AmericaUSA21433226MULTIPOLYGON (((-122.84000 49.00000, -120.0000...
\n", - "
" - ], - "text/plain": [ - " pop_est continent name iso_a3 gdp_md_est \\\n", - "0 889953.0 Oceania Fiji FJI 5496 \n", - "1 58005463.0 Africa Tanzania TZA 63177 \n", - "2 603253.0 Africa W. Sahara ESH 907 \n", - "3 37589262.0 North America Canada CAN 1736425 \n", - "4 328239523.0 North America United States of America USA 21433226 \n", - "\n", - " geometry \n", - "0 MULTIPOLYGON (((180.00000 -16.06713, 180.00000... \n", - "1 POLYGON ((33.90371 -0.95000, 34.07262 -1.05982... \n", - "2 POLYGON ((-8.66559 27.65643, -8.66512 27.58948... \n", - "3 MULTIPOLYGON (((-122.84000 49.00000, -122.9742... \n", - "4 MULTIPOLYGON (((-122.84000 49.00000, -120.0000... " - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "gdf.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Creating the style dictionary\n", - "Now we generate time series data for each country. \n", - "\n", - "Data for different areas might be sampled at different times, and `TimeDynamicGeoJson` can deal with that. This means that there is no need to resample the data, as long as the number of datapoints isn't too large for the browser to deal with. \n", - "\n", - "To simulate that data is sampled at different times we random sample data for `n_periods` rows of data and then pick without replacing `n_sample` of those rows. " - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Index(['1454198400', '1456704000', '1459382400', '1461974400', '1464652800',\n", - " '1467244800', '1469923200', '1472601600', '1475193600', '1477872000',\n", - " '1480464000', '1483142400', '1485820800', '1488240000', '1490918400',\n", - " '1493510400', '1496188800', '1498780800', '1501459200', '1504137600',\n", - " '1506729600', '1509408000', '1512000000', '1514678400', '1517356800',\n", - " '1519776000', '1522454400', '1525046400', '1527724800', '1530316800',\n", - " '1532995200', '1535673600', '1538265600', '1540944000', '1543536000',\n", - " '1546214400', '1548892800', '1551312000', '1553990400', '1556582400',\n", - " '1559260800', '1561852800', '1564531200', '1567209600', '1569801600',\n", - " '1572480000', '1575072000', '1577750400'],\n", - " dtype='object')" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "\n", - "n_periods, n_sample = 48, 40\n", - "\n", - "assert n_sample < n_periods\n", - "\n", - "datetime_index = pd.date_range(\"2016-1-1\", periods=n_periods, freq=\"M\")\n", - "dt_index_epochs = datetime_index.astype(int) // 10 ** 9\n", - "dt_index = dt_index_epochs.astype(\"U10\")\n", - "\n", - "dt_index" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "styledata = {}\n", - "\n", - "for country in gdf.index:\n", - " df = pd.DataFrame(\n", - " {\n", - " \"color\": np.random.normal(size=n_periods),\n", - " \"opacity\": np.random.normal(size=n_periods),\n", - " },\n", - " index=dt_index,\n", - " )\n", - " df = df.cumsum()\n", - " df.sample(n_sample, replace=False).sort_index()\n", - " styledata[country] = df" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that the geodata and random sampled data is linked through the feature_id, which is the index of the `GeoDataFrame`." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Users\\frank\\anaconda3\\envs\\folium\\lib\\site-packages\\pandas\\core\\dtypes\\inference.py:383: ShapelyDeprecationWarning: Iteration over multi-part geometries is deprecated and will be removed in Shapely 2.0. Use the `geoms` property to access the constituent parts of a multi-part geometry.\n", - " iter(obj) # Can iterate over it.\n", - "C:\\Users\\frank\\anaconda3\\envs\\folium\\lib\\site-packages\\pandas\\core\\dtypes\\inference.py:384: ShapelyDeprecationWarning: __len__ for multi-part geometries is deprecated and will be removed in Shapely 2.0. Check the length of the `geoms` property instead to get the number of parts of a multi-part geometry.\n", - " len(obj) # Has a length associated with it.\n", - "C:\\Users\\frank\\anaconda3\\envs\\folium\\lib\\site-packages\\pandas\\io\\formats\\printing.py:117: ShapelyDeprecationWarning: Iteration over multi-part geometries is deprecated and will be removed in Shapely 2.0. Use the `geoms` property to access the constituent parts of a multi-part geometry.\n", - " s = iter(seq)\n", - "C:\\Users\\frank\\anaconda3\\envs\\folium\\lib\\site-packages\\pandas\\io\\formats\\printing.py:121: ShapelyDeprecationWarning: __len__ for multi-part geometries is deprecated and will be removed in Shapely 2.0. Check the length of the `geoms` property instead to get the number of parts of a multi-part geometry.\n", - " for i in range(min(nitems, len(seq)))\n", - "C:\\Users\\frank\\anaconda3\\envs\\folium\\lib\\site-packages\\pandas\\io\\formats\\printing.py:125: ShapelyDeprecationWarning: __len__ for multi-part geometries is deprecated and will be removed in Shapely 2.0. Check the length of the `geoms` property instead to get the number of parts of a multi-part geometry.\n", - " if nitems < len(seq):\n" - ] - }, - { - "data": { - "text/plain": [ - "pop_est 889953.0\n", - "continent Oceania\n", - "name Fiji\n", - "iso_a3 FJI\n", - "gdp_md_est 5496\n", - "geometry (POLYGON ((180 -16.067132663642447, 180 -16.55...\n", - "Name: 0, dtype: object" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "gdf.loc[0]" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
coloropacity
1454198400-0.674058-0.290131
1456704000-0.501830-0.227581
14593824000.1201421.042161
1461974400-1.1165512.079087
1464652800-0.0838642.239067
\n", - "
" - ], - "text/plain": [ - " color opacity\n", - "1454198400 -0.674058 -0.290131\n", - "1456704000 -0.501830 -0.227581\n", - "1459382400 0.120142 1.042161\n", - "1461974400 -1.116551 2.079087\n", - "1464652800 -0.083864 2.239067" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "styledata.get(0).head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We see that we generated two series of data for each country; one for color and one for opacity. Let's plot them to see what they look like. " - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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vmhxjDu8/vPmzWvxb3vSpEnNjqmuruamm24iOjqaoKAgzjzzTA4fPtziWt999x0TJ04kICCA6Ohozj33XOtj77zzTovr6F+5ubkALF26lLPOOov4+HiCgoIYPXo0H3zwQYvr/Oc//2HIkCEEBAQwaNAgFixY0OKYoqIibrjhBuLj4/H392fIkCF8//33zY7xlNf/+uuvp1+/fgQEBBATE8NZZ53Frl27rI+np6dz9dVXk5qaSkBAAP369ePBBx+kpqam2Xl+/fVXpkyZQkhICPHx8dx1113U1dU1O6aj95+lS5e2+nfYdDyvv/46xx9/PBEREURERHDiiSfyxx9/tHhtPOX1t+X9f8OGDZx00kmEh4cTFRXFddddR1lZmfXxzZs3c8kll5CcnExAQABDhgzh+eefbzFeW95/fvvtN8aNG4e/vz99+/bl1VdfbXGe5557jkGDBhEQEEBycjL/93//R1VVVbNjuuP191iag33//ffavffeqy1cuFADtC+++KLV47744gtt1KhRWkJCgvbvf/+72WPTp0/Xrr32Wi07O9v6VVRU1Op5br75Zu3UU0/VAG3jxo3NHrvpppu0l156SZs7d642atSoVsdqMpm0V155RUtLS9O+/fZbrVevXtqLL75oPWbZsmWa0WjUnn/+eW3//v3asmXLtGHDhmlnn312i/Olp6driYmJ2vHHH6+dddZZzR776KOPNF9fX+3111/XduzYod1yyy1aUFCQdvDgQesxTzzxhBYSEqItXLhQ27p1q3bRRRdp8fHxWklJSas/e2sc8fqfeOKJ2nHHHaetWbNGS0tL0/7xj39oRqNR27Bhg/WYU045RRs+fLi2cuVKbeXKldrw4cO1P/3pT61e66yzzrL+HRUWFjZ77KabbtIGDRqkffXVV9r+/fu1jRs3aosWLWpxjqKiIq1v377aySef3OLvcuXKlZqPj4/22GOPaTt37tQee+wxzWQyaatXr7Ye4y6v/5VXXqmdcsopzf5tHz16tNkx8+fP1xITE7VFixZpGzZs0GbOnKmNGjVKq6ursx7z2WefaREREdorr7yi7d69W9u1a5f26aefWh+vqKhodo3s7Gxtzpw52vTp063HPProo9p9992nrVixQtu3b5/2/PPPa0ajUfv666+tx7z88staSEiI9tFHH2lpaWnahx9+qAUHBzc7prq6Whs/frx22mmnacuXL9fS09O1ZcuWaZs2bfLI1/+///2v9ttvv2kHDhzQ1q9fr51xxhlacnKy9fX/4YcftHnz5mk//fSTlpaWpn311VdabGysdvvtt1vPsXnzZs3Pz097+OGHtb1792pLly7VBg8e3OwYW95/lixZogHa7t27m4256b+FSy+9VPvPf/6jbdy4Udu5c6d21VVXaWFhYdrhw4c98vXv6P0/MzNTi4iI0ObPn6/t2rVL++OPP7QpU6Zo5513nvWYN998U7vpppu0pUuXamlpadp7772nBQQENHttNa3j95/9+/drgYGB2i233KLt2LFDe/311zVfX1/ts88+sx7z/vvva2azWfvggw+0AwcOaD/99JMWHx+v3Xrrrd3++nsqhwcizU7exgfh4cOHtcTERG3btm1anz59Wg1Ebrnllg7P//3332uDBw/Wtm/f3mogonvwwQdbDUQuueQS7fzzz29237///W8tKSlJs1gsmqZp2tNPP6317du32TEvvPCClpSU1Oy+uro6berUqdobb7yhXXnllS0CkQkTJmjz589vdt/gwYO1u+++W9M0TbNYLFqvXr20J554wvp4VVWVFhYWpr366qttvgbt6ezrHxQUpC1YsKDZfZGRkdobb7yhaZqm7dixQwOafdCvWrVKA7Rdu3Y1e97LL7+sTZ8+Xfv1119bBCI7duzQTCZTi+e05qKLLtLuu+++Vv8uL7zwQu2UU05pdt+cOXO0iy++2Ppnd3n9W/u30VRRUZHm6+urffTRR9b7MjMzNaPRqP3444+apmlabW2tlpiYaP37sEVubq7m6+vb4u/1WKeddpp21VVXWf88efJk7W9/+1uzY2655RZt6tSp1j+/8sorWt++fbWampo2z+spr39rNm/erAHavn372jzmqaee0lJTU61/vueee7Tx48c3O+aLL77Q/P39rR8strz/6IHIsQF8e+rq6rSQkBDt3Xfftd7nSa9/R+////3vf7XY2Fitvr7eet/GjRs1QNu7d2+bz/vrX/+qzZw50/pnW95/7rzzTm3w4MHN7rv++uu1SZMmWf98ww03aLNmzWp2zG233aZNmzbN+mdXvP6epNtzRCwWC3PnzuWOO+5g2LBhbR73wQcfEB0dzbBhw/jb3/5m3YlXd+TIEa699lree+89AgMDOzWW6upq/P39m90XEBDA4cOHOXjwIABTpkzh8OHDfP/992iaxpEjR/jss884/fTTmz3vkUceISYmhquvvrrFdWpqali/fj0nn3xys/tPPvlkVq5cCcCBAwfIyclpdozZbGb69OnWYxzBltd/2rRpfPzxxxQUFGCxWPjoo4+orq5mxowZAKxatYqwsDAmTpxofc6kSZMICwtrNtYdO3bwyCOPsGDBglY3Pfrmm2/o27cv3377LampqaSkpHDNNddQUFDQ7Li3336btLQ0HnzwwVbHu2rVqhav7Zw5c6xjcafXH9R0e2xsLAMHDuTaa6+1LpUArF+/ntra2mbjSEhIYPjw4dZxbNiwgczMTIxGI2PGjCE+Pp5TTz213WncBQsWEBgYyPnnn9/u2IqLi4mMjLT+ua3/I3/88Qe1tbUAfP3110yePJkbbriBuLg4hg8fzmOPPUZ9fT3gWa//scrLy3n77bdJTU1tdxdwW1+3qqoq1q9f3+4xTd9/dPrf8+zZs1myZEm7P19FRQW1tbXW8Xji69/e+391dTV+fn7N3lMCAgIAWL58eZvXPfbvyJb3n7beW9atW2f99z9t2jTWr19vXQ7bv38/33//vfUzwt1ef3fU7YHIk08+iclk4uabb27zmMsuu4wPP/yQpUuXcv/997Nw4cJm69+apjFv3jzmz5/P+PHjOz2WOXPm8Pnnn/Prr79isVjYs2ePNV8iOzsbUIHIBx98wEUXXYSfnx+9evUiPDycF1980XqeFStW8Oabb/L666+3ep38/Hzq6+uJi4trdn9cXBw5OTkA1u/tHeMItrz+H3/8MXV1dURFRWE2m7n++uv54osv6Nevn3WssbGxLZ4XGxtrHWt1dTWXXHIJTz/9NL179271Ovv37+fgwYN8+umnLFiwgHfeeYf169c3+7Dcu3cvd999Nx988AEmU+t7NObk5LT7urnT63/qqafywQcfsHjxYv71r3+xdu1aZs2aRXV1tXUcfn5+REREtDmO/fv3A/DQQw9x33338e233xIREcH06dNbBHG6t956i0svvdT6ht2azz77jLVr13LVVVdZ75szZw5vvPEG69evR9M01q1bx1tvvUVtbS35+fnW8Xz22WfU19fz/fffc9999/Gvf/2LRx99FPCs11/38ssvExwcTHBwMD/++COLFi3Cz8+v1XOmpaXx4osvMn/+fOt9eiD84YcfUl9fT2ZmJv/85z+BxvcWW95/4uPjee2111i4cCGff/45gwYNYvbs2fz+++9t/ox33303iYmJnHjiiYDnvf4dvf/PmjWLnJwcnn76aWpqaigsLOTvf/870Pi6HWvVqlV88sknXH/99db7bHn/aeu9pa6uzvrv/+KLL+Yf//gH06ZNw9fXl379+jFz5kzuvvtuwL1ef3fVrbvvrl+/nueff54NGzZgMBjaPO7aa6+13h4+fDgDBgxg/PjxbNiwgbFjx/Liiy9SUlLCPffc06XxXHvttaSlpfGnP/2J2tpaQkNDueWWW3jooYfw8fEB1G/1N998Mw888ABz5swhOzubO+64g/nz5/Pmm29SWlrK5Zdfzuuvv050dHS71zv2Z9Y0rcV9thzTWba+/vfddx+FhYX88ssvREdH8+WXX3LBBRewbNkyRowY0eo4jx3rPffcw5AhQ7j88svbvI7FYqG6upoFCxYwcOBAAN58803GjRvH7t276d+/P5deeikPP/yw9fG2OOq1debrD3DRRRdZbw8fPpzx48fTp08fvvvuu2ZvtsdqOg6LxQLAvffey3nnnQeoWaOkpCQ+/fTTZm+2oN6Ed+zY0WqSqW7p0qXMmzeP119/vdlM2f33309OTg6TJk1C0zTi4uKYN28eTz31lPX/iMViITY2ltdeew0fHx/GjRtHVlYWTz/9NA888ID1XJ70+l922WWcdNJJZGdn88wzz3DhhReyYsWKFjMYWVlZnHLKKVxwwQVcc8011vtPPvlknn76aebPn8/cuXMxm83cf//9LF++3Pq62fL+M2jQIAYNGmQ97+TJk8nIyOCZZ57hhBNOaPHzPfXUU9YP8WPH6imvf0fv/8OGDePdd9/ltttu45577sHHx4ebb76ZuLg46+vW1Pbt2znrrLN44IEHOOmkk6z3d/T+o7/urb0mTe9funQpjz76KC+//DITJ05k37593HLLLcTHx3P//fdbn+cOr7+76tYZkWXLlpGbm0vv3r0xmUyYTCYOHjzI7bffTkpKSpvPGzt2LL6+vuzduxeAxYsXs3r1asxmMyaTif79+wMwfvx4rrzySpvHYzAYePLJJykrK+PgwYPk5OQwYcIEAOt4Hn/8caZOncodd9zByJEjmTNnDi+//DJvvfUW2dnZpKWlkZ6ezhlnnGH9mRYsWMDXX3+NyWQiLS2N6OhofHx8WkS2ubm51gi4V69eAO0e01W2vP5paWm89NJLvPXWW8yePZtRo0bx4IMPMn78eP7zn/9Yx3rkyJEW58/Ly7OOdfHixXz66afW68yePRuA6Oho6xJLfHw8JpOpWZAxZMgQAA4dOkRpaSnr1q3jxhtvtJ7nkUceYfPmzZhMJhYvXmwdT3uvm7u8/q2Jj4+nT58+1n/bvXr1sv6W19Y44uPjARg6dKj1cbPZTN++fTl06FCLa7zxxhuMHj2acePGtTqG3377jTPOOINnn32WK664otljAQEBvPXWW1RUVJCens6hQ4dISUkhJCTEGnjHx8czcODAZh8CQ4YMIScnh5qaGo96/XVhYWEMGDCAE044gc8++4xdu3a1qMTKyspi5syZTJ48mddee63FuW+77TaKioo4dOgQ+fn5nHXWWQCkpqYCtr3/tGbSpEktxgvwzDPP8Nhjj/Hzzz8zcuRI6/2e+Po3dez7P8Cll15KTk4OmZmZHD16lIceeoi8vDzra6vbsWMHs2bN4tprr+W+++5rce323n+g7fcWk8lEVFQUoIL1uXPncs011zBixAjOOeccHnvsMR5//HEsFotbv/7uolsDkblz57JlyxY2bdpk/UpISOCOO+7gp59+avN527dvp7a21voG/MILL7B582brOfQywY8//tg6HWwPHx8fEhMT8fPz48MPP2Ty5MnWpYeKiooW+Q36G66maQwePJitW7c2+5nOPPNMZs6cyaZNm0hOTsbPz49x48axaNGiZudZtGgRU6ZMAdSbU69evZodU1NTw2+//WY9pqtsef0rKioAWv2Z9d/EJ0+eTHFxcbMSwTVr1lBcXGwd68KFC5v9Hb3xxhuACoZuuOEGAKZOnUpdXR1paWnW8+zZsweAPn36EBoa2uK1nT9/PoMGDWLTpk3WHJXJkye3eG1//vln61jc5fVvzdGjR8nIyLD+2x43bhy+vr7NxpGdnc22bdus49BL0nfv3m09pra2lvT0dPr06dPs/GVlZXzyySet5i6B+m3u9NNP54knnuC6665rc5y+vr4kJSXh4+PDRx99xJ/+9Cfrv5GpU6eyb98+678PUH+P8fHx+Pn5edTr3xZN05otH2RmZjJjxgzGjh3L22+/3WoOFKhgQy/H/PDDD0lOTmbs2LHNjmnv/ac1GzdubDHep59+mn/84x/8+OOPLZarPf31P/b9v6m4uDiCg4P5+OOP8ff3bzbjsX37dmbOnMmVV17Z6udCR+8/0PZ7y/jx4/H19QXa/ozQVDGIW7/+bsPR2a+lpaXaxo0brVnMzz77rLZx48ZmZUpNHVu1sW/fPu3hhx/W1q5dqx04cED77rvvtMGDB2tjxoxpVrLW1IEDB1qtmtm7d6+2ceNG7frrr9cGDhxoHVd1dbWmaZqWl5envfLKK9rOnTu1jRs3ajfffLPm7++vrVmzxnqOt99+WzOZTNrLL7+spaWlacuXL9fGjx+vTZgwoc3XoLXMcL18680339R27Nih3XrrrVpQUJCWnp5uPeaJJ57QwsLCtM8//1zbunWrdskll9hdvtXV17+mpkbr37+/dvzxx2tr1qzR9u3bpz3zzDOawWDQvvvuO+txp5xyijZy5Eht1apV2qpVq7QRI0a0Wb6raa1n/9fX12tjx47VTjjhBG3Dhg3aunXrtIkTJ2onnXRSm+dprWpmxYoVmo+Pj/bEE09oO3fu1J544ok2y3dd+fqXlpZqt99+u7Zy5UrtwIED2pIlS7TJkydriYmJza4xf/58LSkpSfvll1+0DRs2aLNmzWpRvnvLLbdoiYmJ2k8//aTt2rVLu/rqq7XY2FitoKCg2XjeeOMNzd/fv8X9mqb+TgIDA7V7/r+9uwdpnY3iAO47JG1qoxhoVFArVlAcRF2qIBU/EASh0EGhQeosRRAX7xQRFeoifuEkDg4OKi7i4KRLQdBFQ6EFFYsdVJwEBQX/73Bfi7HtpXBfDIX/Dzo9D83pCT05gZz216+c45TxeBxbW1tIJBI4PT3F8PAwFEXBzc1Nek8ymYTT6UQ4HEY8HsfBwQFUVcXs7GzB5f/q6grz8/M4OzvD7e0totEo/H4/FEXB/f09gN9TTPX19ejp6cHd3Z0pd18tLCzg4uIChmFgZmYGgiCYpkjyqT+Li4vY399HIpGAYRiYmppCUVER9vb20nsikQhEUcTu7q4plufn54LLf771f2VlBefn54jH41hdXYUkSVhaWkqvG4YBl8sFTdNMOXl4eEjvyaf+fI7vTkxMIBaLYWNjI2N8V9d1yLKM7e1tXF9f4+joCB6PB0NDQz+e/0L1vzcinxec769QKJR1//cLYTKZhM/ng6IoEEURHo8H4+PjGbPmX+VqRLq6urLG8llEHx8f0d7ejuLiYjgcDvT29pouXp+Wl5fR1NQESZJQWVkJTdNMM/rf5RpRW1tbg9vthiiKaGtrw8nJiWn94+MDuq6joqICNpsNPp8Pl5eXOY+Tzd/mHwASiQQCgQBUVYXD4UBzc3PG2OfT0xM0TYMsy5BlGZqm/XHEMNcYYiqVQiAQgNPpRHl5OUZHR/94rnONYu/s7KChoQGCIKCxsdFUqD9Znf+Xlxf09/fD5XJBEATU1NQgFAohmUya3uP19RXhcBiKokCSJAwODmbseXt7w+TkJFRVhSzL6Ovrg2EYGfF0dHQgGAxmjTUUCmWN9etvjcRiMbS0tECSJJSUlMDv92cdd4xGo/B6vbDZbKirq8Pc3FzGjUMh5D+VSmFgYACqqkIQBFRVVSEYDJo+8+bmZtZjfL+v6+7uRmlpKex2O7xeLw4PD03r+dSfSCQCj8cDu92OsrIydHZ2mm4IgN/f4Wyx6LpecPnPt/6PjIyk92SrT7quZ43D7Xab9uVTf46Pj9Ha2gpRFFFbW4v19XXT+vv7O6anp9Pnqbq6GmNjYxm17ifyX6j+Af578oaIiIjoh/G/ZoiIiMgybESIiIjIMmxEiIiIyDJsRIiIiMgybESIiIjIMmxEiIiIyDJsRIiIiMgybESIiIjIMmxEiIiIyDJsRIiIiMgybESIiIjIMmxEiIiIyDL/Amo9nuPkyb+5AAAAAElFTkSuQmCC\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins/timeslider_choropleth.html" ], - "source": [ - "ax = df.plot()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Looks random alright. We want to map the column named `color` to a hex color. To do this we use a normal colormap. To create the colormap, we calculate the maximum and minimum values over all the timeseries. We also need the max/min of the `opacity` column, so that we can map that column into a range [0,1]." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "max_color, min_color, max_opacity, min_opacity = 0, 0, 0, 0\n", - "\n", - "for country, data in styledata.items():\n", - " max_color = max(max_color, data[\"color\"].max())\n", - " min_color = min(max_color, data[\"color\"].min())\n", - " max_opacity = max(max_color, data[\"opacity\"].max())\n", - " max_opacity = min(max_color, data[\"opacity\"].max())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Define and apply maps: " - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "from branca.colormap import linear\n", - "\n", - "cmap = linear.PuRd_09.scale(min_color, max_color)\n", - "\n", - "\n", - "def norm(x):\n", - " return (x - x.min()) / (x.max() - x.min())\n", - "\n", - "\n", - "for country, data in styledata.items():\n", - " data[\"color\"] = data[\"color\"].apply(cmap)\n", - " data[\"opacity\"] = norm(data[\"opacity\"])" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
coloropacity
1454198400#ddcbe4ff0.000000
1456704000#dcc9e3ff0.007573
1459382400#d8c2dfff0.161309
1461974400#dfd0e6ff0.286857
1464652800#dac4e0ff0.306226
\n", - "
" - ], - "text/plain": [ - " color opacity\n", - "1454198400 #ddcbe4ff 0.000000\n", - "1456704000 #dcc9e3ff 0.007573\n", - "1459382400 #d8c2dfff 0.161309\n", - "1461974400 #dfd0e6ff 0.286857\n", - "1464652800 #dac4e0ff 0.306226" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "styledata.get(0).head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally we use `pd.DataFrame.to_dict()` to convert each dataframe into a dictionary, and place each of these in a map from country id to data. " - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "styledict = {\n", - " str(country): data.to_dict(orient=\"index\") for country, data in styledata.items()\n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally we can create the choropleth. I like to use the Stamen Toner tileset because its monochrome colors makes it neutral and clean looking. \n", - "\n", - "If the time slider above doesn't show up in the notebook, it's probably because the output is being cropped. Try loading the saved .html file in your browser for the fullscreen experience. " - ] - }, - { - "cell_type": "code", - "execution_count": 13, "metadata": { - "scrolled": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import folium\n", - "from folium.plugins import TimeSliderChoropleth\n", - "\n", - "\n", - "m = folium.Map([0, 0], tiles=\"Stamen Toner\", zoom_start=2)\n", - "\n", - "g = TimeSliderChoropleth(\n", - " gdf.to_json(),\n", - " styledict=styledict,\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Initial timestamp\n", - "\n", - "By default the timeslider starts at the beginning. You can also select another timestamp to begin with using the `init_timestamp` parameter. Note that it expects an index to the list of timestamps. In this example we use `-1` to select the last timestamp." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map([0, 0], tiles=\"Stamen Toner\", zoom_start=2)\n", - "\n", - "g = TimeSliderChoropleth(\n", - " gdf.to_json(),\n", - " styledict=styledict,\n", - " init_timestamp=-1,\n", - ").add_to(m)\n", - "\n", - "m" - ] + "collapsed": false + } } ], "metadata": { diff --git a/examples/VectorLayers.ipynb b/examples/VectorLayers.ipynb index b5b3cbfd1..9a2b3adf2 100644 --- a/examples/VectorLayers.ipynb +++ b/examples/VectorLayers.ipynb @@ -2,496 +2,14 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Circle and CircleMarker" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import folium\n", - "from folium.plugins.measure_control import MeasureControl\n", - "\n", - "m = folium.Map(location=[-27.5717, -48.6256], zoom_start=9)\n", - "\n", - "c = MeasureControl()\n", - "c.add_to(m)\n", - "\n", - "radius = 50\n", - "folium.CircleMarker(\n", - " location=[-27.55, -48.8],\n", - " radius=radius,\n", - " color=\"cornflowerblue\",\n", - " stroke=False,\n", - " fill=True,\n", - " fill_opacity=0.6,\n", - " opacity=1,\n", - " popup=\"{} pixels\".format(radius),\n", - " tooltip=\"I am in pixels\",\n", - ").add_to(m)\n", - "\n", - "radius = 25\n", - "folium.CircleMarker(\n", - " location=[-27.35, -48.8],\n", - " radius=radius,\n", - " color=\"black\",\n", - " weight=3,\n", - " fill=False,\n", - " fill_opacity=0.6,\n", - " opacity=1,\n", - ").add_to(m)\n", - "\n", - "radius = 10000\n", - "folium.Circle(\n", - " location=[-27.551667, -48.478889],\n", - " radius=radius,\n", - " color=\"black\",\n", - " weight=1,\n", - " fill_opacity=0.6,\n", - " opacity=1,\n", - " fill_color=\"green\",\n", - " fill=False, # gets overridden by fill_color\n", - " popup=\"{} meters\".format(radius),\n", - " tooltip=\"I am in meters\",\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### PolyLine" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Coordinates are 15 points on the great circle from Boston to\n", - "# San Francisco.\n", - "# Reference: http://williams.best.vwh.net/avform.htm#Intermediate\n", - "coordinates = [\n", - " [42.3581, -71.0636],\n", - " [42.82995815, -74.78991444],\n", - " [43.17929819, -78.56603306],\n", - " [43.40320216, -82.37774519],\n", - " [43.49975489, -86.20965845],\n", - " [43.46811941, -90.04569087],\n", - " [43.30857071, -93.86961818],\n", - " [43.02248456, -97.66563267],\n", - " [42.61228259, -101.41886832],\n", - " [42.08133868, -105.11585198],\n", - " [41.4338549, -108.74485069],\n", - " [40.67471747, -112.29609954],\n", - " [39.8093434, -115.76190821],\n", - " [38.84352776, -119.13665678],\n", - " [37.7833, -122.4167],\n", - "]\n", - "\n", - "\n", - "# Create the map and add the line\n", - "m = folium.Map(location=[41.9, -97.3], zoom_start=4)\n", - "\n", - "folium.PolyLine(\n", - " locations=coordinates,\n", - " color=\"#FF0000\",\n", - " weight=5,\n", - " tooltip=\"From Boston to San Francisco\",\n", - ").add_to(m)\n", - "\n", - "folium.PolyLine(\n", - " smooth_factor=50,\n", - " locations=coordinates,\n", - " color=\"grey\",\n", - " tooltip=\"Too much smoothing?\",\n", - " weight=5,\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Dateline" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "lon = lat = 0\n", - "zoom_start = 1\n", - "\n", - "m = folium.Map(location=[lat, lon], zoom_start=zoom_start)\n", - "\n", - "kw = {\"opacity\": 1.0, \"weight\": 6}\n", - "folium.PolyLine(\n", - " locations=[(2, 179), (2, -179)],\n", - " tooltip=\"Wrong\",\n", - " color=\"red\",\n", - " line_cap=\"round\",\n", - " **kw,\n", - ").add_to(m)\n", - "\n", - "\n", - "folium.PolyLine(\n", - " locations=[(-2, 179), (-2, 181)],\n", - " tooltip=\"Correct\",\n", - " line_cap=\"butt\",\n", - " color=\"blue\",\n", - " **kw,\n", - ").add_to(m)\n", - "\n", - "\n", - "folium.PolyLine(\n", - " locations=[(-6, -179), (-6, 179)],\n", - " line_cap=\"square\",\n", - " color=\"green\",\n", - " tooltip=\"Correct\",\n", - " **kw,\n", - ").add_to(m)\n", - "\n", - "\n", - "folium.PolyLine(\n", - " locations=[(12, -179), (12, 190)],\n", - " color=\"orange\",\n", - " tooltip=\"Artifact?\",\n", - " **kw,\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### MultiPolyline" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "lat = +38.89399\n", - "lon = -77.03659\n", - "zoom_start = 17\n", - "\n", - "m = folium.Map(location=[lat, lon], zoom_start=zoom_start)\n", - "\n", - "kw = {\"color\": \"red\", \"fill\": True, \"radius\": 20}\n", - "\n", - "folium.CircleMarker([38.89415, -77.03738], **kw).add_to(m)\n", - "folium.CircleMarker([38.89415, -77.03578], **kw).add_to(m)\n", - "\n", - "\n", - "locations = [\n", - " [\n", - " (38.893596444352134, -77.03814983367920),\n", - " (38.893379333722040, -77.03792452812195),\n", - " ],\n", - " [\n", - " (38.893379333722040, -77.03792452812195),\n", - " (38.893162222428310, -77.03761339187622),\n", - " ],\n", - " [\n", - " (38.893162222428310, -77.03761339187622),\n", - " (38.893028615148424, -77.03731298446655),\n", - " ],\n", - " [\n", - " (38.893028615148424, -77.03731298446655),\n", - " (38.892920059048464, -77.03691601753235),\n", - " ],\n", - " [\n", - " (38.892920059048464, -77.03691601753235),\n", - " (38.892903358095296, -77.03637957572937),\n", - " ],\n", - " [\n", - " (38.892903358095296, -77.03637957572937),\n", - " (38.893011914220770, -77.03592896461487),\n", - " ],\n", - " [\n", - " (38.893011914220770, -77.03592896461487),\n", - " (38.893162222428310, -77.03549981117249),\n", - " ],\n", - " [\n", - " (38.893162222428310, -77.03549981117249),\n", - " (38.893404384982480, -77.03514575958252),\n", - " ],\n", - " [\n", - " (38.893404384982480, -77.03514575958252),\n", - " (38.893596444352134, -77.03496336936950),\n", - " ],\n", - "]\n", - "\n", - "folium.PolyLine(\n", - " locations=locations,\n", - " color=\"orange\",\n", - " weight=8,\n", - " opacity=1,\n", - " smooth_factor=0,\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Rectangle" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.Map(location=[35.685, 139.76], zoom_start=15)\n", - "\n", - "kw = {\n", - " \"color\": \"blue\",\n", - " \"line_cap\": \"round\",\n", - " \"fill\": True,\n", - " \"fill_color\": \"red\",\n", - " \"weight\": 5,\n", - " \"popup\": \"Tokyo, Japan\",\n", - " \"tooltip\": \"Click me!\",\n", - "}\n", - "\n", - "folium.Rectangle(\n", - " bounds=[[35.681, 139.766], [35.691, 139.776]],\n", - " line_join=\"round\",\n", - " dash_array=\"5, 5\",\n", - " **kw,\n", - ").add_to(m)\n", - "\n", - "dx = 0.012\n", - "folium.Rectangle(\n", - " bounds=[[35.681, 139.766 - dx], [35.691, 139.776 - dx]],\n", - " line_join=\"mitter\",\n", - " dash_array=\"5, 10\",\n", - " **kw,\n", - ").add_to(m)\n", - "\n", - "\n", - "folium.Rectangle(\n", - " bounds=[[35.681, 139.766 - 2 * dx], [35.691, 139.7762 - 2 * dx]],\n", - " line_join=\"bevel\",\n", - " dash_array=\"15, 10, 5, 10, 15\",\n", - " **kw,\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Polygon" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "m = folium.Map(location=[35.67, 139.78], zoom_start=13)\n", - "\n", - "locations = [\n", - " [35.6762, 139.7795],\n", - " [35.6718, 139.7831],\n", - " [35.6767, 139.7868],\n", - " [35.6795, 139.7824],\n", - " [35.6787, 139.7791],\n", - "]\n", - "\n", - "folium.Polygon(\n", - " locations=locations,\n", - " color=\"blue\",\n", - " weight=6,\n", - " fill_color=\"red\",\n", - " fill_opacity=0.5,\n", - " fill=True,\n", - " popup=\"Tokyo, Japan\",\n", - " tooltip=\"Click me!\",\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + }, "source": [ - "locations = [\n", - " [\n", - " [7.577794326946673, 8.998503901433935],\n", - " [7.577851434795945, 8.998572430673164],\n", - " [7.577988491475764, 8.998652380403087],\n", - " [7.578105560723088, 8.998426807051544],\n", - " [7.577891409660878, 8.998289750371725],\n", - " [7.577794326946673, 8.998503901433935],\n", - " ],\n", - " [\n", - " [7.578139824893071, 8.999291979141560],\n", - " [7.578359687549607, 8.999414759083890],\n", - " [7.578456769364435, 8.999266281014116],\n", - " [7.578471046101925, 8.999197181604700],\n", - " [7.578247331649095, 8.999094883721964],\n", - " [7.578139824893071, 8.99929197914156],\n", - " ],\n", - " [\n", - " [7.577851730672876, 8.997811268775080],\n", - " [7.578012579816743, 8.997460464828633],\n", - " [7.577798113991832, 8.997311104523930],\n", - " [7.577667902951418, 8.997663440915119],\n", - " [7.577851730672876, 8.997811268775080],\n", - " ],\n", - " [\n", - " [7.578562417221803, 8.999551816663029],\n", - " [7.578688052511666, 8.999654609172921],\n", - " [7.578813688700849, 8.999443313458185],\n", - " [7.578670920426703, 8.999369073523950],\n", - " [7.578562417221803, 8.999551816663029],\n", - " ],\n", - " [\n", - " [7.577865711533433, 8.998252059784761],\n", - " [7.577989601239152, 8.998002756022402],\n", - " [7.577648754586391, 8.997784460884190],\n", - " [7.577545911714481, 8.998069316645683],\n", - " [7.577865711533433, 8.998252059784761],\n", - " ],\n", - "]\n", - "\n", - "m = folium.Map(location=[7.577798113991832, 8.997311104523930], zoom_start=16)\n", - "\n", - "folium.Polygon(\n", - " locations=locations,\n", - " smooth_factor=2,\n", - " color=\"crimson\",\n", - " no_clip=True,\n", - " tooltip=\"Hi there!\",\n", - ").add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/vector_layers.html" ] } ], diff --git a/examples/VideoOverlayLayer.ipynb b/examples/VideoOverlayLayer.ipynb index d80af9122..893c7e829 100644 --- a/examples/VideoOverlayLayer.ipynb +++ b/examples/VideoOverlayLayer.ipynb @@ -1,42 +1,15 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "import folium\n", - "\n", - "\n", - "m = folium.Map(location=[22.5, -115], zoom_start=4)\n", - "\n", - "video = folium.raster_layers.VideoOverlay(\n", - " video_url=\"https://www.mapbox.com/bites/00188/patricia_nasa.webm\",\n", - " bounds=[[32, -130], [13, -100]],\n", - " opacity=0.65,\n", - " attr=\"Video from patricia_nasa\",\n", - " autoplay=True,\n", - " loop=False,\n", - ")\n", - "\n", - "video.add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/raster_layers/video_overlay.html" ] } ], diff --git a/examples/WMS_and_WMTS.ipynb b/examples/WMS_and_WMTS.ipynb index 79cc0bb55..d792200e2 100644 --- a/examples/WMS_and_WMTS.ipynb +++ b/examples/WMS_and_WMTS.ipynb @@ -1,66 +1,15 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "import folium\n", - "\n", - "\n", - "m = folium.Map(location=[41, -70], zoom_start=5, tiles=None)\n", - "\n", - "\n", - "folium.raster_layers.TileLayer(\n", - " tiles=\"http://{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}\",\n", - " attr=\"google\",\n", - " name=\"google maps\",\n", - " max_zoom=20,\n", - " subdomains=[\"mt0\", \"mt1\", \"mt2\", \"mt3\"],\n", - " overlay=False,\n", - " control=True,\n", - ").add_to(m)\n", - "\n", - "folium.raster_layers.TileLayer(\n", - " tiles=\"http://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}\",\n", - " attr=\"google\",\n", - " name=\"google street view\",\n", - " max_zoom=20,\n", - " subdomains=[\"mt0\", \"mt1\", \"mt2\", \"mt3\"],\n", - " overlay=False,\n", - " control=True,\n", - ").add_to(m)\n", - "\n", - "\n", - "folium.raster_layers.WmsTileLayer(\n", - " url=\"http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi\",\n", - " name=\"test\",\n", - " fmt=\"image/png\",\n", - " layers=\"nexrad-n0r-900913\",\n", - " attr=u\"Weather data © 2012 IEM Nexrad\",\n", - " transparent=True,\n", - " overlay=True,\n", - " control=True,\n", - ").add_to(m)\n", - "\n", - "folium.LayerControl().add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/raster_layers/wms_tile_layer.html" ] } ], diff --git a/examples/WidthHeight.ipynb b/examples/WidthHeight.ipynb index f1cb676fd..64d12cf00 100644 --- a/examples/WidthHeight.ipynb +++ b/examples/WidthHeight.ipynb @@ -1,307 +1,15 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from branca.element import Figure\n", - "\n", - "lon, lat = -122.1889, 46.1991\n", - "\n", - "location = [lat, lon]\n", - "\n", - "zoom_start = 13\n", - "\n", - "tiles = \"OpenStreetMap\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Using same width and height triggers the scroll bar" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import folium\n", - "\n", - "\n", - "width, height = 480, 350\n", - "\n", - "fig = Figure(width=width, height=height)\n", - "\n", - "m = folium.Map(\n", - " location=location, tiles=tiles, width=width, height=height, zoom_start=zoom_start\n", - ")\n", - "\n", - "fig.add_child(m)\n", - "\n", - "fig" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Can figure take relative sizes?" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "width, height = \"100%\", 350\n", - "\n", - "fig = Figure(width=width, height=height)\n", - "\n", - "m = folium.Map(\n", - " location=location, tiles=tiles, width=width, height=height, zoom_start=zoom_start\n", - ")\n", - "\n", - "fig.add_child(m)\n", - "\n", - "fig" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# I guess not. (Well, it does make sense for a single HTML page, but not for iframes.)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "width, height = 480, \"100%\"\n", - "\n", - "fig = Figure(width=width, height=height)\n", - "\n", - "m = folium.Map(\n", - " location=location, tiles=tiles, width=width, height=height, zoom_start=zoom_start\n", - ")\n", - "\n", - "fig.add_child(m)\n", - "\n", - "fig" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Not that Figure is interpreting this as 50px. We should raise something and be explicit on the docs." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "width, height = \"50%\", \"100%\"\n", - "\n", - "fig = Figure(width=width, height=height)\n", - "\n", - "m = folium.Map(\n", - " location=location, tiles=tiles, width=width, height=height, zoom_start=zoom_start\n", - ")\n", - "\n", - "fig.add_child(m)\n", - "\n", - "fig" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Cannot parse value 150.0 as '%'\n" - ] - } - ], - "source": [ - "width, height = \"150%\", \"100%\"\n", - "\n", - "try:\n", - " folium.Map(\n", - " location=location,\n", - " tiles=tiles,\n", - " width=width,\n", - " height=height,\n", - " zoom_start=zoom_start,\n", - " )\n", - "except ValueError as e:\n", - " print(e)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Cannot parse value '80p' as '%'\n" - ] - } - ], - "source": [ - "width, height = \"50%\", \"80p\"\n", - "\n", - "try:\n", - " folium.Map(\n", - " location=location,\n", - " tiles=tiles,\n", - " width=width,\n", - " height=height,\n", - " zoom_start=zoom_start,\n", - " )\n", - "except ValueError as e:\n", - " print(e)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Cannot parse value -350.0 as 'px'\n" - ] - } - ], - "source": [ - "width, height = width, height = 480, -350\n", - "\n", - "try:\n", - " folium.Map(\n", - " location=location,\n", - " tiles=tiles,\n", - " width=width,\n", - " height=height,\n", - " zoom_start=zoom_start,\n", - " )\n", - "except ValueError as e:\n", - " print(e)" - ] - }, { "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Maybe we should recommend" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "width, height = 480, 350\n", - "\n", - "fig = Figure(width=width, height=height)\n", - "\n", - "m = folium.Map(\n", - " location=location, tiles=tiles, width=\"100%\", height=\"100%\", zoom_start=zoom_start\n", - ")\n", - "\n", - "fig.add_child(m)\n", - "\n", - "fig" + "We've updated our documentation and removed this notebook.\n", + "You can find the current documentation at https://python-visualization.github.io/folium/latest/." ] } ], diff --git a/examples/WmsTimeDimension.ipynb b/examples/WmsTimeDimension.ipynb index de5f9031c..9e1ee70b2 100644 --- a/examples/WmsTimeDimension.ipynb +++ b/examples/WmsTimeDimension.ipynb @@ -2,194 +2,14 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exploring the WMS with OWSLib" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CRW_DHW\n", - "CRW_DHW_mask\n", - "CRW_HOTSPOT\n", - "CRW_HOTSPOT_mask\n", - "CRW_SSTANOMALY\n", - "CRW_SSTANOMALY_mask\n", - "CRW_BAA\n", - "CRW_BAA_mask\n", - "CRW_BAA_7D_MAX\n", - "CRW_BAA_7D_MAX_mask\n", - "CRW_SEAICE\n", - "CRW_SST\n" - ] - } - ], - "source": [ - "from owslib.wms import WebMapService\n", - "\n", - "\n", - "url = \"https://pae-paha.pacioos.hawaii.edu/thredds/wms/dhw_5km?service=WMS\"\n", - "\n", - "web_map_services = WebMapService(url)\n", - "\n", - "print(\"\\n\".join(web_map_services.contents.keys()))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Layer metadata" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "layer = \"CRW_SST\"\n", - "wms = web_map_services.contents[layer]\n", - "\n", - "name = wms.title\n", - "\n", - "lon = (wms.boundingBox[0] + wms.boundingBox[2]) / 2.0\n", - "lat = (wms.boundingBox[1] + wms.boundingBox[3]) / 2.0\n", - "center = lat, lon\n", - "\n", - "time_interval = \"{0}/{1}\".format(\n", - " wms.timepositions[0].strip(), wms.timepositions[-1].strip()\n", - ")\n", - "style = \"boxfill/sst_36\"\n", - "\n", - "if style not in wms.styles:\n", - " style = None" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Single layer" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "import folium\n", - "from folium import plugins\n", - "\n", - "lon, lat = -50, -40\n", - "\n", - "m = folium.Map(location=[lat, lon], zoom_start=5, control_scale=True)\n", - "\n", - "w = folium.raster_layers.WmsTileLayer(\n", - " url=url,\n", - " name=name,\n", - " styles=style,\n", - " fmt=\"image/png\",\n", - " transparent=True,\n", - " layers=layer,\n", - " overlay=True,\n", - " COLORSCALERANGE=\"1.2,28\",\n", - ")\n", - "\n", - "w.add_to(m)\n", - "\n", - "time = plugins.TimestampedWmsTileLayers(w, period=\"PT1H\", time_interval=time_interval)\n", - "\n", - "time.add_to(m)\n", - "\n", - "folium.LayerControl().add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Multiple layers" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + }, "source": [ - "m = folium.Map(location=[lat, lon], zoom_start=5, control_scale=True)\n", - "\n", - "w0 = folium.raster_layers.WmsTileLayer(\n", - " url=url,\n", - " name=\"sea_surface_temperature\",\n", - " styles=style,\n", - " fmt=\"image/png\",\n", - " transparent=True,\n", - " layers=\"CRW_SST\",\n", - " overlay=True,\n", - ")\n", - "\n", - "w1 = folium.raster_layers.WmsTileLayer(\n", - " url=url,\n", - " name=\"analysed sea surface temperature anomaly\",\n", - " styles=style,\n", - " fmt=\"image/png\",\n", - " transparent=True,\n", - " layers=\"CRW_SSTANOMALY\",\n", - " overlay=True,\n", - ")\n", - "\n", - "w0.add_to(m)\n", - "w1.add_to(m)\n", - "\n", - "time = folium.plugins.TimestampedWmsTileLayers(\n", - " [w0, w1], period=\"PT1H\", time_interval=time_interval\n", - ")\n", - "\n", - "time.add_to(m)\n", - "\n", - "folium.LayerControl().add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins/WmsTimeDimension.html" ] } ], diff --git a/examples/flask_example.py b/examples/flask_example.py index 47d4273cf..9491936e8 100644 --- a/examples/flask_example.py +++ b/examples/flask_example.py @@ -1,92 +1,4 @@ -""" flask_example.py - - Required packages: - - flask - - folium - - Usage: - - Start the flask server by running: - - $ python flask_example.py - - And then head to http://127.0.0.1:5000/ in your browser to see the map displayed - """ - -from flask import Flask, render_template_string - -import folium - -app = Flask(__name__) - - -@app.route("/") -def fullscreen(): - """Simple example of a fullscreen map.""" - m = folium.Map() - return m.get_root().render() - - -@app.route("/iframe") -def iframe(): - """Embed a map as an iframe on a page.""" - m = folium.Map() - - # set the iframe width and height - m.get_root().width = "800px" - m.get_root().height = "600px" - iframe = m.get_root()._repr_html_() - - return render_template_string( - """ - - - - -

Using an iframe

- {{ iframe|safe }} - - - """, - iframe=iframe, - ) - - -@app.route("/components") -def components(): - """Extract map components and put those on a page.""" - m = folium.Map( - width=800, - height=600, - ) - - m.get_root().render() - header = m.get_root().header.render() - body_html = m.get_root().html.render() - script = m.get_root().script.render() - - return render_template_string( - """ - - - - {{ header|safe }} - - -

Using components

- {{ body_html|safe }} - - - - """, - header=header, - body_html=body_html, - script=script, - ) - - -if __name__ == "__main__": - app.run(debug=True) +We've updated our documentation. You can find the new version of this example here: +https://python-visualization.github.io/folium/latest/advanced_guide/flask.html +""" diff --git a/examples/plugin-Draw.ipynb b/examples/plugin-Draw.ipynb index f41ebb9be..5308f9653 100644 --- a/examples/plugin-Draw.ipynb +++ b/examples/plugin-Draw.ipynb @@ -1,65 +1,15 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "import folium\n", - "from folium.plugins import Draw\n", - "\n", - "\n", - "m = folium.Map()\n", - "\n", - "draw = Draw()\n", - "\n", - "draw.add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + }, "source": [ - "m = folium.Map(location=[-27.23, -48.36], zoom_start=12)\n", - "\n", - "draw = Draw(export=True)\n", - "\n", - "draw.add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins/draw.html" ] } ], diff --git a/examples/plugin-DualMap.ipynb b/examples/plugin-DualMap.ipynb index af92158b6..47d459cb7 100644 --- a/examples/plugin-DualMap.ipynb +++ b/examples/plugin-DualMap.ipynb @@ -2,168 +2,14 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, - "source": [ - "# DualMap plugin\n", - "\n", - "This plugin is using the Leaflet plugin Sync by Jieter:\n", - "https://github.com/jieter/Leaflet.Sync\n", - "\n", - "The goal is to have two maps side by side. When you pan or zoom on one map, the other will move as well." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import folium\n", - "import folium.plugins" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `DualMap` class accepts the same arguments as the normal `Map` class. Except for these: 'width', 'height', 'left', 'top', 'position'.\n", - "\n", - "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." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.plugins.DualMap(location=(52.1, 5.1), zoom_start=8)\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can access the two submaps with attributes `m1` and `m2`. You can add objects to each map specifically.\n", - "\n", - "Here we add different tile layers to each map. This way you can see two different tile sets at the same time." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m = folium.plugins.DualMap(location=(52.1, 5.1), tiles=None, zoom_start=8)\n", - "\n", - "folium.TileLayer(\"openstreetmap\").add_to(m.m1)\n", - "folium.TileLayer(\"cartodbpositron\").add_to(m.m2)\n", - "\n", - "folium.LayerControl(collapsed=False).add_to(m)\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "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." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "m = folium.plugins.DualMap(location=(52.1, 5.1), tiles=\"cartodbpositron\", zoom_start=8)\n", - "\n", - "fg_both = folium.FeatureGroup(name=\"markers_both\").add_to(m)\n", - "fg_1 = folium.FeatureGroup(name=\"markers_1\").add_to(m.m1)\n", - "fg_2 = folium.FeatureGroup(name=\"markers_2\").add_to(m.m2)\n", - "\n", - "icon_red = folium.Icon(color=\"red\")\n", - "folium.Marker((52.0, 5.0), tooltip=\"both\", icon=icon_red).add_to(fg_both)\n", - "folium.Marker((52.4, 5.0), tooltip=\"1\").add_to(fg_1)\n", - "folium.Marker((52.0, 5.4), tooltip=\"2\").add_to(fg_2)\n", - "\n", - "folium.LayerControl(collapsed=False).add_to(m)\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, you can use the `layout` argument to change the layout to vertical:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + }, "source": [ - "m = folium.plugins.DualMap(layout=\"vertical\")\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins/dual_map.html" ] } ], diff --git a/examples/plugin-GroupedLayerControl.ipynb b/examples/plugin-GroupedLayerControl.ipynb index 05c2d6dc9..0d06db9b5 100644 --- a/examples/plugin-GroupedLayerControl.ipynb +++ b/examples/plugin-GroupedLayerControl.ipynb @@ -2,377 +2,14 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, - "source": [ - "# GroupedLayerControl\n", - "\n", - "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.\n", - "\n", - "`GroupedLayerControl` takes the same arguments as `LayerControl`.\n", - "\n", - "By default groups are exclusive, meaning only one layer in a group can be active at a time." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "import folium\n", - "from folium.plugins import GroupedLayerControl\n", - "\n", - "m = folium.Map([40., 70.], zoom_start=6)\n", - "\n", - "fg1 = folium.FeatureGroup(name='g1')\n", - "fg2 = folium.FeatureGroup(name='g2')\n", - "fg3 = folium.FeatureGroup(name='g3')\n", - "folium.Marker([40, 74]).add_to(fg1)\n", - "folium.Marker([38, 72]).add_to(fg2)\n", - "folium.Marker([40, 72]).add_to(fg3)\n", - "m.add_child(fg1)\n", - "m.add_child(fg2)\n", - "m.add_child(fg3)\n", - "\n", - "folium.LayerControl(collapsed=False).add_to(m)\n", - "\n", - "GroupedLayerControl(\n", - " groups={'groups1': [fg1, fg2]},\n", - " collapsed=False,\n", - ").add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "It's also possible to have check boxes instead of radio buttons, so multiple layers within a group can be active.\n", - "\n", - "In this example the layers are not shown by default, but can all be activated." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + }, "source": [ - "m = folium.Map([40., 70.], zoom_start=6)\n", - "\n", - "fg1 = folium.FeatureGroup(name='g1', show=False)\n", - "fg2 = folium.FeatureGroup(name='g2', show=False)\n", - "fg3 = folium.FeatureGroup(name='g3')\n", - "folium.Marker([40, 74]).add_to(fg1)\n", - "folium.Marker([38, 72]).add_to(fg2)\n", - "folium.Marker([40, 72]).add_to(fg3)\n", - "m.add_child(fg1)\n", - "m.add_child(fg2)\n", - "m.add_child(fg3)\n", - "\n", - "folium.LayerControl(collapsed=False).add_to(m)\n", - "\n", - "GroupedLayerControl(\n", - " groups={'groups1': [fg1, fg2]},\n", - " exclusive_groups=False,\n", - " collapsed=False,\n", - ").add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins/grouped_layer_control.html" ] } ], diff --git a/examples/plugin-MeasureControl.ipynb b/examples/plugin-MeasureControl.ipynb index 86a9cca1c..e97ecddc4 100644 --- a/examples/plugin-MeasureControl.ipynb +++ b/examples/plugin-MeasureControl.ipynb @@ -1,34 +1,15 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "import folium\n", - "from folium.plugins import MeasureControl\n", - "\n", - "\n", - "m = folium.Map([-27.5717, -48.6256], zoom_start=10)\n", - "\n", - "m.add_child(MeasureControl())\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins/measure_control.html" ] } ], diff --git a/examples/plugin-MousePosition.ipynb b/examples/plugin-MousePosition.ipynb index a10418079..97a1fdb7d 100644 --- a/examples/plugin-MousePosition.ipynb +++ b/examples/plugin-MousePosition.ipynb @@ -1,72 +1,15 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "import folium\n", - "from folium.plugins import MousePosition\n", - "\n", - "\n", - "m = folium.Map()\n", - "\n", - "MousePosition().add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + }, "source": [ - "m = folium.Map()\n", - "\n", - "formatter = \"function(num) {return L.Util.formatNum(num, 3) + ' º ';};\"\n", - "\n", - "MousePosition(\n", - " position=\"topright\",\n", - " separator=\" | \",\n", - " empty_string=\"NaN\",\n", - " lng_first=True,\n", - " num_digits=20,\n", - " prefix=\"Coordinates:\",\n", - " lat_formatter=formatter,\n", - " lng_formatter=formatter,\n", - ").add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins/mouse_position.html" ] } ], diff --git a/examples/plugin-PolyLineOffset.ipynb b/examples/plugin-PolyLineOffset.ipynb index 977da99f1..b6321b5f0 100644 --- a/examples/plugin-PolyLineOffset.ipynb +++ b/examples/plugin-PolyLineOffset.ipynb @@ -2,266 +2,14 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Note** : The examples presented below are the copy of the ones presented on https://github.com/bbecquet/Leaflet.PolylineOffset" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Basic Demo" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- The dashed line is the \"model\", with no offset applied. \n", - "- The Red line is with a -5px offset,\n", - "- The Green line is with a 10px offset.\n", - "The three are distinct Polyline objects but uses the same coordinate array" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import folium\n", - "from folium import plugins\n", - "\n", - "\n", - "m = folium.Map(location=[58.0, -11.0], zoom_start=4, tiles=\"cartodbpositron\")\n", - "\n", - "coords = [\n", - " [58.44773, -28.65234],\n", - " [53, -23.33496],\n", - " [53, -14.32617],\n", - " [58.1707, -10.37109],\n", - " [59, -13],\n", - " [57, -15],\n", - " [57, -18],\n", - " [60, -18],\n", - " [63, -5],\n", - " [59, -7],\n", - " [58, -3],\n", - " [56, -3],\n", - " [60, -4],\n", - "]\n", - "\n", - "plugins.PolyLineOffset(\n", - " coords, weight=2, dash_array=\"5,10\", color=\"black\", opacity=1\n", - ").add_to(m)\n", - "\n", - "plugins.PolyLineOffset(coords, color=\"#f00\", opacity=1, offset=-5).add_to(m)\n", - "\n", - "plugins.PolyLineOffset(coords, color=\"#080\", opacity=1, offset=10).add_to(m)\n", - "\n", - "m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Bus Lines" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A more complex demo. \n", - "Offsets are computed automatically depending on the number of bus lines using the same segment.\n", - "Other non-offset polylines are used to achieve the white and black outline effect." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "m = folium.Map(location=[48.868, 2.365], zoom_start=15)\n", - "\n", - "geojson = {\n", - " \"type\": \"FeatureCollection\",\n", - " \"features\": [\n", - " {\n", - " \"type\": \"Feature\",\n", - " \"properties\": {\"lines\": [0, 1]},\n", - " \"geometry\": {\n", - " \"type\": \"LineString\",\n", - " \"coordinates\": [\n", - " [2.357919216156006, 48.87621773324153],\n", - " [2.357339859008789, 48.874834693731664],\n", - " [2.362983226776123, 48.86855408432749],\n", - " [2.362382411956787, 48.86796126699168],\n", - " [2.3633265495300293, 48.86735432768131],\n", - " ],\n", - " },\n", - " },\n", - " {\n", - " \"type\": \"Feature\",\n", - " \"properties\": {\"lines\": [2, 3]},\n", - " \"geometry\": {\n", - " \"type\": \"LineString\",\n", - " \"coordinates\": [\n", - " [2.351503372192383, 48.86443950493823],\n", - " [2.361609935760498, 48.866775611250205],\n", - " [2.3633265495300293, 48.86735432768131],\n", - " ],\n", - " },\n", - " },\n", - " {\n", - " \"type\": \"Feature\",\n", - " \"properties\": {\"lines\": [1, 2]},\n", - " \"geometry\": {\n", - " \"type\": \"LineString\",\n", - " \"coordinates\": [\n", - " [2.369627058506012, 48.86619159489603],\n", - " [2.3724031448364253, 48.8626397112042],\n", - " [2.3728322982788086, 48.8616233285001],\n", - " [2.372767925262451, 48.86080456075567],\n", - " ],\n", - " },\n", - " },\n", - " {\n", - " \"type\": \"Feature\",\n", - " \"properties\": {\"lines\": [0]},\n", - " \"geometry\": {\n", - " \"type\": \"LineString\",\n", - " \"coordinates\": [\n", - " [2.3647427558898926, 48.86653565369396],\n", - " [2.3647642135620117, 48.86630981023694],\n", - " [2.3666739463806152, 48.86314789481612],\n", - " [2.3673176765441895, 48.86066339254944],\n", - " ],\n", - " },\n", - " },\n", - " {\n", - " \"type\": \"Feature\",\n", - " \"properties\": {\"lines\": [0, 1, 2, 3]},\n", - " \"geometry\": {\n", - " \"type\": \"LineString\",\n", - " \"coordinates\": [\n", - " [2.3633265495300293, 48.86735432768131],\n", - " [2.3647427558898926, 48.86653565369396],\n", - " ],\n", - " },\n", - " },\n", - " {\n", - " \"type\": \"Feature\",\n", - " \"properties\": {\"lines\": [1, 2, 3]},\n", - " \"geometry\": {\n", - " \"type\": \"LineString\",\n", - " \"coordinates\": [\n", - " [2.3647427558898926, 48.86653565369396],\n", - " [2.3650002479553223, 48.86660622956524],\n", - " [2.365509867668152, 48.866987337550164],\n", - " [2.369627058506012, 48.86619159489603],\n", - " ],\n", - " },\n", - " },\n", - " {\n", - " \"type\": \"Feature\",\n", - " \"properties\": {\"lines\": [3]},\n", - " \"geometry\": {\n", - " \"type\": \"LineString\",\n", - " \"coordinates\": [\n", - " [2.369627058506012, 48.86619159489603],\n", - " [2.372349500656128, 48.865702850895744],\n", - " ],\n", - " },\n", - " },\n", - " ],\n", - "}\n", - "\n", - "# manage overlays in groups to ease superposition order\n", - "outlines = folium.FeatureGroup(\"outlines\")\n", - "line_bg = folium.FeatureGroup(\"lineBg\")\n", - "bus_lines = folium.FeatureGroup(\"busLines\")\n", - "bus_stops = folium.FeatureGroup(\"busStops\")\n", - "\n", - "line_weight = 6\n", - "line_colors = [\"red\", \"#08f\", \"#0c0\", \"#f80\"]\n", - "stops = []\n", - "for line_segment in geojson[\"features\"]:\n", - " # Get every bus line coordinates\n", - " segment_coords = [[x[1], x[0]] for x in line_segment[\"geometry\"][\"coordinates\"]]\n", - " # Get bus stops coordinates\n", - " stops.append(segment_coords[0])\n", - " stops.append(segment_coords[-1])\n", - " # Get number of bus lines sharing the same coordinates\n", - " lines_on_segment = line_segment[\"properties\"][\"lines\"]\n", - " # Width of segment proportional to the number of bus lines\n", - " segment_width = len(lines_on_segment) * (line_weight + 1)\n", - " # For the white and black outline effect\n", - " folium.PolyLine(\n", - " segment_coords, color=\"#000\", weight=segment_width + 5, opacity=1\n", - " ).add_to(outlines)\n", - " folium.PolyLine(\n", - " segment_coords, color=\"#fff\", weight=segment_width + 3, opacity=1\n", - " ).add_to(line_bg)\n", - " # Draw parallel bus lines with different color and offset\n", - " for j, line_number in enumerate(lines_on_segment):\n", - " plugins.PolyLineOffset(\n", - " segment_coords,\n", - " color=line_colors[line_number],\n", - " weight=line_weight,\n", - " opacity=1,\n", - " offset=j * (line_weight + 1) - (segment_width / 2) + ((line_weight + 1) / 2),\n", - " ).add_to(bus_lines)\n", - "\n", - "# Draw bus stops\n", - "for stop in stops:\n", - " folium.CircleMarker(\n", - " stop,\n", - " color=\"#000\",\n", - " fill_color=\"#ccc\",\n", - " fill_opacity=1,\n", - " radius=10,\n", - " weight=4,\n", - " opacity=1,\n", - " ).add_to(bus_stops)\n", - "\n", - "outlines.add_to(m)\n", - "line_bg.add_to(m)\n", - "bus_lines.add_to(m)\n", - "bus_stops.add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins/polyline_offset.html" ] } ], diff --git a/examples/plugin-Search.ipynb b/examples/plugin-Search.ipynb index a334d445e..29b285acf 100644 --- a/examples/plugin-Search.ipynb +++ b/examples/plugin-Search.ipynb @@ -2,902 +2,14 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's get some JSON data from the web - both a point layer and a polygon GeoJson dataset with some population data." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "import geopandas\n", - "\n", - "\n", - "states = geopandas.read_file(\n", - " \"https://raw.githubusercontent.com/PublicaMundi/MappingAPI/master/data/geojson/us-states.json\",\n", - " driver=\"GeoJSON\",\n", - ")\n", - "\n", - "cities = geopandas.read_file(\n", - " \"https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_populated_places_simple.geojson\",\n", - " driver=\"GeoJSON\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And take a look at what our data looks like:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
density
count52.000000
mean402.504404
std1395.100812
min1.264000
25%53.440000
50%100.335000
75%234.050000
max10065.000000
\n", - "
" - ], - "text/plain": [ - " density\n", - "count 52.000000\n", - "mean 402.504404\n", - "std 1395.100812\n", - "min 1.264000\n", - "25% 53.440000\n", - "50% 100.335000\n", - "75% 234.050000\n", - "max 10065.000000" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], - "source": [ - "states.describe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Look how far the minimum and maximum values for the density are from the top and bottom quartile breakpoints! We have some outliers in our data that are well outside the meat of most of the distribution. Let's look into this to find the culprits within the sample." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
namedensity
8District of Columbia10065.000
30New Jersey1189.000
51Puerto Rico1082.000
39Rhode Island1006.000
21Massachusetts840.200
1Alaska1.264
50Wyoming5.851
26Montana6.858
34North Dakota9.916
31New Mexico17.160
\n", - "
" - ], - "text/plain": [ - " name density\n", - "8 District of Columbia 10065.000\n", - "30 New Jersey 1189.000\n", - "51 Puerto Rico 1082.000\n", - "39 Rhode Island 1006.000\n", - "21 Massachusetts 840.200\n", - "1 Alaska 1.264\n", - "50 Wyoming 5.851\n", - "26 Montana 6.858\n", - "34 North Dakota 9.916\n", - "31 New Mexico 17.160" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "\n", - "states_sorted = states.sort_values(by=\"density\", ascending=False)\n", - "\n", - "pd.concat([\n", - " states_sorted.nlargest(5, 'density')[['name', 'density']],\n", - " states_sorted.nsmallest(5, 'density')[['name', 'density']]\n", - "])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Looks like Washington D.C. and Alaska were the culprits on each end of the range. Washington was more dense than the next most dense state, New Jersey, than the least dense state, Alaska was from Wyoming, however. Washington D.C. has a has a relatively small land area for the amount of people that live there, so it makes sense that it's pretty dense. And Alaska has a lot of land area, but not much of it is habitable for humans.\n", - "

\n", - "However, we're looking at all of the states in the US to look at things on a more regional level. That high figure at the top of our range for Washington D.C. will really hinder the ability for us to differentiate between the other states, so let's account for that in the min and max values for our color scale, by getting the quantile values close to the end of the range. Anything higher or lower than those values will just fall into the 'highest' and 'lowest' bins for coloring." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "minimum: 8.54\n", - "\n", - "maximum: 1040.2\n", - "\n", - "Mean: 402.5\n" - ] - } - ], - "source": [ - "def rd2(x):\n", - " return round(x, 2)\n", - "\n", - "\n", - "minimum, maximum = states[\"density\"].quantile([0.05, 0.95]).apply(rd2)\n", - "\n", - "mean = round(states[\"density\"].mean(), 2)\n", - "\n", - "\n", - "print(f\"minimum: {minimum}\", f\"maximum: {maximum}\", f\"Mean: {mean}\", sep=\"\\n\\n\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This looks better. Our min and max values for the colorscale are much closer to the mean value now. Let's run with these values, and make a colorscale. I'm just going to use a sequential light-to-dark color palette from the [ColorBrewer](https://colorbrewer2.org/#type=sequential&scheme=Purples&n=5)." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "8.54180.5352.4524.4696.3868.31040.2Population Density in the United States" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import branca\n", - "\n", - "\n", - "colormap = branca.colormap.LinearColormap(\n", - " colors=[\"#f2f0f7\", \"#cbc9e2\", \"#9e9ac8\", \"#756bb1\", \"#54278f\"],\n", - " index=states[\"density\"].quantile([0.2, 0.4, 0.6, 0.8]),\n", - " vmin=minimum,\n", - " vmax=maximum,\n", - ")\n", - "\n", - "colormap.caption = \"Population Density in the United States\"\n", - "\n", - "colormap" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's narrow down these cities to United states cities, by using GeoPandas' spatial join functionality between two GeoDataFrame objects, using the Point 'within' Polygon functionality." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "us_cities = geopandas.sjoin(cities, states, how=\"inner\", predicate=\"within\")\n", - "\n", - "pop_ranked_cities = us_cities.sort_values(by=\"pop_max\", ascending=False)[\n", - " [\"nameascii\", \"pop_max\", \"geometry\"]\n", - "].iloc[:20]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ok, now we have a new GeoDataFrame with our top 20 populated cities. Let's see the top 5." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nameasciipop_maxgeometry
1224New York19040000POINT (-73.98196 40.75192)
1222Los Angeles12500000POINT (-118.18193 33.99192)
1186Chicago8990000POINT (-87.75200 41.83194)
1184Miami5585000POINT (-80.22605 25.78956)
1076Philadelphia5492000POINT (-75.17194 40.00192)
\n", - "
" - ], - "text/plain": [ - " nameascii pop_max geometry\n", - "1224 New York 19040000 POINT (-73.98196 40.75192)\n", - "1222 Los Angeles 12500000 POINT (-118.18193 33.99192)\n", - "1186 Chicago 8990000 POINT (-87.75200 41.83194)\n", - "1184 Miami 5585000 POINT (-80.22605 25.78956)\n", - "1076 Philadelphia 5492000 POINT (-75.17194 40.00192)" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pop_ranked_cities.head(5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Alright, let's build a map!" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], + }, "source": [ - "import folium\n", - "from folium.plugins import Search\n", - "\n", - "\n", - "m = folium.Map(location=[38, -97], zoom_start=4)\n", - "\n", - "\n", - "def style_function(x):\n", - " return {\n", - " \"fillColor\": colormap(x[\"properties\"][\"density\"]),\n", - " \"color\": \"black\",\n", - " \"weight\": 2,\n", - " \"fillOpacity\": 0.5,\n", - " }\n", - "\n", - "\n", - "stategeo = folium.GeoJson(\n", - " states,\n", - " name=\"US States\",\n", - " style_function=style_function,\n", - " tooltip=folium.GeoJsonTooltip(\n", - " fields=[\"name\", \"density\"], aliases=[\"State\", \"Density\"], localize=True\n", - " ),\n", - ").add_to(m)\n", - "\n", - "citygeo = folium.GeoJson(\n", - " pop_ranked_cities,\n", - " name=\"US Cities\",\n", - " tooltip=folium.GeoJsonTooltip(\n", - " fields=[\"nameascii\", \"pop_max\"], aliases=[\"\", \"Population Max\"], localize=True\n", - " ),\n", - ").add_to(m)\n", - "\n", - "statesearch = Search(\n", - " layer=stategeo,\n", - " geom_type=\"Polygon\",\n", - " placeholder=\"Search for a US State\",\n", - " collapsed=False,\n", - " search_label=\"name\",\n", - " weight=3,\n", - ").add_to(m)\n", - "\n", - "citysearch = Search(\n", - " layer=citygeo,\n", - " geom_type=\"Point\",\n", - " placeholder=\"Search for a US City\",\n", - " collapsed=True,\n", - " search_label=\"nameascii\",\n", - ").add_to(m)\n", - "\n", - "folium.LayerControl().add_to(m)\n", - "colormap.add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins/search.html" ] } ], diff --git a/examples/plugin-patterns.ipynb b/examples/plugin-patterns.ipynb index 234fc4907..86877cbb3 100644 --- a/examples/plugin-patterns.ipynb +++ b/examples/plugin-patterns.ipynb @@ -2,70 +2,14 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Preleminary demo of the pattern plugin for Folium" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "import folium\n", - "from folium import plugins\n", - "\n", - "\n", - "m = folium.Map([40.0, -105.0], zoom_start=6)\n", - "\n", - "url = \"https://raw.githubusercontent.com/python-visualization/folium/main/examples/data/us-states.json\"\n", - "stripes = plugins.pattern.StripePattern(angle=-45)\n", - "stripes.add_to(m)\n", - "\n", - "circles = plugins.pattern.CirclePattern(\n", - " width=20, height=20, radius=5, fill_opacity=0.5, opacity=1\n", - ")\n", - "circles.add_to(m)\n", - "\n", - "\n", - "def style_function(feature):\n", - " default_style = {\n", - " \"opacity\": 1.0,\n", - " \"fillColor\": \"#ffff00\",\n", - " \"color\": \"black\",\n", - " \"weight\": 2,\n", - " }\n", - "\n", - " if feature[\"properties\"][\"name\"] == \"Colorado\":\n", - " default_style[\"fillPattern\"] = stripes\n", - " default_style[\"fillOpacity\"] = 1.0\n", - "\n", - " if feature[\"properties\"][\"name\"] == \"Utah\":\n", - " default_style[\"fillPattern\"] = circles\n", - " default_style[\"fillOpacity\"] = 1.0\n", - "\n", - " return default_style\n", - "\n", - "\n", - "# Adding remote GeoJSON as additional layer.\n", - "folium.GeoJson(url, smooth_factor=0.5, style_function=style_function).add_to(m)\n", - "\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins/pattern.html" ] } ], diff --git a/examples/plugin-vector-tiles.ipynb b/examples/plugin-vector-tiles.ipynb index 6c5a90983..eea505311 100644 --- a/examples/plugin-vector-tiles.ipynb +++ b/examples/plugin-vector-tiles.ipynb @@ -1,198 +1,16 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 81, + "cell_type": "markdown", "id": "09534296", - "metadata": {}, - "outputs": [], - "source": [ - "from folium.plugins import VectorGridProtobuf\n", - "import folium" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "c044c77f", - "metadata": {}, - "outputs": [], - "source": [ - "styles = {\n", - " \"water\": {\n", - " \"fill\": True,\n", - " \"weight\": 1,\n", - " \"fillColor\": \"#06cccc\",\n", - " \"color\": \"#06cccc\",\n", - " \"fillOpacity\": 0.2,\n", - " \"opacity\": 0.4\n", - " },\n", - " \"admin\": {\n", - " \"weight\": 1,\n", - " \"fillColor\": \"pink\",\n", - " \"color\": \"pink\",\n", - " \"fillOpacity\": 0.2,\n", - " \"opacity\": 0.4\n", - " },\n", - " \"waterway\": {\n", - " \"weight\": 1,\n", - " \"fillColor\": \"#2375e0\",\n", - " \"color\": \"#2375e0\",\n", - " \"fillOpacity\": 0.2,\n", - " \"opacity\": 0.4\n", - " },\n", - " \"landcover\": {\n", - " \"fill\": True,\n", - " \"weight\": 1,\n", - " \"fillColor\": \"#53e033\",\n", - " \"color\": \"#53e033\",\n", - " \"fillOpacity\": 0.2,\n", - " \"opacity\": 0.4\n", - " },\n", - " \"landuse\": {\n", - " \"fill\": True,\n", - " \"weight\": 1,\n", - " \"fillColor\": \"#e5b404\",\n", - " \"color\": \"#e5b404\",\n", - " \"fillOpacity\": 0.2,\n", - " \"opacity\": 0.4\n", - " },\n", - " \"park\": {\n", - " \"fill\": True,\n", - " \"weight\": 1,\n", - " \"fillColor\": \"#84ea5b\",\n", - " \"color\": \"#84ea5b\",\n", - " \"fillOpacity\": 0.2,\n", - " \"opacity\": 0.4\n", - " },\n", - " \"boundary\": {\n", - " \"weight\": 1,\n", - " \"fillColor\": \"#c545d3\",\n", - " \"color\": \"#c545d3\",\n", - " \"fillOpacity\": 0.2,\n", - " \"opacity\": 0.4\n", - " },\n", - " \"aeroway\": {\n", - " \"weight\": 1,\n", - " \"fillColor\": \"#51aeb5\",\n", - " \"color\": \"#51aeb5\",\n", - " \"fillOpacity\": 0.2,\n", - " \"opacity\": 0.4\n", - " },\n", - " \"building\": {\n", - " \"fill\": True,\n", - " \"weight\": 1,\n", - " \"fillColor\": \"#2b2b2b\",\n", - " \"color\": \"#2b2b2b\",\n", - " \"fillOpacity\": 0.2,\n", - " \"opacity\": 0.4\n", - " },\n", - " \"water_name\": {\n", - " \"weight\": 1,\n", - " \"fillColor\": \"#022c5b\",\n", - " \"color\": \"#022c5b\",\n", - " \"fillOpacity\": 0.2,\n", - " \"opacity\": 0.4\n", - " },\n", - " \"transportation_name\": {\n", - " \"weight\": 1,\n", - " \"fillColor\": \"#bc6b38\",\n", - " \"color\": \"#bc6b38\",\n", - " \"fillOpacity\": 0.2,\n", - " \"opacity\": 0.4\n", - " },\n", - " \"place\": {\n", - " \"weight\": 1,\n", - " \"fillColor\": \"#f20e93\",\n", - " \"color\": \"#f20e93\",\n", - " \"fillOpacity\": 0.2,\n", - " \"opacity\": 0.4\n", - " },\n", - " \"housenumber\": {\n", - " \"weight\": 1,\n", - " \"fillColor\": \"#ef4c8b\",\n", - " \"color\": \"#ef4c8b\",\n", - " \"fillOpacity\": 0.2,\n", - " \"opacity\": 0.4\n", - " },\n", - " \"poi\": {\n", - " \"weight\": 1,\n", - " \"fillColor\": \"#3bb50a\",\n", - " \"color\": \"#3bb50a\",\n", - " \"fillOpacity\": 0.2,\n", - " \"opacity\": 0.4\n", - " },\n", - " \"road\": {\n", - " \"weight\": 1,\n", - " \"fillColor\": \"#f2b648\",\n", - " \"color\": \"#f2b648\",\n", - " \"fillOpacity\": 0.2,\n", - " \"opacity\": 0.4\n", - " },\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": 92, - "id": "725693fc", - "metadata": {}, - "outputs": [], - "source": [ - "vectorTileLayerStyles = {}\n", - "vectorTileLayerStyles[\"aerodrome_label\"] = []\n", - "vectorTileLayerStyles[\"aeroway\"] = []\n", - "vectorTileLayerStyles[\"area_name\"] = []\n", - "vectorTileLayerStyles[\"boundary\"] = styles[\"admin\"]\n", - "vectorTileLayerStyles[\"building\"] = []\n", - "vectorTileLayerStyles[\"building_ln\"] = []\n", - "vectorTileLayerStyles[\"construct\"] = []\n", - "vectorTileLayerStyles[\"contour_line\"] = []\n", - "vectorTileLayerStyles[\"landcover\"] = styles[\"landcover\"]\n", - "vectorTileLayerStyles[\"landuse\"] = styles[\"landuse\"]\n", - "vectorTileLayerStyles[\"mountain_peak\"] = []\n", - "vectorTileLayerStyles[\"park\"] = styles[\"park\"]\n", - "vectorTileLayerStyles[\"place\"] = []\n", - "vectorTileLayerStyles[\"poi\"] = []\n", - "vectorTileLayerStyles[\"spot_elevation\"] = []\n", - "vectorTileLayerStyles[\"transportation\"] = styles[\"road\"]\n", - "vectorTileLayerStyles[\"transportation_name\"] = []\n", - "vectorTileLayerStyles[\"water\"] = styles[\"water\"]\n", - "vectorTileLayerStyles[\"waterway\"] = styles[\"water\"]\n", - "vectorTileLayerStyles[\"water_name\"] = []" - ] - }, - { - "cell_type": "code", - "execution_count": 97, - "id": "49c9bf7a", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 97, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "url = \"https://vectortiles3.geo.admin.ch/tiles/ch.swisstopo.leichte-basiskarte.vt/v1.0.0/{z}/{x}/{y}.pbf\"\n", - "m = folium.Map(tiles=None, location=[46.8, 8.2], zoom_start=14)\n", - "\n", - "options = {\n", - " \"vectorTileLayerStyles\": vectorTileLayerStyles\n", - "}\n", - "\n", - "vc = VectorGridProtobuf(url, \"folium_layer_name\", options)\n", - "m.add_child(vc)\n", - "m" + "We've updated our documentation. You can find the new version of this notebook here:\n", + "https://python-visualization.github.io/folium/latest/user_guide/plugins/vector_tiles.html" ] } ],