{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "[En français](../use-case_arthur_fr/) \n", "\n", "![ECCC logo](https://eccc-msc.github.io/open-data/img_eccc-logo.png) \n", "\n", "[TOC](https://eccc-msc.github.io/open-data/readme_en/) > [Usage overview](https://eccc-msc.github.io/open-data/usage/readme_en/) > WMS request in Python\n", "\n", "# Use case: anticipated profits based on precipitations probability\n", "\n", "## Introduction\n", "\n", "Weather, climate and water data from [MSC GeoMet](https://eccc-msc.github.io/open-data/msc-geomet/readme_en/) geospatial web services can be easily used to predict demand associated with certain products or services. This usage example show how to extract and process raw meteorological data with [Python](https://www.python.org/) programming language to create a tool to calculate anticipated profits from sales depending on meteorological conditions. This use case teaches you how to:\n", "* Access and query meteorological data from MSC GeoMet geospatial web services;\n", "* Query layers to get data for specific locations;\n", "* Create temporal queries;\n", "* Show results in different formats including plots and data tables.\n", "\n", "The [interactive version of this Jupyter Notebook is available](https://mybinder.org/v2/gh/ECCC-MSC/open-data/master?filepath=docs%2Fusage%2Fuse-case_arthur%2Fuse-case_arthur_en.ipynb).\n", "\n", "[![badge](https://img.shields.io/badge/Interactive%20version-binder-F5A252.svg?logo=data:image/png;base64,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)](https://mybinder.org/v2/gh/ECCC-MSC/open-data/master?filepath=docs%2Fusage%2Fuse-case_arthur%2Fuse-case_arthur_en.ipynb)\n", "\n", "## Creation of a tool to calculate anticipated profits\n", "\n", "Consider the following situation: Arthur, a souvenir kiosk owner in Vancouver, wants to calculate the profits he anticipates making from umbrellas sales using Environment and Climate Change Canada weather forecast. Indeed, his umbrellas sales increase drastically when there is at least 30% chance that there will be a minimum of 5 mm of precipitations. Considering that the kiosk is open from 9 a.m. to 9 p.m, Arthur wants to calculate how much profits he anticipates to make in the following days according to the weather forecast obtained from MSC GeoMet geospatial web services.\n", "\n", "To determinate the amount of umbrellas that is predicted to be sold in the next days, the first step is to query the [Web Map Service (WMS)](https://eccc-msc.github.io/open-data/msc-geomet/web-services_en/#web-map-service-wms) from MSC to get the probability of getting 5 mm or more of precipitations for the time, the date and the location desired through Python programming. To carry out this step, the Python modules must first be imported and values must be given to the request parameters including the layer name, the coordinates of the location and the local time zone. The layer used for this exemple will be the layer from the [Regional Ensemble Prediction System (REPS)](https://eccc-msc.github.io/open-data/msc-data/nwp_reps/readme_reps_en/) that contains the probability that the quantity of precipitations will be equal or greater than 5 mm (``REPS.DIAG.3_PRMM.ERGE5``)." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# Importation of Python modules \n", "from datetime import datetime, timedelta\n", "import re\n", "import warnings\n", "\n", "# The following modules must first be installed to use \n", "# this code out of Jupyter Notebook\n", "import matplotlib.pyplot as plt\n", "import matplotlib.dates as mdates\n", "import numpy\n", "from owslib.wms import WebMapService\n", "import pandas\n", "from tabulate import tabulate\n", "\n", "# Ignore warnings from the OWSLib module\n", "warnings.filterwarnings('ignore', module='owslib', category=UserWarning)\n", "\n", "# Parameters choice\n", "# Layer:\n", "layer = 'REPS.DIAG.3_PRMM.ERGE5'\n", "# Coordinates:\n", "y, x = 49.288, -123.116\n", "# Local time zone (in this exemple, the local time zone is UTC-07:00):\n", "time_zone = -7" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once the parameters are chosen, the request's ``bbox`` parameter values (location aimed by the query) have to be calculated." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "# bbox parameter\n", "min_x, min_y, max_x, max_y = x - 0.25, y - 0.25, x + 0.25, y + 0.25" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To access the layer metadata, the connection to the WMS service has to be established." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# WMS service connection\n", "wms = WebMapService('https://geo.weather.gc.ca/geomet?SERVICE=WMS' +\n", " '&REQUEST=GetCapabilities',\n", " version='1.3.0',\n", " timeout=300)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The starting and ending time of the available predictions and the time interval between available predictions can be recovered with a ``GetCapabilities`` request. In this request, ``dimensions`` refers to the homonymous section in the layer's metadata that contains temporal information. As ``dimensions`` is a Python dictionary, it is possible to recover the necessary information using dictionary keys and the ``split`` method to split character chains around the slash symbol. For the time interval, the numbers can be recovered with the ``re.sub`` method that replace all the characters that are not numerical with empty space.\n", "\n", "Then, the time and date of all available predictions from the starting time to the ending time for the UTC±00:00 time zone can be obtained with a ``while`` loop. Theses informations are necessary to carry out the WMS request. The same ``while`` loop will be used to get the local time and date of all the predictions. The local time and date will be used in the plots and data tables in order to facilitate the result interpretation. " ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# Extraction of temporal information from metadata\n", "def time_parameters(layer):\n", " start_time, end_time, interval = (wms[layer]\n", " .dimensions['time']['values'][0]\n", " .split('/')\n", " )\n", " iso_format = '%Y-%m-%dT%H:%M:%SZ'\n", " start_time = datetime.strptime(start_time, iso_format)\n", " end_time = datetime.strptime(end_time, iso_format)\n", " interval = int(re.sub(r'\\D', '', interval))\n", " return start_time, end_time, interval\n", "\n", "\n", "start_time, end_time, interval = time_parameters(layer)\n", "\n", "# To use specific starting and ending time, remove the #\n", "# from the next lines and replace the start_time and\n", "# end_time with the desired values:\n", "# start_time = 'YYYY-MM-DDThh:00'\n", "# end_time = 'YYYY-MM-DDThh:00'\n", "# fmt = '%Y-%m-%dT%H:%M'\n", "# start_time = datetime.strptime(start_time, fmt) - timedelta(hours=time_zone)\n", "# end_time = datetime.strptime(end_time, fmt) - timedelta(hours=time_zone)\n", "\n", "# Calculation of date and time for available predictions\n", "# (the time variable represents time at UTC±00:00)\n", "time = [start_time]\n", "local_time = [start_time + timedelta(hours=time_zone)]\n", "while time[-1] < end_time:\n", " time.append(time[-1] + timedelta(hours=interval))\n", " local_time.append(time[-1] + timedelta(hours=time_zone))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The WMS service can now be queried. To get the probability of getting 5 mm or more of precipitations for each available prediction, a ``for`` loop is used to query the WMS service with each prediction time and date as parameters. As the results of the request contains different informations, the probability has to be recovered from the results. To achieve this, [regular expressions](https://en.wikipedia.org/wiki/Regular_expression) (``re`` module) can be used to find a character chain. Regular expressions, also called regex, are expressions that describe a search pattern. In this use case exemple, the regex used are ``\\s`` (whitespace character), ``\\d`` (numerical characters), ``*`` (0 or more characters from the regex present before it) et ``+`` (1 or more characters from the regex present before it). Using the ``re.findall`` methods, all the the character chains corresponding to the regex expression given will be extracted. The ``re.sub`` and ``strip`` methods will also be used to remove the characters present around the value we are looking for." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "scrolled": false }, "outputs": [], "source": [ "# Loop to carry out the requests and extract the probabilities\n", "def request(layer): \n", " info = []\n", " pixel_value = []\n", " for timestep in time:\n", " # WMS GetFeatureInfo query\n", " info.append(wms.getfeatureinfo(layers=[layer],\n", " srs='EPSG:4326',\n", " bbox=(min_x, min_y, max_x, max_y),\n", " size=(100, 100),\n", " format='image/jpeg',\n", " query_layers=[layer],\n", " info_format='text/plain',\n", " xy=(50, 50),\n", " feature_count=1,\n", " time=str(timestep.isoformat()) + 'Z'\n", " ))\n", " # Probability extraction from the request's results\n", " text = info[-1].read().decode('utf-8')\n", " pixel_value.append(str(re.findall(r'value_0\\s+\\d*.*\\d+', text)))\n", " pixel_value[-1] = float(\n", " re.sub('value_0 = \\'', '', pixel_value[-1])\n", " .strip('[\"\"]')\n", " )\n", " \n", " return pixel_value\n", "\n", "pixel_value = request(layer)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The probabilities obtained can be visualised with an interactive plot made with the ``matplotlib`` module that can be easily exported. With Jupyter Notebook, the interactive components can be activated with the magic command ``%matplotlib notebook``." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "scrolled": false }, "outputs": [ { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "window.mpl = {};\n", "\n", "\n", "mpl.get_websocket_type = function() {\n", " if (typeof(WebSocket) !== 'undefined') {\n", " return WebSocket;\n", " } else if (typeof(MozWebSocket) !== 'undefined') {\n", " return MozWebSocket;\n", " } else {\n", " alert('Your browser does not have WebSocket support. ' +\n", " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", " 'Firefox 4 and 5 are also supported but you ' +\n", " 'have to enable WebSockets in about:config.');\n", " };\n", "}\n", "\n", "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", " this.id = figure_id;\n", "\n", " this.ws = websocket;\n", "\n", " this.supports_binary = (this.ws.binaryType != undefined);\n", "\n", " if (!this.supports_binary) {\n", " var warnings = document.getElementById(\"mpl-warnings\");\n", " if (warnings) {\n", " warnings.style.display = 'block';\n", " warnings.textContent = (\n", " \"This browser does not support binary websocket messages. \" +\n", " \"Performance may be slow.\");\n", " }\n", " }\n", "\n", " this.imageObj = new Image();\n", "\n", " this.context = undefined;\n", " this.message = undefined;\n", " this.canvas = undefined;\n", " this.rubberband_canvas = undefined;\n", " this.rubberband_context = undefined;\n", " this.format_dropdown = undefined;\n", "\n", " this.image_mode = 'full';\n", "\n", " this.root = $('
');\n", " this._root_extra_style(this.root)\n", " this.root.attr('style', 'display: inline-block');\n", "\n", " $(parent_element).append(this.root);\n", "\n", " this._init_header(this);\n", " this._init_canvas(this);\n", " this._init_toolbar(this);\n", "\n", " var fig = this;\n", "\n", " this.waiting = false;\n", "\n", " this.ws.onopen = function () {\n", " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", " fig.send_message(\"send_image_mode\", {});\n", " if (mpl.ratio != 1) {\n", " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", " }\n", " fig.send_message(\"refresh\", {});\n", " }\n", "\n", " this.imageObj.onload = function() {\n", " if (fig.image_mode == 'full') {\n", " // Full images could contain transparency (where diff images\n", " // almost always do), so we need to clear the canvas so that\n", " // there is no ghosting.\n", " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", " }\n", " fig.context.drawImage(fig.imageObj, 0, 0);\n", " };\n", "\n", " this.imageObj.onunload = function() {\n", " fig.ws.close();\n", " }\n", "\n", " this.ws.onmessage = this._make_on_message_function(this);\n", "\n", " this.ondownload = ondownload;\n", "}\n", "\n", "mpl.figure.prototype._init_header = function() {\n", " var titlebar = $(\n", " '
');\n", " var titletext = $(\n", " '
');\n", " titlebar.append(titletext)\n", " this.root.append(titlebar);\n", " this.header = titletext[0];\n", "}\n", "\n", "\n", "\n", "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "\n", "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "mpl.figure.prototype._init_canvas = function() {\n", " var fig = this;\n", "\n", " var canvas_div = $('
');\n", "\n", " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", "\n", " function canvas_keyboard_event(event) {\n", " return fig.key_event(event, event['data']);\n", " }\n", "\n", " canvas_div.keydown('key_press', canvas_keyboard_event);\n", " canvas_div.keyup('key_release', canvas_keyboard_event);\n", " this.canvas_div = canvas_div\n", " this._canvas_extra_style(canvas_div)\n", " this.root.append(canvas_div);\n", "\n", " var canvas = $('');\n", " canvas.addClass('mpl-canvas');\n", " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", "\n", " this.canvas = canvas[0];\n", " this.context = canvas[0].getContext(\"2d\");\n", "\n", " var backingStore = this.context.backingStorePixelRatio ||\n", "\tthis.context.webkitBackingStorePixelRatio ||\n", "\tthis.context.mozBackingStorePixelRatio ||\n", "\tthis.context.msBackingStorePixelRatio ||\n", "\tthis.context.oBackingStorePixelRatio ||\n", "\tthis.context.backingStorePixelRatio || 1;\n", "\n", " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", "\n", " var rubberband = $('');\n", " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", "\n", " var pass_mouse_events = true;\n", "\n", " canvas_div.resizable({\n", " start: function(event, ui) {\n", " pass_mouse_events = false;\n", " },\n", " resize: function(event, ui) {\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " stop: function(event, ui) {\n", " pass_mouse_events = true;\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " });\n", "\n", " function mouse_event_fn(event) {\n", " if (pass_mouse_events)\n", " return fig.mouse_event(event, event['data']);\n", " }\n", "\n", " rubberband.mousedown('button_press', mouse_event_fn);\n", " rubberband.mouseup('button_release', mouse_event_fn);\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " rubberband.mousemove('motion_notify', mouse_event_fn);\n", "\n", " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", "\n", " canvas_div.on(\"wheel\", function (event) {\n", " event = event.originalEvent;\n", " event['data'] = 'scroll'\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " mouse_event_fn(event);\n", " });\n", "\n", " canvas_div.append(canvas);\n", " canvas_div.append(rubberband);\n", "\n", " this.rubberband = rubberband;\n", " this.rubberband_canvas = rubberband[0];\n", " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", " this.rubberband_context.strokeStyle = \"#000000\";\n", "\n", " this._resize_canvas = function(width, height) {\n", " // Keep the size of the canvas, canvas container, and rubber band\n", " // canvas in synch.\n", " canvas_div.css('width', width)\n", " canvas_div.css('height', height)\n", "\n", " canvas.attr('width', width * mpl.ratio);\n", " canvas.attr('height', height * mpl.ratio);\n", " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", "\n", " rubberband.attr('width', width);\n", " rubberband.attr('height', height);\n", " }\n", "\n", " // Set the figure to an initial 600x600px, this will subsequently be updated\n", " // upon first draw.\n", " this._resize_canvas(600, 600);\n", "\n", " // Disable right mouse context menu.\n", " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", " return false;\n", " });\n", "\n", " function set_focus () {\n", " canvas.focus();\n", " canvas_div.focus();\n", " }\n", "\n", " window.setTimeout(set_focus, 100);\n", "}\n", "\n", "mpl.figure.prototype._init_toolbar = function() {\n", " var fig = this;\n", "\n", " var nav_element = $('
');\n", " nav_element.attr('style', 'width: 100%');\n", " this.root.append(nav_element);\n", "\n", " // Define a callback function for later on.\n", " function toolbar_event(event) {\n", " return fig.toolbar_button_onclick(event['data']);\n", " }\n", " function toolbar_mouse_event(event) {\n", " return fig.toolbar_button_onmouseover(event['data']);\n", " }\n", "\n", " for(var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " // put a spacer in here.\n", " continue;\n", " }\n", " var button = $('');\n", " button.click(method_name, toolbar_event);\n", " button.mouseover(tooltip, toolbar_mouse_event);\n", " nav_element.append(button);\n", " }\n", "\n", " // Add the status bar.\n", " var status_bar = $('');\n", " nav_element.append(status_bar);\n", " this.message = status_bar[0];\n", "\n", " // Add the close button to the window.\n", " var buttongrp = $('
');\n", " var button = $('');\n", " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", " buttongrp.append(button);\n", " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", " titlebar.prepend(buttongrp);\n", "}\n", "\n", "mpl.figure.prototype._root_extra_style = function(el){\n", " var fig = this\n", " el.on(\"remove\", function(){\n", "\tfig.close_ws(fig, {});\n", " });\n", "}\n", "\n", "mpl.figure.prototype._canvas_extra_style = function(el){\n", " // this is important to make the div 'focusable\n", " el.attr('tabindex', 0)\n", " // reach out to IPython and tell the keyboard manager to turn it's self\n", " // off when our div gets focus\n", "\n", " // location in version 3\n", " if (IPython.notebook.keyboard_manager) {\n", " IPython.notebook.keyboard_manager.register_events(el);\n", " }\n", " else {\n", " // location in version 2\n", " IPython.keyboard_manager.register_events(el);\n", " }\n", "\n", "}\n", "\n", "mpl.figure.prototype._key_event_extra = function(event, name) {\n", " var manager = IPython.notebook.keyboard_manager;\n", " if (!manager)\n", " manager = IPython.keyboard_manager;\n", "\n", " // Check for shift+enter\n", " if (event.shiftKey && event.which == 13) {\n", " this.canvas_div.blur();\n", " // select the cell after this one\n", " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", " IPython.notebook.select(index + 1);\n", " }\n", "}\n", "\n", "mpl.figure.prototype.handle_save = function(fig, msg) {\n", " fig.ondownload(fig, null);\n", "}\n", "\n", "\n", "mpl.find_output_cell = function(html_output) {\n", " // Return the cell and output element which can be found *uniquely* in the notebook.\n", " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", " // IPython event is triggered only after the cells have been serialised, which for\n", " // our purposes (turning an active figure into a static one), is too late.\n", " var cells = IPython.notebook.get_cells();\n", " var ncells = cells.length;\n", " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", " data = data.data;\n", " }\n", " if (data['text/html'] == html_output) {\n", " return [cell, data, j];\n", " }\n", " }\n", " }\n", " }\n", "}\n", "\n", "// Register the function which deals with the matplotlib target/channel.\n", "// The kernel may be null if the page has been refreshed.\n", "if (IPython.notebook.kernel != null) {\n", " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", "}\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Create and show plot\n", "fig(x=local_time,\n", " y=pixel_value,\n", " title=('Anticipated profits from umbrellas sales ' +\n", " 'depending\\non precipitations probability'),\n", " xlabel='\\nDate and time',\n", " ylabel='Probability of getting 5 mm\\nor more of precipitations (%)',\n", " ylim=(-10, 110),\n", " y2=cumulative_profit,\n", " y2label='Cumulative anticipated profits ($)'\n", " )\n", "\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cumulative anticipated profits can also be show in a data table that can be exported in CSV format if desired." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Anticipated profits from umbrellas sales depending on precipitations probability\n", "+---------------------+-----------------+------------------------------------+\n", "| Local date and time | Probability (%) | Anticipated cumulative profits ($) |\n", "+---------------------+-----------------+------------------------------------+\n", "| 2021-01-11 11:00:00 | 25.0 | 30.0 |\n", "| 2021-01-11 14:00:00 | 0.0 | 30.0 |\n", "| 2021-01-11 17:00:00 | 5.0 | 30.0 |\n", "| 2021-01-11 20:00:00 | 30.0 | 30.0 |\n", "| 2021-01-12 11:00:00 | 65.0 | 660.0 |\n", "| 2021-01-12 14:00:00 | 50.0 | 1140.0 |\n", "| 2021-01-12 17:00:00 | 60.0 | 1710.0 |\n", "| 2021-01-12 20:00:00 | 50.0 | 2190.0 |\n", "| 2021-01-13 11:00:00 | 0.0 | 2220.0 |\n", "| 2021-01-13 14:00:00 | 0.0 | 2220.0 |\n", "| 2021-01-13 17:00:00 | 0.0 | 2220.0 |\n", "| 2021-01-13 20:00:00 | 0.0 | 2220.0 |\n", "+---------------------+-----------------+------------------------------------+\n" ] } ], "source": [ "# Probability of precipitations and cumulative\n", "# profits only within open hours\n", "probability = []\n", "profit = []\n", "for index, timestep in enumerate(local_time):\n", " if timestep in open_hours:\n", " probability.append(pixel_value[index])\n", " profit.append(cumulative_profit[index])\n", "\n", "# Create table\n", "profit_df = pandas.DataFrame({'Local date and time': open_hours,\n", " 'Probability (%)': probability,\n", " 'Anticipated cumulative profits ($)': profit\n", " })\n", "\n", "# Show table\n", "print('Anticipated profits from umbrellas sales ' +\n", " 'depending on precipitations probability')\n", "print(tabulate(profit_df,\n", " headers='keys',\n", " tablefmt='pretty',\n", " showindex=False))\n", "\n", "# Save in CSV format (remove # from the following lines)\n", "# profit_df.to_csv('profit.csv',\n", "# sep=';',\n", "# index=False,\n", "# encoding='utf-8-sig')\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Conclusion\n", "\n", "Using this tool, Arthur will have an insight of the profits he could make with umbrellas sales in the next days. After reading this use case exemple, you should be able to use Python programming to access and query a WMS service, create temporal queries and show the results using plots and data tables. You can adapt this exemple to fit your needs by changing the request parameters and the data processing steps." ] } ], "metadata": { "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.7.4" } }, "nbformat": 4, "nbformat_minor": 4 }