diff --git a/examples/HereMapsApiExplorer_no_creds.ipynb b/examples/HereMapsApiExplorer_no_creds.ipynb new file mode 100644 index 0000000000..841aa94f1c --- /dev/null +++ b/examples/HereMapsApiExplorer_no_creds.ipynb @@ -0,0 +1,742 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# HERE Map Tiles Rest API Explorer" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "This notebook is intended to show how to access map tiles from [HERE Technologies](https://here.com) using their [RESTful Map Tile API](https://developer.here.com/documentation/map-tile/topics/quick-start.html) and build a variety of maps using [Folium](https://github.com/python-visualization/folium), a high-level library for creating web maps with [Leaflet](https://leafletjs.com).\n", + "\n", + "Folium supports already a number of map tiles providers, including OpenStreetMap or Mapbox (the latter needing an API_KEY), but not yet those made by HERE. To see such HERE map tiles and maps inside this [Jupyter](http://jupyter.org) notebook you will need to [register for a free HERE account](https://developer.here.com). You can chose a 90-day free trial or a free public \"BASIC\" plan with [standard features](https://developer.here.com/plans#standard_features) (see [more about plans](https://developer.here.com/plans?basicPlanOverlay)). And then you can obtain an APP_CODE and APP_ID for accessing HERE maps.\n", + "\n", + "Running this notebook also requires to have pip-installed the external packages named `requests`, `folium`, and `ipywidgets` (Python 3 is recommended, but 2 should also work). The APP_CODE and APP_ID values are assumed to be set as environment variables named `c` and `HEREMAPS_APP_ID`, respectively. These will be included in the HTML maps created with Folium/Leaflet, so be careful where you share your results!\n", + "\n", + "**N.B.** When writing this notebook it appeared that you can get HERE map tiles even with fake APP_CODE and APP_ID like `foo` and `bar` (as stored inside some cells in this notebook), but it is unpredictable to say which ones you will get or not. This is likely a way for HERE to show *something* even without credentials, while making the result not really useful, instead of limiting zoom levels or using watermarks (which might be a costly thing when serving many map tiles). Anyway, you can have a free account, see above.\n", + "\n", + "You will see the output best if you run the notebook locally with proper HERE credentials. But if you read it [on the Jupyter Notebook viewer](http://nbviewer.jupyter.org/github/deeplook/notebooks/blob/master/mapping/here_maps_api_explorer_no_creds.ipynb) or [on GitHub](https://github.com/deeplook/notebooks/blob/master/mapping/here_maps_api_explorer_no_creds.ipynb), or if you don't have real HERE credentials you might actually see no output for some cells. In these cases there is a comment to explain and a static screenshot is provided, too.\n", + "\n", + "Finally, it is assumed that you have a little experience with Jupyter notebooks, so not all steps are explained in detail. That was long intro, so now let's start playing a bit with map tiles and build maps! " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Testing your environment" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, run a little test to see if you are ready to go. Make sure you address any import or assertion error appearing in the next cell (by pip-installing the missing packages or adding the missing environment variables). Then move on!" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "You are ready to go!\n" + ] + } + ], + "source": [ + "import os\n", + "msg = \"Error: Environment variable {} not found\"\n", + "for varname in [\"HEREMAPS_APP_ID\", \"HEREMAPS_APP_CODE\"]:\n", + " assert os.getenv(varname), msg.format(varname)\n", + "\n", + "import folium\n", + "import requests\n", + "import ipywidgets\n", + "\n", + "print(\"You are ready to go!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Getting single HERE map tiles\n", + "\n", + "Web maps are composed of individual so-called map tiles, traditionally small precomputed bitmaps (although the industry is moving into using so-called map vector tiles, which is not a topic in this notebook, though). Now, lets see how to get a single map tile using the HERE REST API and your credentials. The URL contains quite a few parameters describing which tile exactly to download, but more about that later:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import os\n", + "from IPython.display import Image\n", + "\n", + "# load HERE API credentials, get your own from http://developer.here.com\n", + "app_id, app_code = map(os.getenv, [\"HEREMAPS_APP_ID\", \"HEREMAPS_APP_CODE\"])\n", + "\n", + "# then get and display a specific map tile\n", + "url = \"https://1.base.maps.api.here.com/maptile/2.1/maptile/newest/normal.day/13/4400/2686/256/png8?lg=eng&app_id=%s&app_code=%s\" % (app_id, app_code)\n", + "Image(url=url)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Static version\n", + "\n", + "If you don't see the tile image in the section above it's likely because you read this notebook on GitHub or on the Jupyter NoteBook Viewer. Subsequent sections will include static versrions included inside this notebook. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Inspecting HTTP response header\n", + "\n", + "Have a look at the HTTP response headers, too! Here it's all fine." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "200\n" + ] + }, + { + "data": { + "text/plain": [ + "{'Access-Control-Allow-Origin': '*',\n", + " 'Cache-Control': 'public, max-age=63327',\n", + " 'Connection': 'keep-alive',\n", + " 'Content-Length': '31354',\n", + " 'Content-Type': 'image/png',\n", + " 'Date': 'Sun, 20 Aug 2017 14:13:36 GMT',\n", + " 'ETag': 'afd6f70912',\n", + " 'Last-Modified': 'Fri, 21 Jul 2017 00:00:00 GMT',\n", + " 'Server': 'Apache',\n", + " 'X-NLP-IRT': 'D=72183',\n", + " 'X-Served-By': 'i-0cf8d7c9e85afbe31.eu-west-1a'}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import requests\n", + "\n", + "resp = requests.get(url)\n", + "print(resp.status_code)\n", + "dict(resp.headers.items())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Getting specific map tiles\n", + "\n", + "Normally you want to get a map tile that contains a specific geographic position at some zoom level. Depending on this zoom level a map of the entire world is composed of a varying number of tiles with x- and y-positions on a rectangular grid. You can use two simple functions to convert between these two domains, geographic coordinates on a sphere and the respective tile positions on a rectangular grid (including zoom level):" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Conversion between lat/lon in degrees (and zoom) to x/y/zoom as used in tile sets,\n", + "# from http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Python\n", + "\n", + "from math import radians, degrees, log, cos, tan, pi, atan, sinh\n", + "\n", + "def deg2tile(lat_deg, lon_deg, zoom):\n", + " lat_rad = radians(lat_deg)\n", + " n = 2.0 ** zoom\n", + " xtile = int((lon_deg + 180.0) / 360.0 * n)\n", + " ytile = int((1.0 - log(tan(lat_rad) + (1 / cos(lat_rad))) / pi) / 2.0 * n)\n", + " return (xtile, ytile)\n", + "\n", + "def tile2deg(xtile, ytile, zoom):\n", + " n = 2.0 ** zoom\n", + " lon_deg = xtile / n * 360.0 - 180.0\n", + " lat_rad = atan(sinh(pi * (1 - 2 * ytile / n)))\n", + " lat_deg = degrees(lat_rad)\n", + " return (lat_deg, lon_deg)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's make a round-trip test with a the latitude and longitude of a geographic point somewhere in the middle of Berlin, Germany (taken from the respective [Wikipedia page](https://en.wikipedia.org/wiki/Berlin)):" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(8802, 5373)" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "deg2tile(52.518611, 13.408333, 14)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(52.522905940278065, 13.4033203125)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tile2deg(8802, 5373, 14)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(8802, 5373)" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "deg2tile(52.522905940278065, 13.4033203125, 14)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And now let's get the map tile containing this geographic point (52.518611, 13.408333) somewhere inside, at level zoom 14: " + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "url = \"https://1.base.maps.api.here.com/maptile/2.1/maptile/newest/normal.day/14/8802/5373/256/png8?lg=eng&app_id=%s&app_code=%s\" % (app_id, app_code)\n", + "Image(url=url)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Adding an interactive interface\n", + "\n", + "You can make this easier to explore by using a few little widgets as an interactive interface for some of these parameters. Here we take only latitude, longitude, zoom level and only two scheme names (the [API documentation](https://developer.here.com/documentation/map-tile/topics/resource-base-basetile.html) lists many more!)." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "af3d4d0c410c429ab7f7248bb04c05dc" + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from ipywidgets import interact\n", + "\n", + "schemes = [\"normal.day\", \"normal.night\"]\n", + "\n", + "@interact(lat=(-90., 90.), lon=(-180., 180.), zoom=(0, 18), scheme=schemes, show_url=False)\n", + "def get_here_maptile(lat=52.518611, lon=13.408333, zoom=11, scheme=\"normal.day\", show_url=False):\n", + " x, y = deg2tile(lat, lon, zoom)\n", + " params = dict(x=x, y=y, zoom=zoom, scheme=scheme, app_id=app_id, app_code=app_code)\n", + " url = \"https://1.base.maps.api.here.com/maptile/2.1/maptile/newest/{scheme}/{zoom}/{x}/{y}/256/png8?lg=eng&app_id={app_id}&app_code={app_code}\".format(**params)\n", + " if show_url:\n", + " print(url)\n", + " return Image(url=url)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Static version\n", + "\n", + "If you don't see the widgets and/or image output in the section above it's likely because you read this notebook on GitHub or on the Jupyter NoteBook Viewer and/or you don't have valid HERE credentials. In this case, this is a static sample image of what you see when running the notebook locally with valid HERE credentials: \n", + "\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Building entire maps\n", + "\n", + "Of course, the whole purpose of map tiles is to build entire maps from a bunch of them, like those you know from [HERE](https://wego.here.com) or [OpenStreetMap](http://www.openstreetmap.org). All the magic of map tile selection and assembly happens in the background if you use the right tool, like Leaflet and the excellent Folium interface to it. Effectively, using Folium you can do it in one line of code (the default map tiles are set to `tiles=\"OpenStreetMap\"`, but you can change that):" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import folium; folium.Map(location=(52.518611, 13.408333), zoom_start=14)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Any such map output can be saved as a self-contained HTML file (without the map tiles, of course) and easily passed on to somebody else. (This other person might have to use her own credentials, if needed, though.):" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import folium\n", + "m = folium.Map(location=(52.518611, 13.408333), zoom_start=14)\n", + "m.save(\"mymap.html\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Making it interactive" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "One nice feature of Folium is that you can chose between a number of predefined tile sets by using the `tiles` parameter for `folium.Map`, so we can easily switch between those in a more interactive way, too. In addition, the following snippet lets you also change latitude, longitude and zoom level interactively:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "0251bbe7936740c59778594f1dfa7a16" + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import folium\n", + "from ipywidgets import interact\n", + "\n", + "# Cloudmade Mapbox needs an API key, Mapbox Control Room is limited to a few levels\n", + "tiles = [name.strip() for name in \"\"\"\n", + " OpenStreetMap\n", + " Mapbox Bright\n", + " Mapbox Control Room\n", + " Stamen Terrain\n", + " Stamen Toner\n", + " Stamen Watercolor\n", + " CartoDB positron\n", + " CartoDB dark_matter\"\"\".strip().split('\\n')]\n", + "\n", + "@interact(lat=(-90., 90.), lon=(-180., 180.), tiles=tiles, zoom=(1, 18))\n", + "def create_map(lat=52.518611, lon=13.408333, tiles=\"Stamen Toner\", zoom=10):\n", + " return folium.Map(location=(lat, lon), tiles=tiles, zoom_start=zoom)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Static version\n", + "\n", + "If you don't see the widgets and/or map output in the section above it's likely because you read this notebook on GitHub or on the Jupyter NoteBook Viewer. In this case, this is a static sample image of what you see when running the notebook locally with valid HERE credentials: \n", + "\n", + "![alt text](images/here12.png)\n", + "\n", + "And one thing missing here is, of course: when you interact with the map itself by zooming in or out or panning around you would like to see the widget values change accordingly. But that would need some JavaScript magic. Your contribution is welcome!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Building HERE Maps\n", + "\n", + "But Folium goes one step further and lets you use an arbitrary source of map tiles, simply by providing a URL for the `tiles` parameter in `folium.Map()` that needs to contain placeholders for tile numbers and the zoom level. This means you can use HERE map tiles, even without built-in support for them in Folium." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import os\n", + "import folium\n", + "\n", + "c = map(os.getenv, [\"HEREMAPS_APP_ID\", \"HEREMAPS_APP_CODE\"])\n", + "tiles=\"https://1.base.maps.api.here.com/maptile/2.1/maptile/newest/normal.day/{z}/{x}/{y}/256/png8?lg=eng&app_id=%s&app_code=%s\" % (app_id, app_code)\n", + "folium.Map(location=(52.518611, 13.408333), tiles=tiles, zoom_start=10, attr=\"HERE.com\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Static version\n", + "\n", + "If you don't see the widgets and/or map output in the section above it's likely because you read this notebook on GitHub or on the Jupyter Notebook Viewer and/or you don't have valid HERE credentials. In this case, this is a static sample image of what you see when running the notebook locally with valid HERE credentials: \n", + "\n", + "![alt text](images/here13.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Adding more interactive features\n", + "\n", + "Now let's build a more feature-rich interactive interface to explore the API. This time there are more parameters to play with, using preselected values for some of them. Note that not all combinations are meaningful. Where they are not you simply don't see a map result below. There could be some validation, but... there isn't. This time we use a class, but that's not strictly needed." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "8edcdbff86d9419e81774381599c5828" + } + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + ".>" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import os\n", + "import datetime\n", + "\n", + "app_id, app_code = map(os.getenv, [\"HEREMAPS_APP_ID\", \"HEREMAPS_APP_CODE\"])\n", + "\n", + "tile_formats = \"png8 png jpeg\".split()\n", + "map_types = \"base aerial pano traffic\".split()\n", + "tile_types = \"\"\"\n", + " maptile traffictile flowbasetile trucktile rcdistonlytile\n", + " mapnopttile blinetile alabeltile\n", + "\"\"\".strip().split()\n", + "languages_3 = \"eng ger fre ita gre rus ara hin chi ---\".split()\n", + "\n", + "schemes = \"\"\"\n", + " normal.day normal.day.grey normal.day.transit normal.night\n", + " normal.day.mobile\n", + " pedestrian.day pedestrian.day.mobile\n", + " carnav.day.grey\n", + " normal.traffic.day\n", + " reduced.night\n", + " satellite.day\n", + " hybrid.day\n", + " wrong\n", + "\"\"\".strip().split()\n", + "\n", + "\n", + "class HereMap(object):\n", + " def draw(self, map_type, tile_type, scheme, tile_format, language,\n", + " lat, lon, zoom=10, show_url=False):\n", + " \"Draw a HERE map. Default values are given as parameter keyword values.\"\n", + " \n", + " # raise error for not allowed combinations\n", + " if scheme == \"wrong\":\n", + " raise Exception(\"Combination not allowed\")\n", + " \n", + " # set parameter defaults for map tiles to request\n", + " number = '1' # (1-4)\n", + " map_version = \"newest\" # or some hex hash value\n", + " server_env = \"\" # production, or \"cit.\" for \"customer integration test\"\n", + " tile_size = \"256\"\n", + "\n", + " # build map tiles URL\n", + " server = \"https://{number}.{map_type}.maps.{server_env}api.here.com\"\n", + " path = \"/maptile/2.1/{tile_type}/{map_version}/{scheme}/{{z}}/{{x}}/{{y}}/{tile_size}/{tile_format}\"\n", + " query = \"?app_id={app_id}&app_code={app_code}\"\n", + " if language != \"---\":\n", + " query += \"&lg={language}\"\n", + " params = dict(number=number, map_type=map_type, tile_type=tile_type,\n", + " scheme=scheme, tile_format=tile_format, tile_size=tile_size,\n", + " map_version=map_version, server_env=server_env,\n", + " app_id=app_id, app_code=app_code,\n", + " language=language\n", + " )\n", + " tiles_url = (server + path + query).format(**params)\n", + "\n", + " # set map attribution text\n", + " year = datetime.datetime.now().year\n", + " attr = 'Data by HERE.com, %s' % year\n", + "\n", + " if show_url:\n", + " print(tiles_url)\n", + "\n", + " # build and return a map\n", + " return folium.Map(\n", + " location=(lat, lon),\n", + " tiles=tiles_url,\n", + " zoom_start=zoom,\n", + " attr=attr\n", + " )\n", + "\n", + "hmap = HereMap()\n", + "interact(hmap.draw, map_type=map_types, tile_type=tile_types, scheme=schemes,\n", + " tile_format=tile_formats, language=languages_3, lat=52.5159, lon=13.3777, zoom=(1, 18), show_url=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Static version\n", + "\n", + "If you don't see the widgets and/or map output in the section above it's likely because you read this notebook on GitHub or on the Jupyter NoteBook Viewer and/or you don't have valid HERE credentials. In this case, this is a static sample image of what you see when running the notebook locally with valid HERE credentials: \n", + "\n", + "![alt text](images/here14.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Building a map dashboard\n", + "\n", + "Once you have explored the map parameter space long enough, you might arrive at a few settings that you would probably need more regularly. This is the moment when you can prepare such queries into something like a very simple dashboard-like overview as shown below. This one shows a few maps displaying traffic conditions, information for trucks, public transit and a normal and hybrid satellite view for a few selected cities." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "438628cdd1304beca4891fade406eeed" + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import folium\n", + "from ipywidgets import interact\n", + "\n", + "cities = [\"Berlin\", \"Paris\", \"Chicago\", \"Singapore\"]\n", + "examples = [\"Traffic\", \"Truck info\", \"Transit\", \"Regular\", \"Satellite\"]\n", + "@interact(city=cities, example=examples)\n", + "def show_canned_examples(city, example):\n", + " attr = \"HERE.com\"\n", + " latlon_for_city = {\n", + " \"Berlin\": (52.518611, 13.408333), \n", + " \"Paris\": (48.8567, 2.3508), \n", + " \"Chicago\": (41.88416, -87.63243),\n", + " \"Singapore\": (1.283333, 103.833333)\n", + " }\n", + " zoom = 14\n", + " queries = {\n", + " \"Traffic\":\n", + " \"https://1.traffic.maps.api.here.com/maptile/2.1/traffictile/newest/normal.traffic.day/{z}/{x}/{y}/256/png8?lg=eng&app_id=%s&app_code=%s\" % (app_id, app_code),\n", + " \"Regular\":\n", + " \"https://1.base.maps.api.here.com/maptile/2.1/maptile/newest/normal.day/{z}/{x}/{y}/256/png8?lg=eng&app_id=%s&app_code=%s\" % (app_id, app_code),\n", + " \"Truck info\":\n", + " \"https://1.base.maps.api.here.com/maptile/2.1/trucktile/newest/normal.day.grey/{z}/{x}/{y}/256/png8?lg=eng&app_id=%s&app_code=%s\" % (app_id, app_code),\n", + " \"Transit\":\n", + " \"https://1.base.maps.api.here.com/maptile/2.1/maptile/newest/normal.day.transit/{z}/{x}/{y}/256/png8?lg=eng&app_id=%s&app_code=%s\" % (app_id, app_code),\n", + " \"Satellite\":\n", + " \"https://1.aerial.maps.api.here.com/maptile/2.1/maptile/newest/hybrid.day/{z}/{x}/{y}/256/png8?lg=eng&app_id=%s&app_code=%s\" % (app_id, app_code),\n", + " }\n", + " return folium.Map(location=latlon_for_city[city], tiles=queries[example],attr=attr, zoom_start=zoom)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Static version\n", + "\n", + "Again, if you don't see the widgets and/or map output above this paragraph it's likely because you read this notebook on GitHub or on the Jupyter NoteBook Viewer and/or you don't have valid HERE credentials. In this case, this is a static sample image of what you see when running the notebook locally with valid HERE credentials: \n", + "\n", + "![alt text](images/here15.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conclusion\n", + "\n", + "This concludes our little exploration with map tiles and maps. This notebook has shown how to use Folium (and Leaflet) to grab individual map tiles from a map service provider not yet directly supported by Folium, [HERE.com](https://here.com), explore them interactively using the RESTful API inside a Jupyter notebook, and generate full-fledged maps. It has shown how surprisingly simple this is with the powerful tools and great content available today. And there are lots of other interesting APIs, e.g. about venue maps, see the [HERE API documentation](https://developer.here.com/documentation).\n", + "\n", + "There are many more features of HERE maps, Folium and Leaflet, that have not been touched in this notebook, especially about using additional data layers. This might be addressed in other notebooks using Folium and HERE's emerging [Open Location Platform](https://here.com/en/innovation/here-open-location-platform). So please stay tuned!" + ] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/images/here12.png b/examples/images/here12.png new file mode 100644 index 0000000000..65716d7a3d Binary files /dev/null and b/examples/images/here12.png differ diff --git a/examples/images/here13.png b/examples/images/here13.png new file mode 100644 index 0000000000..d8eb8d16bf Binary files /dev/null and b/examples/images/here13.png differ diff --git a/examples/images/here14.png b/examples/images/here14.png new file mode 100644 index 0000000000..d59fb07278 Binary files /dev/null and b/examples/images/here14.png differ diff --git a/examples/images/here15.png b/examples/images/here15.png new file mode 100644 index 0000000000..157645a758 Binary files /dev/null and b/examples/images/here15.png differ diff --git a/examples/images/here9.png b/examples/images/here9.png new file mode 100644 index 0000000000..5ac28a9588 Binary files /dev/null and b/examples/images/here9.png differ