{ "cells": [ { "cell_type": "markdown", "id": "810a72e5-6928-47e1-bdbe-5ff5c58cb8b0", "metadata": {}, "source": [ "# Timeline\n", "\n", "[![open_in_colab][colab_badge]][colab_notebook_link]\n", "[![open_in_binder][binder_badge]][binder_notebook_link]\n", "\n", "[colab_badge]: https://colab.research.google.com/assets/colab-badge.svg\n", "[colab_notebook_link]: https://colab.research.google.com/github/foursquare/unfolded-sdk-examples/blob/master/notebooks/05%20-%20Timeline.ipynb\n", "[binder_badge]: https://mybinder.org/badge_logo.svg\n", "[binder_notebook_link]: https://mybinder.org/v2/gh/foursquare/unfolded-sdk-examples/master?urlpath=lab/tree/notebooks/05%20-%20Timeline.ipynb" ] }, { "cell_type": "markdown", "id": "a5890a22-9d6d-4a0b-9e5e-c77ff03881e3", "metadata": {}, "source": [ "Unfolded Studio supports [time playback for temporal analytics](https://docs.unfolded.ai/studio/map-guide/playback). If you have a column in your dataset with temporal data, you can add a filter to it and it will be displayed as an interactive timeline over the map. Unfolded Map SDK makes it possible to control this filter remotely." ] }, { "cell_type": "markdown", "id": "adb056b6", "metadata": {}, "source": [ "## Dependencies\n", "\n", "This notebook requires the following Python dependencies:\n", "\n", "- `unfolded.map-sdk`: The Unfolded Map SDK\n", "- `pandas`: DataFrame library\n", "\n", "If running this notebook in Binder, these dependencies should already be installed. If running in Colab, the next cell will install these dependencies." ] }, { "cell_type": "code", "execution_count": null, "id": "283d65e3", "metadata": {}, "outputs": [], "source": [ "# If in Colab, install this notebook's required dependencies\n", "import sys\n", "if \"google.colab\" in sys.modules:\n", " !pip install 'unfolded.map_sdk>=1.0' pandas" ] }, { "cell_type": "markdown", "id": "43c89777", "metadata": {}, "source": [ "## Imports" ] }, { "cell_type": "code", "execution_count": null, "id": "dbc1433c", "metadata": {}, "outputs": [], "source": [ "from unfolded.map_sdk import create_map\n", "from datetime import datetime\n", "import pandas as pd\n", "from uuid import uuid4" ] }, { "cell_type": "markdown", "id": "a6f57408", "metadata": {}, "source": [ "## Using Map Timelines" ] }, { "cell_type": "markdown", "id": "2ddf92a9-2dfd-45d0-8edf-32cbca14bd0c", "metadata": {}, "source": [ "First, create a map and add data to it:" ] }, { "cell_type": "code", "execution_count": null, "id": "928756e8-94ad-41be-8590-6da1a495c7de", "metadata": {}, "outputs": [], "source": [ "unfolded_map = create_map(height=600)\n", "unfolded_map" ] }, { "cell_type": "code", "execution_count": null, "id": "93c4b4ca-5842-44b5-a8c4-7edf96b64929", "metadata": {}, "outputs": [], "source": [ "url = 'https://raw.githubusercontent.com/foursquare/unfolded-sdk-examples/master/notebooks/data/earthquakes.csv'\n", "df = pd.read_csv(url)\n", "dataset_id = str(uuid4())\n", "unfolded_map.add_dataset({\n", " 'id': dataset_id,\n", " 'label': 'Earthquakes',\n", " 'data': df\n", "})" ] }, { "cell_type": "markdown", "id": "fc3aaf39-3603-4453-8ca4-8b44cfaf099f", "metadata": {}, "source": [ "## Updating timeline range" ] }, { "cell_type": "markdown", "id": "b65d179f-1a0d-4062-865e-26765dd927ee", "metadata": {}, "source": [ "First, let's convert the `DateTime` column to [`datetime`](https://docs.python.org/3/library/datetime.html):" ] }, { "cell_type": "code", "execution_count": null, "id": "8b3640e0-2e21-42bf-990b-caafe6817a93", "metadata": {}, "outputs": [], "source": [ "df['DateTime']= pd.to_datetime(df['DateTime'])" ] }, { "cell_type": "markdown", "id": "a32c191e-8091-401d-85ff-0885b088604b", "metadata": {}, "source": [ "Now we can calculate the time extent:" ] }, { "cell_type": "code", "execution_count": null, "id": "180a1a1a-286c-44ea-a383-2eda3cc7765c", "metadata": {}, "outputs": [], "source": [ "time_extent = [df['DateTime'].min(), df['DateTime'].max()]\n", "time_extent" ] }, { "cell_type": "markdown", "id": "8e774952-8f2b-4258-a449-79ea61a9e120", "metadata": {}, "source": [ "Here we add a `DateTime` filter to the map:" ] }, { "cell_type": "code", "execution_count": null, "id": "fc2754e3-2987-43ec-9cdf-65b3994bacae", "metadata": {}, "outputs": [], "source": [ "unfolded_map.add_filter({\n", " 'id': 'time-filter',\n", " 'sources': [\n", " {\n", " 'data_id': dataset_id,\n", " 'field_name': 'DateTime'\n", " }\n", " ], \n", " 'value': [\n", " time_extent[0].timestamp() * 1000,\n", " time_extent[1].timestamp() * 1000,\n", " ]\n", "})" ] }, { "cell_type": "markdown", "id": "ab62fa3e-a2c5-4f12-a80c-0c480f44846d", "metadata": {}, "source": [ "Once you execute the above, you should see the timeline appear in the map." ] }, { "cell_type": "markdown", "id": "c63803fb-d64b-48f2-bdfd-60d21b00e6ce", "metadata": {}, "source": [ "## Controlling the timeline" ] }, { "cell_type": "markdown", "id": "c42016a8-3312-423c-9ceb-73c5b1aafb6b", "metadata": {}, "source": [ "Once we have added the timeline filter we can use [`update_timeline()`](https://docs.unfolded.ai/map-sdk-v1/api/update-timeline) to change attributes of the timeline itself (separate from the filter). We use the same filter id to refer to it:" ] }, { "cell_type": "code", "execution_count": null, "id": "0cbdbbb0-40b1-4cff-b43f-e29592a65b3b", "metadata": { "tags": [] }, "outputs": [], "source": [ "unfolded_map.update_timeline(\n", " 'time-filter',\n", " time_format='YYYY-MM-DD',\n", " view='minified',\n", ")" ] }, { "cell_type": "markdown", "id": "15bcf5f3-0838-4dff-b2d0-be3ce8b109d9", "metadata": {}, "source": [ "## Animating the timeline" ] }, { "cell_type": "markdown", "id": "f2bddd94-3936-4efb-a634-529bd049db84", "metadata": {}, "source": [ "Let's first set the timeline to a narrower range:" ] }, { "cell_type": "code", "execution_count": null, "id": "9284bf14-ec3a-4b42-9b86-ea5e25dc813c", "metadata": { "tags": [] }, "outputs": [], "source": [ "unfolded_map.update_filter(\n", " 'time-filter',\n", " value = (\n", " datetime(1967,1,1).timestamp() * 1000,\n", " datetime(1968,1,1).timestamp() * 1000\n", " )\n", ")" ] }, { "cell_type": "markdown", "id": "a0035cb8-e303-4c89-b062-a7b769b89fb1", "metadata": {}, "source": [ "Now we can start the animation:" ] }, { "cell_type": "code", "execution_count": null, "id": "0e2a50f3-8b25-41ce-84c5-757cd97ea524", "metadata": {}, "outputs": [], "source": [ "unfolded_map.update_timeline(\n", " 'time-filter',\n", " is_animating=True,\n", " animation_speed=1\n", ")" ] }, { "cell_type": "markdown", "id": "06ab8cf8-e2e5-4111-96c1-d34d3ff2a790", "metadata": {}, "source": [ "We can also take the timeline off the map and put it in the side panel:" ] }, { "cell_type": "code", "execution_count": null, "id": "01f01b74-19d5-4942-b837-23ded2c4a361", "metadata": {}, "outputs": [], "source": [ "unfolded_map.update_timeline(\n", " 'time-filter',\n", " view='side',\n", ")" ] }, { "cell_type": "markdown", "id": "4e672f25-83dc-4ca9-bdb9-8a248620c81c", "metadata": {}, "source": [ "Now let's stop the animation and display the timeline back on the main map:" ] }, { "cell_type": "code", "execution_count": null, "id": "e455eaa5-0389-4397-965a-ada73fcccf94", "metadata": {}, "outputs": [], "source": [ "unfolded_map.update_timeline(\n", " 'time-filter',\n", " is_animating=False,\n", " view='enlarged',\n", ")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.8.10" } }, "nbformat": 4, "nbformat_minor": 5 }