Skip to content

Instantly share code, notes, and snippets.

@vincentsarago
Last active September 5, 2018 17:32
Show Gist options
  • Save vincentsarago/c2144bbdb9002795d0c3c7a7389989fc to your computer and use it in GitHub Desktop.
Save vincentsarago/c2144bbdb9002795d0c3c7a7389989fc to your computer and use it in GitHub Desktop.

Run live tile processing and display on Jupyter Notbook

Install

pip install numpy
pip install rasterio[s3]

pip install rio-glui mapboxgl opencv-python scipy

Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"from rio_glui.server import TileServer\n",
"from rio_glui.raster import RasterTiles\n",
"\n",
"from mapboxgl.utils import *\n",
"from mapboxgl.viz import *"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"token = os.getenv('MAPBOX_ACCESS_TOKEN')"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"file = 'https://oin-hotosm.s3.amazonaws.com/5ac626e091b5310010e0d482/0/5ac626e091b5310010e0d483.tif'"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"import mercantile\n",
"import numpy\n",
"\n",
"import cv2\n",
"from scipy.ndimage.morphology import binary_dilation\n",
"from rasterio.plot import reshape_as_image\n",
"from rio_tiler.utils import tile_read\n",
"\n",
"\n",
"# https://github.com/mapbox/rio-glui/blob/master/rio_glui/raster.py#L148-L158\n",
"class customRaster(RasterTiles):\n",
" def read_tile(self, z, x, y):\n",
" \"\"\"Read raster tile data and mask.\"\"\"\n",
" mercator_tile = mercantile.Tile(x=x, y=y, z=z)\n",
" tile_bounds = mercantile.xy_bounds(mercator_tile)\n",
"\n",
" data, mask = tile_read(\n",
" self.path,\n",
" tile_bounds,\n",
" self.tiles_size,\n",
" indexes=self.indexes,\n",
" nodata=self.nodata,\n",
" )\n",
"\n",
" #################################\n",
" # apply your custom function here\n",
" # Extract Linear Features\n",
" # https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_houghlines/py_houghlines.html\n",
" img = reshape_as_image(data)\n",
" gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n",
" edges = cv2.Canny(gray, 50, 100)\n",
"\n",
" # Edges dilation for visual\n",
" edges = binary_dilation(edges).astype(numpy.uint8) * 255\n",
" \n",
" data[0, edges > 0] = 255\n",
" \n",
" return data, mask"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"raster = customRaster(file, indexes=(1,2,3))\n",
"ts = TileServer(raster)\n",
"ts.start()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<iframe id=\"map\", srcdoc=\"<!DOCTYPE html>\n",
"<html>\n",
"<head>\n",
"<title>mapboxgl-jupyter viz</title>\n",
"<meta charset='UTF-8' />\n",
"<meta name='viewport'\n",
" content='initial-scale=1,maximum-scale=1,user-scalable=no' />\n",
"<script type='text/javascript'\n",
" src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.47.0/mapbox-gl.js'></script>\n",
"<link type='text/css'\n",
" href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.47.0/mapbox-gl.css' \n",
" rel='stylesheet' />\n",
"\n",
"<style type='text/css'>\n",
" body { margin:0; padding:0; }\n",
" .map { position: absolute; top:0; bottom:0; width:100%; }\n",
" .legend {\n",
" background-color: white;\n",
" color: #6e6e6e;\n",
" border-radius: 3px;\n",
" bottom: 10px;\n",
" box-shadow: 0 1px 2px rgba(0, 0, 0, 0.10);\n",
" font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;\n",
" padding: 0;\n",
" position: absolute;\n",
" right: 10px;\n",
" z-index: 1;\n",
" min-width: 100px;\n",
" }\n",
" .legend.horizontal {bottom: 10px; text-align: left;}\n",
"\n",
" /* legend header */\n",
" .legend .legend-header { border-radius: 3px 3px 0 0; background: white; }\n",
" .legend .legend-title {\n",
" padding: 6px 12px 6px 12px;\n",
" text-shadow: 0 0 2px white;\n",
" text-transform: capitalize;\n",
" text-align: center;\n",
" font-weight: bold !important;\n",
" font-size: 14px;\n",
" font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;\n",
" max-width: 160px;\n",
" }\n",
" .legend-title {padding: 6px 12px 6px 12px; text-shadow: 0 0 2px #FFF; text-transform: capitalize; text-align: center; max-width: 160px; font-size: 0.9em; font-weight: bold;}\n",
" .legend.horizontal .legend-title {text-align: left;}\n",
"\n",
" /* legend items */\n",
" .legend-content {margin: 6px 12px 6px 12px; overflow: hidden; padding: 0; float: left; list-style: none; font-size: 0.8em;}\n",
" .legend.vertical .legend-item {white-space: nowrap;}\n",
" .legend-value {display: inline-block; line-height: 18px; vertical-align: top;}\n",
" .legend.horizontal ul.legend-content li.legend-item .legend-value,\n",
" .legend.horizontal ul.legend-content li.legend-item {display: inline-block; float: left; width: 30px; margin-bottom: 0; text-align: center; height: 30px;}\n",
"\n",
" /* legend key styles */\n",
" .legend-key {display: inline-block; height: 10px;}\n",
" .legend-key.default, .legend-key.square {border-radius: 0;}\n",
" .legend-key.circle {border-radius: 50%;}\n",
" .legend-key.rounded-square {border-radius: 20%;}\n",
" .legend.vertical .legend-key {width: 10px; margin-right: 5px; margin-left: 1px;}\n",
" .legend.horizontal .legend-key {width: 30px; margin-right: 0; margin-top: 1px; float: left;}\n",
" .legend.horizontal .legend-key.square, .legend.horizontal .legend-key.rounded-square, .legend.horizontal .legend-key.circle {margin-left: 10px; width: 10px;}\n",
" .legend.horizontal .legend-key.line {margin-left: 5px;}\n",
" .legend.horizontal .legend-key.line, .legend.vertical .legend-key.line {border-radius: 10%; width: 20px; height: 3px; margin-bottom: 2px;}\n",
"\n",
" /* gradient bar alignment */\n",
" .gradient-bar {margin: 6px 12px 6px 12px;}\n",
" .legend.horizontal .gradient-bar {width: 88%; height: 10px;}\n",
" .legend.vertical .gradient-bar {width: 10px; min-height: 50px; position: absolute; bottom: 4px;}\n",
"\n",
" /* contiguous vertical bars (discrete) */\n",
" .legend.vertical.contig .legend-key {height: 15px; width: 10px;}\n",
" .legend.vertical.contig li.legend-item {height: 15px;}\n",
" .legend.vertical.contig {padding-bottom: 6px;}\n",
"\n",
"</style>\n",
"\n",
"</head>\n",
"<body>\n",
"\n",
"<div id='map' class='map'></div>\n",
"\n",
"<script type='text/javascript'>\n",
"\n",
"var legendHeader;\n",
"\n",
"function calcColorLegend(myColorStops, title) {\n",
"\n",
" // create legend\n",
" var legend = document.createElement('div');\n",
" if ('square' === 'contiguous-bar') {\n",
" legend.className = 'legend vertical contig';\n",
" }\n",
" else {\n",
" legend.className = 'legend vertical';\n",
" }\n",
"\n",
" legend.id = 'legend';\n",
" document.body.appendChild(legend);\n",
"\n",
" // add legend header and content elements\n",
" var mytitle = document.createElement('div'),\n",
" legendContent = document.createElement('ul');\n",
" legendHeader = document.createElement('div');\n",
" mytitle.textContent = title;\n",
" mytitle.className = 'legend-title'\n",
" legendHeader.className = 'legend-header'\n",
" legendContent.className = 'legend-content'\n",
" legendHeader.appendChild(mytitle);\n",
" legend.appendChild(legendHeader);\n",
" legend.appendChild(legendContent);\n",
"\n",
" if (false === true) {\n",
" var gradientText = 'linear-gradient(to right, ';\n",
" var gradient = document.createElement('div');\n",
" gradient.className = 'gradient-bar';\n",
" legend.appendChild(gradient);\n",
" }\n",
"\n",
" // calculate a legend entries on a Mapbox GL Style Spec property function stops array\n",
" for (p = 0; p < myColorStops.length; p++) {\n",
" if (!!document.getElementById('legend-points-value-' + p)) {\n",
" //update the legend if it already exists\n",
" document.getElementById('legend-points-value-' + p).textContent = myColorStops[p][0];\n",
" document.getElementById('legend-points-id-' + p).style.backgroundColor = myColorStops[p][1];\n",
" }\n",
" else {\n",
" // create the legend if it doesn't yet exist\n",
" var item = document.createElement('li');\n",
" item.className = 'legend-item';\n",
"\n",
" var key = document.createElement('span');\n",
" key.className = 'legend-key square';\n",
" key.id = 'legend-points-id-' + p;\n",
" key.style.backgroundColor = myColorStops[p][1]; \n",
"\n",
" var value = document.createElement('span');\n",
" value.className = 'legend-value';\n",
" value.id = 'legend-points-value-' + p;\n",
"\n",
" item.appendChild(key);\n",
" item.appendChild(value);\n",
" legendContent.appendChild(item);\n",
" \n",
" data = document.getElementById('legend-points-value-' + p)\n",
"\n",
" // round number values in legend if precision defined\n",
" if ((typeof(myColorStops[p][0]) == 'number') && (typeof(null) == 'number')) {\n",
" data.textContent = myColorStops[p][0].toFixed(null);\n",
" }\n",
" else {\n",
" data.textContent = myColorStops[p][0];\n",
" }\n",
"\n",
" // add color stop to gradient list\n",
" if (false === true) {\n",
" if (p < myColorStops.length - 1) {\n",
" gradientText = gradientText + myColorStops[p][1] + ', ';\n",
" }\n",
" else {\n",
" gradientText = gradientText + myColorStops[p][1] + ')';\n",
" }\n",
" if ('vertical' === 'vertical') {\n",
" gradientText = gradientText.replace('to right', 'to bottom');\n",
" }\n",
" }\n",
" }\n",
" }\n",
"\n",
" if (false === true) {\n",
" // convert to gradient scale appearance\n",
" gradient.style.background = gradientText;\n",
"\n",
" // hide legend keys generated above\n",
" var keys = document.getElementsByClassName('legend-key');\n",
" for (var i=0; i < keys.length; i++) {\n",
" keys[i].style.visibility = 'hidden';\n",
" }\n",
"\n",
" if ('vertical' === 'vertical') {\n",
" gradient.style.height = (legendContent.offsetHeight - 6) + 'px';\n",
" }\n",
" }\n",
"\n",
" // add class for styling bordered legend keys\n",
" if (true) {\n",
" var keys = document.getElementsByClassName('legend-key');\n",
" for (var i=0; i < keys.length; i++) {\n",
" if (keys[i]) {\n",
" keys[i].classList.add('bordered');\n",
" }\n",
" }\n",
" var gradientBars = document.getElementsByClassName('gradient-bar');\n",
" for (var i=0; i < keys.length; i++) {\n",
" if (gradientBars[i]) {\n",
" gradientBars[i].classList.add('bordered');\n",
" }\n",
" }\n",
" }\n",
"\n",
" // update right-margin for compact Mapbox attribution based on calculated legend width\n",
" var attribMargin = legend.offsetWidth + 15;\n",
" document.getElementsByClassName('mapboxgl-ctrl-attrib')[0].style.marginRight = attribMargin.toString() + 'px';\n",
"\n",
"}\n",
"\n",
"\n",
"function generateInterpolateExpression(propertyValue, stops) {\n",
" var expression;\n",
" if (propertyValue == 'zoom') {\n",
" expression = ['interpolate', ['exponential', 1.2], ['zoom']]\n",
" }\n",
" else if (propertyValue == 'heatmap-density') {\n",
" expression = ['interpolate', ['linear'], ['heatmap-density']]\n",
" }\n",
" else {\n",
" expression = ['interpolate', ['linear'], ['get', propertyValue]]\n",
" }\n",
"\n",
" for (var i=0; i<stops.length; i++) {\n",
" expression.push(stops[i][0], stops[i][1])\n",
" }\n",
" return expression\n",
"}\n",
"\n",
"\n",
"function generateMatchExpression(propertyValue, stops, defaultValue) {\n",
" var expression;\n",
" expression = ['match', ['get', propertyValue]]\n",
" for (var i=0; i<stops.length; i++) {\n",
" expression.push(stops[i][0], stops[i][1])\n",
" }\n",
" expression.push(defaultValue)\n",
" \n",
" return expression\n",
"}\n",
"\n",
"\n",
"function generatePropertyExpression(expressionType, propertyValue, stops, defaultValue) {\n",
" var expression;\n",
" if (expressionType == 'match') {\n",
" expression = generateMatchExpression(propertyValue, stops, defaultValue)\n",
" }\n",
" else {\n",
" expression = generateInterpolateExpression(propertyValue, stops)\n",
" }\n",
"\n",
" return expression\n",
"}\n",
"\n",
"</script>\n",
"\n",
"<!-- main map creation code, extended by mapboxgl/templates/raster.html -->\n",
"<script type='text/javascript'>\n",
"\n",
" mapboxgl.accessToken = 'pk.eyJ1IjoidmluY2VudHNhcmFnbyIsImEiOiJjaXZ2MjlxbWUwMG41MnlwNzNnaGN0a2NmIn0.HxKPljj1_AK5333eBz-YxQ';\n",
"\n",
" var map = new mapboxgl.Map({\n",
" container: 'map',\n",
" attributionControl: false,\n",
" style: 'mapbox://styles/mapbox/light-v9?optimize=true',\n",
" center: [39.3000632136319, -5.756631921716197],\n",
" zoom: 13,\n",
" pitch: 0,\n",
" bearing: 0,\n",
" transformRequest: (url, resourceType) => {\n",
" if ( url.slice(0,22) == 'https://api.mapbox.com' || \n",
" url.slice(0,26) == 'https://a.tiles.mapbox.com' || \n",
" url.slice(0,26) == 'https://b.tiles.mapbox.com' ||\n",
" url.slice(0,26) == 'https://c.tiles.mapbox.com' ||\n",
" url.slice(0,26) == 'https://d.tiles.mapbox.com') {\n",
" //Add Mapboxgl-Jupyter Plugin identifier for Mapbox API traffic\n",
" return {\n",
" url: [url.slice(0, url.indexOf('?')+1), 'pluginName=PythonMapboxgl&', url.slice(url.indexOf('?')+1)].join('')\n",
" }\n",
" }\n",
" else {\n",
" //Do not transform URL for non Mapbox GET requests\n",
" return {url: url}\n",
" }\n",
" },\n",
" });\n",
"\n",
" \n",
" \n",
" map.addControl(new mapboxgl.AttributionControl({ compact: true }));\n",
"\n",
" \n",
"\n",
" \n",
"\n",
" map.addControl(new mapboxgl.NavigationControl());\n",
"\n",
" \n",
"\n",
" \n",
"\n",
" \n",
"\n",
" map.on('style.load', function() {\n",
" console.log('Yoooooo');\n",
" let params = {\n",
" 'type': 'raster',\n",
" 'tiles': [\n",
" 'http://127.0.0.1:8080/tiles/{z}/{x}/{y}.png'\n",
" ],\n",
" 'tileSize': 256,\n",
" 'minzoom': 0,\n",
" 'maxzoom': 22\n",
" }\n",
" if ([39.28650720617372, -5.770217424643658, 39.313619221090086, -5.743046418788738] !== undefined) params.bounds = [39.28650720617372, -5.770217424643658, 39.313619221090086, -5.743046418788738];\n",
"\n",
" map.addSource('raster-tiles', params);\n",
"\n",
" map.addLayer({\n",
" 'id': 'raster-tiles',\n",
" 'type': 'raster',\n",
" 'source': 'raster-tiles'\n",
" }, '' );\n",
"\n",
" });\n",
"\n",
"\n",
"\n",
"</script>\n",
"\n",
"</body>\n",
"</html>\" style=\"width: 100%; height: 1000px;\"></iframe>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"viz = RasterTilesViz(ts.get_tiles_url(), \n",
" tiles_bounds=ts.get_bounds(),\n",
" center=ts.get_center(),\n",
" access_token=token, \n",
" height='1000px', \n",
" zoom=13)\n",
"viz.show()"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"ts.stop()"
]
}
],
"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.0"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment