{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "EOr-DwYgRsUa"
   },
   "source": [
    "# Initiation to data collection with web scraping and APIs\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "All required packages are available.\n"
     ]
    }
   ],
   "source": [
    "# Run this cell only if some packages are missing.\n",
    "import importlib.util\n",
    "import subprocess\n",
    "import sys\n",
    "\n",
    "packages = {\n",
    "    \"bs4\": \"beautifulsoup4\",\n",
    "    \"pandas\": \"pandas\",\n",
    "    \"lxml\": \"lxml\",\n",
    "    \"folium\": \"folium\",\n",
    "}\n",
    "\n",
    "for import_name, package_name in packages.items():\n",
    "    if importlib.util.find_spec(import_name) is None:\n",
    "        print(f\"Installing {package_name}...\")\n",
    "        subprocess.check_call([sys.executable, \"-m\", \"pip\", \"install\", package_name])\n",
    "\n",
    "print(\"All required packages are available.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "executionInfo": {
     "elapsed": 10389,
     "status": "ok",
     "timestamp": 1737535342998,
     "user": {
      "displayName": "Lau re",
      "userId": "03302099944040145915"
     },
     "user_tz": -60
    },
    "id": "E4zarSeAQdHm"
   },
   "outputs": [],
   "source": [
    "import bs4\n",
    "import pandas as pd\n",
    "\n",
    "from io import StringIO\n",
    "from urllib.parse import quote, urljoin\n",
    "from urllib.request import Request, urlopen\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "t4wzROqzT36G"
   },
   "source": [
    "## Scrape a table on a Wikipedia page\n",
    "\n",
    "We would like to display on a map the location of the Summer Olympic Games since 1896. We will use a [Wikipedia page](https://fr.wikipedia.org/wiki/Jeux_olympiques) to scrape the associated table.\n",
    "\n",
    "Below is the code to download the page with `urllib.request` and display its title with `BeautifulSoup`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 1274,
     "status": "ok",
     "timestamp": 1737535344270,
     "user": {
      "displayName": "Lau re",
      "userId": "03302099944040145915"
     },
     "user_tz": -60
    },
    "id": "Nl9QICzwTGG7",
    "outputId": "b0c7f6a4-c1f3-4f6a-cc9f-da86a47bbcfe"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Jeux olympiques — Wikipédia\n"
     ]
    }
   ],
   "source": [
    "url = \"https://fr.wikipedia.org/wiki/Jeux_olympiques\"\n",
    "\n",
    "req = Request(url, headers={\"User-Agent\": \"Mozilla/5.0\"})\n",
    "html = urlopen(req).read()\n",
    "\n",
    "page = bs4.BeautifulSoup(html, \"lxml\")\n",
    "\n",
    "print(page.find(\"title\").get_text(strip=True))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "U_18h3E9UiYR"
   },
   "source": [
    "Our objective here is to extract the information from the first table, \"Jeux olympiques d'été\", and build a dataframe.\n",
    "\n",
    "To proceed, we will follow two steps:\n",
    "* Find the table in the HTML page with Beautiful Soup.\n",
    "* Convert the HTML table into a pandas dataframe.\n",
    "\n",
    "Check the quick start of Beautiful Soup to understand what is going on: https://beautiful-soup-4.readthedocs.io/en/latest/\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 4,
     "status": "ok",
     "timestamp": 1737535344270,
     "user": {
      "displayName": "Lau re",
      "userId": "03302099944040145915"
     },
     "user_tz": -60
    },
    "id": "M5oVOOZuKxD_",
    "outputId": "963cee44-646a-46fe-e688-76db7b0c2934"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Année</th>\n",
       "      <th>Olympiade (Nº de l’olympiade[NB 1])</th>\n",
       "      <th>Ville hôte</th>\n",
       "      <th>Pays</th>\n",
       "      <th>Continent</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1896</td>\n",
       "      <td>I</td>\n",
       "      <td>Athènes (1)</td>\n",
       "      <td>Grèce (1)</td>\n",
       "      <td>Europe (1)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1900</td>\n",
       "      <td>II</td>\n",
       "      <td>Paris (1)</td>\n",
       "      <td>France (1)</td>\n",
       "      <td>Europe (2)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1904</td>\n",
       "      <td>III</td>\n",
       "      <td>Saint-Louis (1)</td>\n",
       "      <td>États-Unis (1)</td>\n",
       "      <td>Amérique du Nord (1)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1906</td>\n",
       "      <td>• (Intercalaires[NB 2])</td>\n",
       "      <td>Athènes (2)</td>\n",
       "      <td>Grèce (2)</td>\n",
       "      <td>Europe</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1908</td>\n",
       "      <td>IV</td>\n",
       "      <td>Londres (1)</td>\n",
       "      <td>Royaume-Uni (1)</td>\n",
       "      <td>Europe (3)</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   Année Olympiade (Nº de l’olympiade[NB 1])       Ville hôte  \\\n",
       "0   1896                                   I      Athènes (1)   \n",
       "1   1900                                  II        Paris (1)   \n",
       "2   1904                                 III  Saint-Louis (1)   \n",
       "3   1906             • (Intercalaires[NB 2])      Athènes (2)   \n",
       "4   1908                                  IV      Londres (1)   \n",
       "\n",
       "              Pays             Continent  \n",
       "0        Grèce (1)            Europe (1)  \n",
       "1       France (1)            Europe (2)  \n",
       "2   États-Unis (1)  Amérique du Nord (1)  \n",
       "3        Grèce (2)                Europe  \n",
       "4  Royaume-Uni (1)            Europe (3)  "
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "table = page.find(\"table\", class_=\"wikitable center\")\n",
    "\n",
    "# pandas can read HTML tables directly.\n",
    "olympics = pd.read_html(StringIO(str(table)))[0]\n",
    "\n",
    "olympics.head()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Qw6i-yLueZvG"
   },
   "source": [
    "## Exercise 2: Locate places on a map\n",
    "\n",
    "The objective here is to identify organizer cities on a map.\n",
    "\n",
    "Here are the steps:\n",
    "* For each city in the table, collect the URL of its corresponding page.\n",
    "* Find the coordinates of the city in the HTML page of the city\n",
    "* Store cities and coordinates in a dataframe.\n",
    "\n",
    "Tips:\n",
    "First, check manually how the page of a city is organized. With your favorite browser, check the source of the page and locate the code of the infobox on the topr right of the page. In that infobox, check where are the coordinates of the city and how this is coded in HTML. You will find that the coordinates are written in the HTML source at this location.\n",
    "\n",
    "Read the following code and understand it line by line. Add comments to explain each of the parts.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 35916,
     "status": "ok",
     "timestamp": 1737535380184,
     "user": {
      "displayName": "Lau re",
      "userId": "03302099944040145915"
     },
     "user_tz": -60
    },
    "id": "7xaYx79JMF_N",
    "outputId": "61045df9-7802-4fdb-c596-5767531be764"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>name</th>\n",
       "      <th>url</th>\n",
       "      <th>latitude</th>\n",
       "      <th>longitude</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Athènes</td>\n",
       "      <td>https://fr.wikipedia.org/wiki/Athènes</td>\n",
       "      <td>37.966667</td>\n",
       "      <td>23.716667</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Paris</td>\n",
       "      <td>https://fr.wikipedia.org/wiki/Paris</td>\n",
       "      <td>48.856578</td>\n",
       "      <td>2.351828</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Saint-Louis</td>\n",
       "      <td>https://fr.wikipedia.org/wiki/Saint-Louis_(Mis...</td>\n",
       "      <td>38.648056</td>\n",
       "      <td>-90.212220</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Athènes</td>\n",
       "      <td>https://fr.wikipedia.org/wiki/Athènes</td>\n",
       "      <td>37.966667</td>\n",
       "      <td>23.716667</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Londres</td>\n",
       "      <td>https://fr.wikipedia.org/wiki/Londres</td>\n",
       "      <td>51.507222</td>\n",
       "      <td>-0.127500</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "          name                                                url   latitude  \\\n",
       "0      Athènes              https://fr.wikipedia.org/wiki/Athènes  37.966667   \n",
       "1        Paris                https://fr.wikipedia.org/wiki/Paris  48.856578   \n",
       "2  Saint-Louis  https://fr.wikipedia.org/wiki/Saint-Louis_(Mis...  38.648056   \n",
       "3      Athènes              https://fr.wikipedia.org/wiki/Athènes  37.966667   \n",
       "4      Londres              https://fr.wikipedia.org/wiki/Londres  51.507222   \n",
       "\n",
       "   longitude  \n",
       "0  23.716667  \n",
       "1   2.351828  \n",
       "2 -90.212220  \n",
       "3  23.716667  \n",
       "4  -0.127500  "
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "base_url = \"https://fr.wikipedia.org\"\n",
    "rows = table.find_all(\"tr\")\n",
    "\n",
    "cities = []\n",
    "coordinates_cache = {}\n",
    "\n",
    "for row in rows[1:]:\n",
    "    cells = row.find_all(\"td\")\n",
    "    if len(cells) < 3:\n",
    "        continue\n",
    "\n",
    "    # BeautifulSoup can directly look for links with an href attribute.\n",
    "    city_link = cells[2].find(\"a\", href=True)\n",
    "    if city_link is None:\n",
    "        continue\n",
    "\n",
    "    name = city_link.get_text(strip=True)\n",
    "    city_url = urljoin(base_url, city_link[\"href\"])\n",
    "\n",
    "    if city_url not in coordinates_cache:\n",
    "        safe_city_url = quote(city_url, safe=\"/:?=&%\")\n",
    "        req = Request(safe_city_url, headers={\"User-Agent\": \"Mozilla/5.0\"})\n",
    "        city_html = urlopen(req).read()\n",
    "        city_page = bs4.BeautifulSoup(city_html, \"lxml\")\n",
    "\n",
    "        map_link = city_page.select_one(\n",
    "            \"table[class*=infobox] a.mw-kartographer-maplink[data-lat][data-lon]\"\n",
    "        )\n",
    "\n",
    "        if map_link is None:\n",
    "            map_link = city_page.select_one(\"a.mw-kartographer-maplink[data-lat][data-lon]\")\n",
    "\n",
    "        coordinates_cache[city_url] = (\n",
    "            map_link.get(\"data-lat\") if map_link else None,\n",
    "            map_link.get(\"data-lon\") if map_link else None,\n",
    "        )\n",
    "\n",
    "    latitude, longitude = coordinates_cache[city_url]\n",
    "    cities.append({\n",
    "        \"name\": name,\n",
    "        \"url\": city_url,\n",
    "        \"latitude\": latitude,\n",
    "        \"longitude\": longitude,\n",
    "    })\n",
    "\n",
    "data = pd.DataFrame(cities).dropna()\n",
    "data[\"latitude\"] = pd.to_numeric(data[\"latitude\"])\n",
    "data[\"longitude\"] = pd.to_numeric(data[\"longitude\"])\n",
    "\n",
    "data.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "j3_3JmXggIEk"
   },
   "source": [
    "Then we can plot the map. The map is also saved as an HTML file, so it can be opened in a browser if it does not display correctly inside the notebook.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 711
    },
    "executionInfo": {
     "elapsed": 957,
     "status": "ok",
     "timestamp": 1737535381121,
     "user": {
      "displayName": "Lau re",
      "userId": "03302099944040145915"
     },
     "user_tz": -60
    },
    "id": "93_lzZI3Wkpt",
    "outputId": "45d5a209-06c2-49b3-996c-5295bc1d60e2"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"width:100%;\"><div style=\"position:relative;width:100%;height:0;padding-bottom:60%;\"><span style=\"color:#565656\">Make this Notebook Trusted to load map: File -> Trust Notebook</span><iframe srcdoc=\"&lt;!DOCTYPE html&gt;\n",
       "&lt;html&gt;\n",
       "&lt;head&gt;\n",
       "    \n",
       "    &lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=UTF-8&quot; /&gt;\n",
       "    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/leaflet@1.9.3/dist/leaflet.js&quot;&gt;&lt;/script&gt;\n",
       "    &lt;script src=&quot;https://code.jquery.com/jquery-3.7.1.min.js&quot;&gt;&lt;/script&gt;\n",
       "    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js&quot;&gt;&lt;/script&gt;\n",
       "    &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.js&quot;&gt;&lt;/script&gt;\n",
       "    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/leaflet@1.9.3/dist/leaflet.css&quot;/&gt;\n",
       "    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css&quot;/&gt;\n",
       "    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css&quot;/&gt;\n",
       "    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.2.0/css/all.min.css&quot;/&gt;\n",
       "    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css&quot;/&gt;\n",
       "    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/gh/python-visualization/folium/folium/templates/leaflet.awesome.rotate.min.css&quot;/&gt;\n",
       "    \n",
       "            &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width,\n",
       "                initial-scale=1.0, maximum-scale=1.0, user-scalable=no&quot; /&gt;\n",
       "            &lt;style&gt;\n",
       "                #map_b5187139028cccbdc228bc64fc95a197 {\n",
       "                    position: relative;\n",
       "                    width: 100.0%;\n",
       "                    height: 100.0%;\n",
       "                    left: 0.0%;\n",
       "                    top: 0.0%;\n",
       "                }\n",
       "                .leaflet-container { font-size: 1rem; }\n",
       "            &lt;/style&gt;\n",
       "\n",
       "            &lt;style&gt;html, body {\n",
       "                width: 100%;\n",
       "                height: 100%;\n",
       "                margin: 0;\n",
       "                padding: 0;\n",
       "            }\n",
       "            &lt;/style&gt;\n",
       "\n",
       "            &lt;style&gt;#map {\n",
       "                position:absolute;\n",
       "                top:0;\n",
       "                bottom:0;\n",
       "                right:0;\n",
       "                left:0;\n",
       "                }\n",
       "            &lt;/style&gt;\n",
       "\n",
       "            &lt;script&gt;\n",
       "                L_NO_TOUCH = false;\n",
       "                L_DISABLE_3D = false;\n",
       "            &lt;/script&gt;\n",
       "\n",
       "        \n",
       "&lt;/head&gt;\n",
       "&lt;body&gt;\n",
       "    \n",
       "    \n",
       "            &lt;div class=&quot;folium-map&quot; id=&quot;map_b5187139028cccbdc228bc64fc95a197&quot; &gt;&lt;/div&gt;\n",
       "        \n",
       "&lt;/body&gt;\n",
       "&lt;script&gt;\n",
       "    \n",
       "    \n",
       "            var map_b5187139028cccbdc228bc64fc95a197 = L.map(\n",
       "                &quot;map_b5187139028cccbdc228bc64fc95a197&quot;,\n",
       "                {\n",
       "                    center: [35.66043096697528, 16.30611925895088],\n",
       "                    crs: L.CRS.EPSG3857,\n",
       "                    ...{\n",
       "  &quot;zoom&quot;: 2,\n",
       "  &quot;zoomControl&quot;: true,\n",
       "  &quot;preferCanvas&quot;: false,\n",
       "}\n",
       "\n",
       "                }\n",
       "            );\n",
       "\n",
       "            \n",
       "\n",
       "        \n",
       "    \n",
       "            var tile_layer_9de987a7096fc11d0429b7b866bcd47a = L.tileLayer(\n",
       "                &quot;https://tile.openstreetmap.org/{z}/{x}/{y}.png&quot;,\n",
       "                {\n",
       "  &quot;minZoom&quot;: 0,\n",
       "  &quot;maxZoom&quot;: 19,\n",
       "  &quot;maxNativeZoom&quot;: 19,\n",
       "  &quot;noWrap&quot;: false,\n",
       "  &quot;attribution&quot;: &quot;\\u0026copy; \\u003ca href=\\&quot;https://www.openstreetmap.org/copyright\\&quot;\\u003eOpenStreetMap\\u003c/a\\u003e contributors&quot;,\n",
       "  &quot;subdomains&quot;: &quot;abc&quot;,\n",
       "  &quot;detectRetina&quot;: false,\n",
       "  &quot;tms&quot;: false,\n",
       "  &quot;opacity&quot;: 1,\n",
       "}\n",
       "\n",
       "            );\n",
       "        \n",
       "    \n",
       "            tile_layer_9de987a7096fc11d0429b7b866bcd47a.addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "            var marker_6eb70f98eb7a70783f169678097b9750 = L.marker(\n",
       "                [37.9666667, 23.7166667],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_19d33b96ef4f4ab502c1f6992680e77a = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_3d89d0dec3611cf7b810168eb0be5ef5 = $(`&lt;div id=&quot;html_3d89d0dec3611cf7b810168eb0be5ef5&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Athènes&lt;/div&gt;`)[0];\n",
       "                popup_19d33b96ef4f4ab502c1f6992680e77a.setContent(html_3d89d0dec3611cf7b810168eb0be5ef5);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_6eb70f98eb7a70783f169678097b9750.bindPopup(popup_19d33b96ef4f4ab502c1f6992680e77a)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_e2cc9a4ac7b5449de01cd067a35ca595 = L.marker(\n",
       "                [48.856578, 2.351828],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_94d7e435d4154c1c278b122a1673ce76 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_bb02c13182839adb1c03aa371d0bd8e7 = $(`&lt;div id=&quot;html_bb02c13182839adb1c03aa371d0bd8e7&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Paris&lt;/div&gt;`)[0];\n",
       "                popup_94d7e435d4154c1c278b122a1673ce76.setContent(html_bb02c13182839adb1c03aa371d0bd8e7);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_e2cc9a4ac7b5449de01cd067a35ca595.bindPopup(popup_94d7e435d4154c1c278b122a1673ce76)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_a7f1f6ac65bd7b2391bb9014300dc9ca = L.marker(\n",
       "                [38.648056, -90.21222],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_8b30fb2027c3011bb38f33a5e242a631 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_ce7ebea48e680b907d98bee07b693d06 = $(`&lt;div id=&quot;html_ce7ebea48e680b907d98bee07b693d06&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Saint-Louis&lt;/div&gt;`)[0];\n",
       "                popup_8b30fb2027c3011bb38f33a5e242a631.setContent(html_ce7ebea48e680b907d98bee07b693d06);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_a7f1f6ac65bd7b2391bb9014300dc9ca.bindPopup(popup_8b30fb2027c3011bb38f33a5e242a631)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_5502783f66cbe4bb3229cf6430d39aa1 = L.marker(\n",
       "                [37.9666667, 23.7166667],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_03feca9cccc0ee6414737cfb6bc64f47 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_eae3d34c8d9734051e310c2239e49674 = $(`&lt;div id=&quot;html_eae3d34c8d9734051e310c2239e49674&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Athènes&lt;/div&gt;`)[0];\n",
       "                popup_03feca9cccc0ee6414737cfb6bc64f47.setContent(html_eae3d34c8d9734051e310c2239e49674);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_5502783f66cbe4bb3229cf6430d39aa1.bindPopup(popup_03feca9cccc0ee6414737cfb6bc64f47)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_8755e2bf4826d24cb253cb100e96c2bc = L.marker(\n",
       "                [51.507222, -0.1275],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_6005a2ac0cdfd87a6b8dfb02e312fc92 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_98b6f8b109393d61418887ae0420c37a = $(`&lt;div id=&quot;html_98b6f8b109393d61418887ae0420c37a&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Londres&lt;/div&gt;`)[0];\n",
       "                popup_6005a2ac0cdfd87a6b8dfb02e312fc92.setContent(html_98b6f8b109393d61418887ae0420c37a);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_8755e2bf4826d24cb253cb100e96c2bc.bindPopup(popup_6005a2ac0cdfd87a6b8dfb02e312fc92)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_1ba04a81ef2b064a10ddef8a779f5a68 = L.marker(\n",
       "                [59.329444, 18.068611],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_eb952970b4b461d31f1173fd14902266 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_300ff2c799241fb249297587408b34b5 = $(`&lt;div id=&quot;html_300ff2c799241fb249297587408b34b5&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Stockholm&lt;/div&gt;`)[0];\n",
       "                popup_eb952970b4b461d31f1173fd14902266.setContent(html_300ff2c799241fb249297587408b34b5);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_1ba04a81ef2b064a10ddef8a779f5a68.bindPopup(popup_eb952970b4b461d31f1173fd14902266)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_7695834380a8f19b4f44f4ab205ae819 = L.marker(\n",
       "                [52.516666666667, 13.383333333333],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_bb7e8a850e4ba2b43397f825dd73add1 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_851727dea26a2566763c74dd441d0efd = $(`&lt;div id=&quot;html_851727dea26a2566763c74dd441d0efd&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Berlin&lt;/div&gt;`)[0];\n",
       "                popup_bb7e8a850e4ba2b43397f825dd73add1.setContent(html_851727dea26a2566763c74dd441d0efd);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_7695834380a8f19b4f44f4ab205ae819.bindPopup(popup_bb7e8a850e4ba2b43397f825dd73add1)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_4b198927f35c87a56ec601495da59613 = L.marker(\n",
       "                [51.217, 4.4],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_8fd9de0b1a571b4b6049a2f00e5f7459 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_3a395b7c11203c664d07b51ec54ca985 = $(`&lt;div id=&quot;html_3a395b7c11203c664d07b51ec54ca985&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Anvers&lt;/div&gt;`)[0];\n",
       "                popup_8fd9de0b1a571b4b6049a2f00e5f7459.setContent(html_3a395b7c11203c664d07b51ec54ca985);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_4b198927f35c87a56ec601495da59613.bindPopup(popup_8fd9de0b1a571b4b6049a2f00e5f7459)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_9f55635df4b4d533d6f9405ea34d40f3 = L.marker(\n",
       "                [48.856578, 2.351828],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_d0bc234ccd84cf302110180e03c6bc10 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_9dfed8d087d03dcfa21d1b14db6985ce = $(`&lt;div id=&quot;html_9dfed8d087d03dcfa21d1b14db6985ce&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Paris&lt;/div&gt;`)[0];\n",
       "                popup_d0bc234ccd84cf302110180e03c6bc10.setContent(html_9dfed8d087d03dcfa21d1b14db6985ce);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_9f55635df4b4d533d6f9405ea34d40f3.bindPopup(popup_d0bc234ccd84cf302110180e03c6bc10)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_18396b0d60785a143167ebec7cbdeb0e = L.marker(\n",
       "                [52.366666666667, 4.8833333333333],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_b0e44283a8c2625eb30d4667aa014278 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_d1b340317c17881dafcaa7dcaf6df098 = $(`&lt;div id=&quot;html_d1b340317c17881dafcaa7dcaf6df098&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Amsterdam&lt;/div&gt;`)[0];\n",
       "                popup_b0e44283a8c2625eb30d4667aa014278.setContent(html_d1b340317c17881dafcaa7dcaf6df098);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_18396b0d60785a143167ebec7cbdeb0e.bindPopup(popup_b0e44283a8c2625eb30d4667aa014278)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_9ba420b95aa24447f2c28936a31ba613 = L.marker(\n",
       "                [34.05223, -118.24368],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_4b80bf4fdef99e296b7a0930e52fa1eb = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_8bbee2c0425ad44cb5c65fd80f434ab0 = $(`&lt;div id=&quot;html_8bbee2c0425ad44cb5c65fd80f434ab0&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Los Angeles&lt;/div&gt;`)[0];\n",
       "                popup_4b80bf4fdef99e296b7a0930e52fa1eb.setContent(html_8bbee2c0425ad44cb5c65fd80f434ab0);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_9ba420b95aa24447f2c28936a31ba613.bindPopup(popup_4b80bf4fdef99e296b7a0930e52fa1eb)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_027430aed06a7bd53bfe3b8b0844561b = L.marker(\n",
       "                [52.516666666667, 13.383333333333],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_ff1b62018f885ad8ec930ed3eeeaab4b = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_01816ed3fbe17f4214edfea4ba8baece = $(`&lt;div id=&quot;html_01816ed3fbe17f4214edfea4ba8baece&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Berlin&lt;/div&gt;`)[0];\n",
       "                popup_ff1b62018f885ad8ec930ed3eeeaab4b.setContent(html_01816ed3fbe17f4214edfea4ba8baece);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_027430aed06a7bd53bfe3b8b0844561b.bindPopup(popup_ff1b62018f885ad8ec930ed3eeeaab4b)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_238ba45064d9d04fbafcd127015d5b51 = L.marker(\n",
       "                [35.689444444444, 139.69166666667],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_b6a6c9a3238e924fac7292ca8f975349 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_43d13bd9d1a8d11d5560e9943a3dee99 = $(`&lt;div id=&quot;html_43d13bd9d1a8d11d5560e9943a3dee99&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Tokyo&lt;/div&gt;`)[0];\n",
       "                popup_b6a6c9a3238e924fac7292ca8f975349.setContent(html_43d13bd9d1a8d11d5560e9943a3dee99);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_238ba45064d9d04fbafcd127015d5b51.bindPopup(popup_b6a6c9a3238e924fac7292ca8f975349)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_28745c12031390f19f8b9ea19db2d340 = L.marker(\n",
       "                [51.507222, -0.1275],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_2f5f67bd83796b31f087d35d5e97a45f = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_5fdca06a7fa969f18d3f2ffe4e97fe6b = $(`&lt;div id=&quot;html_5fdca06a7fa969f18d3f2ffe4e97fe6b&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Londres&lt;/div&gt;`)[0];\n",
       "                popup_2f5f67bd83796b31f087d35d5e97a45f.setContent(html_5fdca06a7fa969f18d3f2ffe4e97fe6b);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_28745c12031390f19f8b9ea19db2d340.bindPopup(popup_2f5f67bd83796b31f087d35d5e97a45f)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_8886745e022cfdc9f23322c40a726fc0 = L.marker(\n",
       "                [51.507222, -0.1275],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_f551011d5a15523d7100ce36fc0e7b6d = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_9d3bf7938196b0ac0d6446727b264fe5 = $(`&lt;div id=&quot;html_9d3bf7938196b0ac0d6446727b264fe5&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Londres&lt;/div&gt;`)[0];\n",
       "                popup_f551011d5a15523d7100ce36fc0e7b6d.setContent(html_9d3bf7938196b0ac0d6446727b264fe5);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_8886745e022cfdc9f23322c40a726fc0.bindPopup(popup_f551011d5a15523d7100ce36fc0e7b6d)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_f452469773f562c4f98fa77a5403b9eb = L.marker(\n",
       "                [60.170833333333, 24.9375],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_b4c05ac3c945845225949265b60cc9c6 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_ed8e23f5995255785e655678a6ec426f = $(`&lt;div id=&quot;html_ed8e23f5995255785e655678a6ec426f&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Helsinki&lt;/div&gt;`)[0];\n",
       "                popup_b4c05ac3c945845225949265b60cc9c6.setContent(html_ed8e23f5995255785e655678a6ec426f);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_f452469773f562c4f98fa77a5403b9eb.bindPopup(popup_b4c05ac3c945845225949265b60cc9c6)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_b2aed15ee377cd1f253e2025a8f37f17 = L.marker(\n",
       "                [-37.81417, 144.96833],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_a2db6339c4559157958e5e7433b5e933 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_532714ffb6f8180caf199e168be8664b = $(`&lt;div id=&quot;html_532714ffb6f8180caf199e168be8664b&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Melbourne&lt;/div&gt;`)[0];\n",
       "                popup_a2db6339c4559157958e5e7433b5e933.setContent(html_532714ffb6f8180caf199e168be8664b);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_b2aed15ee377cd1f253e2025a8f37f17.bindPopup(popup_a2db6339c4559157958e5e7433b5e933)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_1b8195279281388684be65e651fcd683 = L.marker(\n",
       "                [41.888732, 12.48657],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_eaabdabb2f60a5d96aee4973661ca8a1 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_bb672224c9c3f29b474403750a3f0cc2 = $(`&lt;div id=&quot;html_bb672224c9c3f29b474403750a3f0cc2&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Rome&lt;/div&gt;`)[0];\n",
       "                popup_eaabdabb2f60a5d96aee4973661ca8a1.setContent(html_bb672224c9c3f29b474403750a3f0cc2);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_1b8195279281388684be65e651fcd683.bindPopup(popup_eaabdabb2f60a5d96aee4973661ca8a1)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_52506dae630b353cc89dfe5c7d5cf7fc = L.marker(\n",
       "                [35.689444444444, 139.69166666667],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_f0d3be0d485ef774150d4a1730527311 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_6cd4787f8f31fe32f9ae78b58540aa66 = $(`&lt;div id=&quot;html_6cd4787f8f31fe32f9ae78b58540aa66&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Tokyo&lt;/div&gt;`)[0];\n",
       "                popup_f0d3be0d485ef774150d4a1730527311.setContent(html_6cd4787f8f31fe32f9ae78b58540aa66);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_52506dae630b353cc89dfe5c7d5cf7fc.bindPopup(popup_f0d3be0d485ef774150d4a1730527311)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_a072c30c1290c62685abb210f0bf36cd = L.marker(\n",
       "                [19.432545, -99.131636],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_2a541fdc014c520c9134463b57843230 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_d47b7243c80a44d77cb8cc8d28ff56de = $(`&lt;div id=&quot;html_d47b7243c80a44d77cb8cc8d28ff56de&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Mexico&lt;/div&gt;`)[0];\n",
       "                popup_2a541fdc014c520c9134463b57843230.setContent(html_d47b7243c80a44d77cb8cc8d28ff56de);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_a072c30c1290c62685abb210f0bf36cd.bindPopup(popup_2a541fdc014c520c9134463b57843230)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_a9563a01deb590f0f81b13abbb2e74ce = L.marker(\n",
       "                [48.15, 11.575],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_fb940ac341121be32632834eeb803fed = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_3ee7c9272045b7fe02308294a7b40cac = $(`&lt;div id=&quot;html_3ee7c9272045b7fe02308294a7b40cac&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Munich&lt;/div&gt;`)[0];\n",
       "                popup_fb940ac341121be32632834eeb803fed.setContent(html_3ee7c9272045b7fe02308294a7b40cac);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_a9563a01deb590f0f81b13abbb2e74ce.bindPopup(popup_fb940ac341121be32632834eeb803fed)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_bc6647610bb0073d9bdb3396e8ecb94e = L.marker(\n",
       "                [45.5033426, -73.5868411],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_750d6688f64299cc7b31642fe71d66df = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_24542a04009ab704a2b1bb90e0a14d6d = $(`&lt;div id=&quot;html_24542a04009ab704a2b1bb90e0a14d6d&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Montréal&lt;/div&gt;`)[0];\n",
       "                popup_750d6688f64299cc7b31642fe71d66df.setContent(html_24542a04009ab704a2b1bb90e0a14d6d);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_bc6647610bb0073d9bdb3396e8ecb94e.bindPopup(popup_750d6688f64299cc7b31642fe71d66df)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_8d15fa5b4eb2b0140d53a79fbf71c280 = L.marker(\n",
       "                [55.7525, 37.6230861],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_b4b8bc63d50943af26bc5457b659f876 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_b67ccf6b1c94c1c2e30def9ad4345bfa = $(`&lt;div id=&quot;html_b67ccf6b1c94c1c2e30def9ad4345bfa&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Moscou&lt;/div&gt;`)[0];\n",
       "                popup_b4b8bc63d50943af26bc5457b659f876.setContent(html_b67ccf6b1c94c1c2e30def9ad4345bfa);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_8d15fa5b4eb2b0140d53a79fbf71c280.bindPopup(popup_b4b8bc63d50943af26bc5457b659f876)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_fdc4325d244a1d8c4e02611176a1ff71 = L.marker(\n",
       "                [34.05223, -118.24368],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_9d93b2b2045bd54cb0c2ed775126e865 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_40a24436e29ff9c7df2abd3a0428bc4b = $(`&lt;div id=&quot;html_40a24436e29ff9c7df2abd3a0428bc4b&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Los Angeles&lt;/div&gt;`)[0];\n",
       "                popup_9d93b2b2045bd54cb0c2ed775126e865.setContent(html_40a24436e29ff9c7df2abd3a0428bc4b);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_fdc4325d244a1d8c4e02611176a1ff71.bindPopup(popup_9d93b2b2045bd54cb0c2ed775126e865)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_5559b15456a5f279b40b67381be3b8b9 = L.marker(\n",
       "                [37.5657, 126.978],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_a908f2b07cb9832b815774014e88759e = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_72cc3486319dd374f86385474f7893db = $(`&lt;div id=&quot;html_72cc3486319dd374f86385474f7893db&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Séoul&lt;/div&gt;`)[0];\n",
       "                popup_a908f2b07cb9832b815774014e88759e.setContent(html_72cc3486319dd374f86385474f7893db);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_5559b15456a5f279b40b67381be3b8b9.bindPopup(popup_a908f2b07cb9832b815774014e88759e)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_5e2004f9abac78a71f49f5a861981b07 = L.marker(\n",
       "                [41.3825, 2.1769444444444],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_ea2326193608397b710a71a74fdde104 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_1dc4c32c7ea23b0fd7f1f988303943a7 = $(`&lt;div id=&quot;html_1dc4c32c7ea23b0fd7f1f988303943a7&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Barcelone&lt;/div&gt;`)[0];\n",
       "                popup_ea2326193608397b710a71a74fdde104.setContent(html_1dc4c32c7ea23b0fd7f1f988303943a7);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_5e2004f9abac78a71f49f5a861981b07.bindPopup(popup_ea2326193608397b710a71a74fdde104)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_3609359c31afdffaa60569ee4f09b313 = L.marker(\n",
       "                [33.754444444444, -84.389722222222],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_ad512e01d18755ccd46952b3eef0a550 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_a4cc7d8cd4fdf6274034ba7c4a47beb7 = $(`&lt;div id=&quot;html_a4cc7d8cd4fdf6274034ba7c4a47beb7&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Atlanta&lt;/div&gt;`)[0];\n",
       "                popup_ad512e01d18755ccd46952b3eef0a550.setContent(html_a4cc7d8cd4fdf6274034ba7c4a47beb7);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_3609359c31afdffaa60569ee4f09b313.bindPopup(popup_ad512e01d18755ccd46952b3eef0a550)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_c63950f205d478413330f0b83e351a10 = L.marker(\n",
       "                [-33.856111, 151.1925],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_9fdd0aaebe835994ef64e0154c927f33 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_953287af36978bbd87ead7e3da1ed815 = $(`&lt;div id=&quot;html_953287af36978bbd87ead7e3da1ed815&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Sydney&lt;/div&gt;`)[0];\n",
       "                popup_9fdd0aaebe835994ef64e0154c927f33.setContent(html_953287af36978bbd87ead7e3da1ed815);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_c63950f205d478413330f0b83e351a10.bindPopup(popup_9fdd0aaebe835994ef64e0154c927f33)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_9932e10a1980070d5c82ab3da6af595d = L.marker(\n",
       "                [37.9666667, 23.7166667],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_686276551a1c5d352636ef08a6d9e444 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_df28597dda825e15cc8c3ffb945d4c4c = $(`&lt;div id=&quot;html_df28597dda825e15cc8c3ffb945d4c4c&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Athènes&lt;/div&gt;`)[0];\n",
       "                popup_686276551a1c5d352636ef08a6d9e444.setContent(html_df28597dda825e15cc8c3ffb945d4c4c);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_9932e10a1980070d5c82ab3da6af595d.bindPopup(popup_686276551a1c5d352636ef08a6d9e444)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_1e7ebd61184dc40a3ba071ec85e3cb34 = L.marker(\n",
       "                [39.903546, 116.387578],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_ca6f584ee383bbb6402b54a14884cdb1 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_816af84cf133e0e825b270d132d4a032 = $(`&lt;div id=&quot;html_816af84cf133e0e825b270d132d4a032&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Pékin&lt;/div&gt;`)[0];\n",
       "                popup_ca6f584ee383bbb6402b54a14884cdb1.setContent(html_816af84cf133e0e825b270d132d4a032);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_1e7ebd61184dc40a3ba071ec85e3cb34.bindPopup(popup_ca6f584ee383bbb6402b54a14884cdb1)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_dc9d046596930b68a06f9059868f55b5 = L.marker(\n",
       "                [51.507222, -0.1275],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_ebd2aa2207130e18a06b3689c7921914 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_896122cd18669c83e6d638254bfc1821 = $(`&lt;div id=&quot;html_896122cd18669c83e6d638254bfc1821&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Londres&lt;/div&gt;`)[0];\n",
       "                popup_ebd2aa2207130e18a06b3689c7921914.setContent(html_896122cd18669c83e6d638254bfc1821);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_dc9d046596930b68a06f9059868f55b5.bindPopup(popup_ebd2aa2207130e18a06b3689c7921914)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_cbc482a994bb1c37a76f41a30c1fed25 = L.marker(\n",
       "                [-22.909793, -43.176251],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_29ddbf64b285a4c742cd32f3efdec25a = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_73007b8b20e2fab19218360afc88463b = $(`&lt;div id=&quot;html_73007b8b20e2fab19218360afc88463b&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Rio de Janeiro&lt;/div&gt;`)[0];\n",
       "                popup_29ddbf64b285a4c742cd32f3efdec25a.setContent(html_73007b8b20e2fab19218360afc88463b);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_cbc482a994bb1c37a76f41a30c1fed25.bindPopup(popup_29ddbf64b285a4c742cd32f3efdec25a)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_e6576c1340f134e696a0377b557c9704 = L.marker(\n",
       "                [35.689444444444, 139.69166666667],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_c358a9db829fc43f73781fbf24d46d04 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_aaf7dfc57850e4946899ca4d56ad522c = $(`&lt;div id=&quot;html_aaf7dfc57850e4946899ca4d56ad522c&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Tokyo&lt;/div&gt;`)[0];\n",
       "                popup_c358a9db829fc43f73781fbf24d46d04.setContent(html_aaf7dfc57850e4946899ca4d56ad522c);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_e6576c1340f134e696a0377b557c9704.bindPopup(popup_c358a9db829fc43f73781fbf24d46d04)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_7aae7b0276a000b4751cbd28f6310323 = L.marker(\n",
       "                [48.856578, 2.351828],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_f309255bb237b191275cc5fa65da771c = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_a1e998ff8b562982782370be707022dd = $(`&lt;div id=&quot;html_a1e998ff8b562982782370be707022dd&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Paris&lt;/div&gt;`)[0];\n",
       "                popup_f309255bb237b191275cc5fa65da771c.setContent(html_a1e998ff8b562982782370be707022dd);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_7aae7b0276a000b4751cbd28f6310323.bindPopup(popup_f309255bb237b191275cc5fa65da771c)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_20e4578fe9112c4b31eb6dd2981c09bf = L.marker(\n",
       "                [34.05223, -118.24368],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_e6ad219ec151973aab3a7f6f098aeff6 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_7475db54b51a14e26e7ba2d2e15aa9da = $(`&lt;div id=&quot;html_7475db54b51a14e26e7ba2d2e15aa9da&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Los Angeles&lt;/div&gt;`)[0];\n",
       "                popup_e6ad219ec151973aab3a7f6f098aeff6.setContent(html_7475db54b51a14e26e7ba2d2e15aa9da);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_20e4578fe9112c4b31eb6dd2981c09bf.bindPopup(popup_e6ad219ec151973aab3a7f6f098aeff6)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            var marker_908bf5d990ae3dbea0083f798f2db040 = L.marker(\n",
       "                [-27.4667, 153.0334],\n",
       "                {\n",
       "}\n",
       "            ).addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "    \n",
       "        var popup_ce20ced7830771d95183f16b9630ab07 = L.popup({\n",
       "  &quot;maxWidth&quot;: &quot;100%&quot;,\n",
       "});\n",
       "\n",
       "        \n",
       "            \n",
       "                var html_d85e03873e40c255ce50755b0cb957a8 = $(`&lt;div id=&quot;html_d85e03873e40c255ce50755b0cb957a8&quot; style=&quot;width: 100.0%; height: 100.0%;&quot;&gt;Brisbane&lt;/div&gt;`)[0];\n",
       "                popup_ce20ced7830771d95183f16b9630ab07.setContent(html_d85e03873e40c255ce50755b0cb957a8);\n",
       "            \n",
       "        \n",
       "\n",
       "        marker_908bf5d990ae3dbea0083f798f2db040.bindPopup(popup_ce20ced7830771d95183f16b9630ab07)\n",
       "        ;\n",
       "\n",
       "        \n",
       "    \n",
       "    \n",
       "            map_b5187139028cccbdc228bc64fc95a197.fitBounds(\n",
       "                [[-37.81417, -118.24368], [60.170833333333, 153.0334]],\n",
       "                {}\n",
       "            );\n",
       "        \n",
       "    \n",
       "            tile_layer_9de987a7096fc11d0429b7b866bcd47a.addTo(map_b5187139028cccbdc228bc64fc95a197);\n",
       "        \n",
       "&lt;/script&gt;\n",
       "&lt;/html&gt;\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe></div></div>"
      ],
      "text/plain": [
       "<folium.folium.Map at 0x1163535c0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from pathlib import Path\n",
    "\n",
    "import folium\n",
    "from IPython.display import display\n",
    "\n",
    "center = data[[\"latitude\", \"longitude\"]].mean().tolist()\n",
    "\n",
    "m = folium.Map(location=center, zoom_start=2, tiles=\"OpenStreetMap\")\n",
    "\n",
    "for _, city in data.iterrows():\n",
    "    folium.Marker(\n",
    "        [city[\"latitude\"], city[\"longitude\"]],\n",
    "        popup=city[\"name\"],\n",
    "    ).add_to(m)\n",
    "\n",
    "sw = data[[\"latitude\", \"longitude\"]].min().tolist()\n",
    "ne = data[[\"latitude\", \"longitude\"]].max().tolist()\n",
    "m.fit_bounds([sw, ne])\n",
    "\n",
    "Path(\"leaflet\").mkdir(exist_ok=True)\n",
    "m.save(\"leaflet/olympic_cities_map.html\")\n",
    "\n",
    "display(m)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Questions\n",
    "* Do the same for the Winter Olympic Games.\n",
    "* Plot Summer and Winter Olympic cities on the same map, using a different color for each.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exercise 3: Use a REST API with OpenFoodFacts\n",
    "\n",
    "In the previous exercises, we scraped HTML pages. Here we use a REST API: the server returns structured JSON directly.\n",
    "\n",
    "We will use the [OpenFoodFacts API](https://openfoodfacts.github.io/documentation/). It is open and does not require an account for read requests. A good habit is to send a clear `User-Agent` header, so the service can identify educational requests if needed.\n",
    "\n",
    "First check quickly the search documentation: https://openfoodfacts.github.io/documentation/docs/Product-Opener/v2/search/get-search/\n",
    "Use this documentation to understand the code below.\n",
    "\n",
    "Our mini mission: become snack detectives and find which chocolate products in the database look the sweetest.\n",
    "\n",
    "Add comments to check that you understand everything that is going on.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Data loaded from OpenFoodFacts.\n",
      "Number of products: 20\n"
     ]
    }
   ],
   "source": [
    "import json\n",
    "from urllib.error import HTTPError, URLError\n",
    "from urllib.parse import urlencode\n",
    "from urllib.request import Request, urlopen\n",
    "\n",
    "api_url = \"https://world.openfoodfacts.org/api/v2/search\"\n",
    "\n",
    "params = urlencode({\n",
    "    \"categories_tags_en\": \"chocolates\",\n",
    "    \"page_size\": 20,\n",
    "    \"fields\": \"code,product_name,brands,nutriscore_grade,nova_group,nutriments\",\n",
    "})\n",
    "\n",
    "request = Request(\n",
    "    f\"{api_url}?{params}\",\n",
    "    headers={\"User-Agent\": \"DALAS-course/1.0 (student exercise)\"},\n",
    ")\n",
    "\n",
    "try:\n",
    "    with urlopen(request) as response:\n",
    "        results = json.load(response)\n",
    "    print(\"Data loaded from OpenFoodFacts.\")\n",
    "except (HTTPError, URLError) as error:\n",
    "    print(\"OpenFoodFacts is temporarily unavailable. Please run this cell again later.\")\n",
    "    print(error)\n",
    "    results = {\"products\": []}\n",
    "\n",
    "print(\"Number of products:\", len(results[\"products\"]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The response is a Python dictionary. The list of products is stored in `results[\"products\"]`.\n",
    "\n",
    "Each product is also a dictionary, and nutrition values are nested inside the `nutriments` dictionary.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "products = []\n",
    "\n",
    "for product in results[\"products\"]:\n",
    "    nutriments = product.get(\"nutriments\", {})\n",
    "    code = product.get(\"code\")\n",
    "\n",
    "    products.append({\n",
    "        \"name\": product.get(\"product_name\"),\n",
    "        \"brand\": product.get(\"brands\"),\n",
    "        \"nutriscore\": product.get(\"nutriscore_grade\"),\n",
    "        \"nova_group\": product.get(\"nova_group\"),\n",
    "        \"sugars_100g\": nutriments.get(\"sugars_100g\"),\n",
    "        \"fat_100g\": nutriments.get(\"fat_100g\"),\n",
    "        \"energy_kcal_100g\": nutriments.get(\"energy-kcal_100g\"),\n",
    "        \"url\": f\"https://world.openfoodfacts.org/product/{code}\" if code else None,\n",
    "    })\n",
    "\n",
    "columns = [\"name\", \"brand\", \"nutriscore\", \"nova_group\", \"sugars_100g\", \"fat_100g\", \"energy_kcal_100g\", \"url\"]\n",
    "food = pd.DataFrame(products, columns=columns)\n",
    "food.head()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can ask a small data question: among the returned products, which ones have the most sugar per 100g?\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>name</th>\n",
       "      <th>brand</th>\n",
       "      <th>sugars_100g</th>\n",
       "      <th>fat_100g</th>\n",
       "      <th>nutriscore</th>\n",
       "      <th>url</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>Noir 70% Intense</td>\n",
       "      <td>cote d or</td>\n",
       "      <td>56.0</td>\n",
       "      <td>46.5</td>\n",
       "      <td>e</td>\n",
       "      <td>https://world.openfoodfacts.org/product/762240...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>Chocolat au lait</td>\n",
       "      <td>Milka</td>\n",
       "      <td>55.0</td>\n",
       "      <td>31.0</td>\n",
       "      <td>e</td>\n",
       "      <td>https://world.openfoodfacts.org/product/304514...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>Excellence Noir à la Pointe de Fleur de Sel</td>\n",
       "      <td>Lindt EXCELLENCE</td>\n",
       "      <td>47.0</td>\n",
       "      <td>32.0</td>\n",
       "      <td>e</td>\n",
       "      <td>https://world.openfoodfacts.org/product/304692...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>Nestlé dessert Noir</td>\n",
       "      <td>Nestlé, NESTLE DESSERT, Tablettes</td>\n",
       "      <td>46.4</td>\n",
       "      <td>34.0</td>\n",
       "      <td>e</td>\n",
       "      <td>https://world.openfoodfacts.org/product/761303...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>chocolat noir noisettes entieres</td>\n",
       "      <td>cote d\\'or</td>\n",
       "      <td>40.0</td>\n",
       "      <td>39.0</td>\n",
       "      <td>e</td>\n",
       "      <td>https://world.openfoodfacts.org/product/762221...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>Excellence 70% Cocoa Intense Dark</td>\n",
       "      <td>Lindt</td>\n",
       "      <td>30.0</td>\n",
       "      <td>41.0</td>\n",
       "      <td>e</td>\n",
       "      <td>https://world.openfoodfacts.org/product/304692...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Noir Intense</td>\n",
       "      <td>Lindt</td>\n",
       "      <td>30.0</td>\n",
       "      <td>41.0</td>\n",
       "      <td>e</td>\n",
       "      <td>https://world.openfoodfacts.org/product/304692...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>Buo Cioccolato Fondente 70%</td>\n",
       "      <td>Lidl Organic</td>\n",
       "      <td>28.0</td>\n",
       "      <td>41.6</td>\n",
       "      <td>e</td>\n",
       "      <td>https://world.openfoodfacts.org/product/40896243</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>Cioccolato fondente</td>\n",
       "      <td>Jd Gross, chocolat noir</td>\n",
       "      <td>27.2</td>\n",
       "      <td>40.0</td>\n",
       "      <td>e</td>\n",
       "      <td>https://world.openfoodfacts.org/product/20095291</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>Extra Dark 74% Cocoa</td>\n",
       "      <td>Fin Carré</td>\n",
       "      <td>26.0</td>\n",
       "      <td>42.0</td>\n",
       "      <td>e</td>\n",
       "      <td>https://world.openfoodfacts.org/product/20022464</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                           name  \\\n",
       "19                             Noir 70% Intense   \n",
       "11                             Chocolat au lait   \n",
       "16  Excellence Noir à la Pointe de Fleur de Sel   \n",
       "7                           Nestlé dessert Noir   \n",
       "15             chocolat noir noisettes entieres   \n",
       "9             Excellence 70% Cocoa Intense Dark   \n",
       "1                                  Noir Intense   \n",
       "13                  Buo Cioccolato Fondente 70%   \n",
       "10                          Cioccolato fondente   \n",
       "6                          Extra Dark 74% Cocoa   \n",
       "\n",
       "                                brand  sugars_100g  fat_100g nutriscore  \\\n",
       "19                          cote d or         56.0      46.5          e   \n",
       "11                              Milka         55.0      31.0          e   \n",
       "16                   Lindt EXCELLENCE         47.0      32.0          e   \n",
       "7   Nestlé, NESTLE DESSERT, Tablettes         46.4      34.0          e   \n",
       "15                         cote d\\'or         40.0      39.0          e   \n",
       "9                               Lindt         30.0      41.0          e   \n",
       "1                               Lindt         30.0      41.0          e   \n",
       "13                       Lidl Organic         28.0      41.6          e   \n",
       "10            Jd Gross, chocolat noir         27.2      40.0          e   \n",
       "6                           Fin Carré         26.0      42.0          e   \n",
       "\n",
       "                                                  url  \n",
       "19  https://world.openfoodfacts.org/product/762240...  \n",
       "11  https://world.openfoodfacts.org/product/304514...  \n",
       "16  https://world.openfoodfacts.org/product/304692...  \n",
       "7   https://world.openfoodfacts.org/product/761303...  \n",
       "15  https://world.openfoodfacts.org/product/762221...  \n",
       "9   https://world.openfoodfacts.org/product/304692...  \n",
       "1   https://world.openfoodfacts.org/product/304692...  \n",
       "13   https://world.openfoodfacts.org/product/40896243  \n",
       "10   https://world.openfoodfacts.org/product/20095291  \n",
       "6    https://world.openfoodfacts.org/product/20022464  "
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sweetest = (\n",
    "    food.dropna(subset=[\"sugars_100g\"])\n",
    "    .sort_values(\"sugars_100g\", ascending=False)\n",
    "    .head(10)\n",
    ")\n",
    "\n",
    "sweetest[[\"name\", \"brand\", \"sugars_100g\", \"fat_100g\", \"nutriscore\", \"url\"]]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Questions\n",
    "\n",
    "* Change `categories_tags_en` to another category: `breakfast-cereals`, `sodas`, `biscuits`, `ice-creams`, or `plant-based-milks`.\n",
    "* Change `page_size` to get more products.\n",
    "* Sort by another column, for example `fat_100g` or `energy_kcal_100g`.\n",
    "* Add one extra field from the API response to the dataframe.\n",
    "* Try to find the product that looks like the best snack: not too much sugar, not too much fat, and a decent Nutri-Score.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Going further"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* To get the full power of an API, you often have to read the documentation. For OpenFoodFacts: https://openfoodfacts.github.io/openfoodfacts-server/api/\n",
    "* Try to use another API. Here is a list of public APIs on many topics: https://github.com/public-apis/public-apis\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  }
 ],
 "metadata": {
  "colab": {
   "authorship_tag": "ABX9TyNG2Abj51Xn36xr00MfsR38",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "dalas (3.13.1)",
   "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.13.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
