{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Working with 3D city models in Python\n", "\n", "\n", "\n", "**Balázs Dukai** [*@BalazsDukai*](https://twitter.com/balazsdukai), **FOSS4G 2019**\n", "\n", "Tweet #CityJSON\n", "\n", "[3D geoinformation research group, TU Delft, Netherlands](https://3d.bk.tudelft.nl/)\n", "\n", "\n", "\n", "Repo of this talk: [https://github.com/balazsdukai/foss4g2019](https://github.com/balazsdukai/foss4g2019)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# 3D + city + model ?\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "Probably the most well known 3d city model is what we see in Google Earth. And it is a very nice model to look at and it is improving continuously. However, certain applications require more information than what is stored in such a mesh model. They need to know what does an object in the model represent in the real world." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "# Semantic models\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "That is why we have semantic models, where for each object in the model we store a label of is meaning.\n", "Once we have labels on the object and on their parts, data preparation becomes more simple. An important property for analytical applications, such as wind flow simulations." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "# Useful for urban analysis\n", "\n", "\n", "\n", "García-Sánchez, C., van Beeck, J., Gorlé, C., Predictive Large Eddy Simulations for Urban Flows: Challenges and Opportunities, Building and Environment, 139, 146-156, 2018." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "But we can do much more with 3d city models. We can use them to better estimate the energy consumption in buildings, simulate noise in cities or analyse views and shadows. In the Netherlands sunshine is precious commodity, so we like to get as much as we can." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "# And many more...\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "There are many open 3d city models available. They come in different formats and quality. However, at our group we are still waiting for the \"year of the 3d city model\" to come. We don't really see mainstream use, apart of visualisation. Which is nice, I belive they can provide much more value than having a nice thing to simply look at." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "# ...mostly just production of the models\n", "\n", "many available, but who **uses** them? **For more than visualisation?**\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "# In truth, 3D CMs are a bit difficult to work with" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "### Our built environment is complex, and the objects are complex too\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "### Software are lagging behind\n", "\n", "+ not many software supports 3D city models\n", "\n", "+ if they do, mostly propietary data model and format\n", "\n", "+ large, *\"eterprise\"*-type applications (think Esri, FME, Bentley ... )\n", "\n", "+ few tools accessible for the individual developer / hobbyist" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "2. GML doesn't help ( *[GML madness](http://erouault.blogspot.com/2014/04/gml-madness.html) by Even Rouault* )" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "That is why we are developing CityJSON, which is a data format for 3d city models. Essentially, it aims to increase the value of 3d city models by making it more simple to work with them and lower the entry for a wider audience than cadastral organisations." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Key concepts of CityJSON" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "+ *simple*, as in easy to implement\n", "+ designed with programmers in mind\n", "+ fully developed in the open\n", "+ flattened hierarchy of objects\n", "+ implementation first\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "CityJSON implements the data model of CityGML. CityGML is an international standard for 3d city models and it is coupled with its GML-based encoding. \n", "\n", "We don't really like GML, because it's verbose, files are deeply nested and large (often several GB). And there are many different ways to do one thing.\n", "\n", "Also, I'm not a web-developer, but I would be surprised if anyone prefers GML over JSON for sending stuff around the web." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "# JSON-based encoding of the CityGML data model\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "
\n", "\n", "+ files are deeply nested, and large\n", "+ many \"points of entry\"\n", "+ many diff ways to do one thing (GML doesn't help, *[GML madness](http://erouault.blogspot.com/2014/04/gml-madness.html) by Even Rouault* )" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "## The CityGML data model\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Compression ~6x over CityGML\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "## Compression\n", "| file | CityGML size (original) | CityGML size (w/o spaces) | textures | CityJSON | compression |\n", "| -------- | ----------------------- | ----------------------------- |--------- | ------------ | --------------- | \n", "| [CityGML demo \"GeoRes\"](https://www.citygml.org/samplefiles/) | 4.3MB | 4.1MB | yes | 524KB | 8.0 |\n", "| [CityGML v2 demo \"Railway\"](https://www.citygml.org/samplefiles/) | 45MB | 34MB | yes | 4.3MB | 8.1 |\n", "| [Den Haag \"tile 01\"](https://data.overheid.nl/data/dataset/ngr-3d-model-den-haag) | 23MB | 18MB | no, material | 2.9MB | 6.2 |\n", "| [Montréal VM05](http://donnees.ville.montreal.qc.ca/dataset/maquette-numerique-batiments-citygml-lod2-avec-textures/resource/36047113-aa19-4462-854a-cdcd6281a5af) | 56MB | 42MB | yes | 5.4MB | 7.8 |\n", "| [New York LoD2 (DA13)](https://www1.nyc.gov/site/doitt/initiatives/3d-building.page) | 590MB | 574MB | no | 105MB | 5.5 |\n", "| [Rotterdam Delfshaven](http://rotterdamopendata.nl/dataset/rotterdam-3d-bestanden/resource/edacea54-76ce-41c7-a0cc-2ebe5750ac18) | 16MB | 15MB | yes | 2.6MB | 5.8 |\n", "| [Vienna (the demo file)](https://www.data.gv.at/katalog/dataset/86d88cae-ad97-4476-bae5-73488a12776d) | 37MB | 36MB | no | 5.3MB | 6.8 |\n", "| [Zürich LoD2](https://www.data.gv.at/katalog/dataset/86d88cae-ad97-4476-bae5-73488a12776d) | 3.03GB | 2.07GB | no | 292MB | 7.1 |" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "If you are interested in a more detailed comparison between CityGML and CityJSON you can read our article, its open access." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "And yes, we are guilty of charge." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "\n", "\n", "[https://xkcd.com/927/](https://xkcd.com/927/)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Let's have a look-see, shall we?\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "Now let's take a peek under the hood, what's going on in a CityJSON file." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## An empty CityJSON file\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "In a city model we represent the real-world objects such as buildings, bridges, trees as different types of CityObjects. Each CityObject has its \n", "\n", "+ unique ID, \n", "+ attributes,\n", "+ geometry,\n", "+ and it can have children objects or it can be part of a parent object.\n", "\n", "Note however, that CityObject are not nested. Each of them is stored at root and the hierachy represented by linking to object IDs. " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## A CityObject\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "Each CityObject has a geometry representation. This geometry is composed of *boundaries* and *semantics*." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Geometry\n", "\n", "+ **boundaries** definition uses vertex indices (inspired by Wavefront OBJ)\n", "+ We have a vertex list at the root of the document\n", "+ Vertices are not repeated (unlike Simple Features)\n", "+ **semantics** are linked to the boundary surfaces\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "This `MulitSurface` has \n", "\n", "5 surfaces \n", "```json\n", "[[0, 3, 2, 1]], [[4, 5, 6, 7]], [[0, 1, 5, 4]], [[0, 2, 3, 8]], [[10, 12, 23, 48]]\n", "```\n", "each surface has only an exterior ring (the first array)\n", "```json\n", "[ [0, 3, 2, 1] ]\n", "```\n", "\n", "The semantic surfaces in the `semantics` json-object are linked to the boundary surfaces. The integers in the `values` property of `surfaces` are the 0-based indices of the surfaces of the boundary." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "pycharm": { "is_executing": false }, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "There are 16 CityObjects\n", "{C9D4A5CF-094A-47DA-97E4-4A3BFD75D3AE} \t\n", "{71B60053-BC28-404D-BAB9-8A642AAC0CF4} \t\n", "{6271F75F-E8D8-4EE4-AC46-9DB02771A031} \t\n", "{DE77E78F-B110-43D2-A55C-8B61911192DE} \t\n", "{19935DFC-F7B3-4D6E-92DD-C48EE1D1519A} \t\n", "{953BC999-2F92-4B38-95CF-218F7E05AFA9} \t\n", "{8D716FDE-18DD-4FB5-AB06-9D207377240E} \t\n", "{C6AAF95B-8C09-4130-AB4D-6777A2A18A2E} \t\n", "{72390BDE-903C-4C8C-8A3F-2DF5647CD9B4} \t\n", "{8244B286-63E2-436E-9D4E-169B8ACFE9D0} \t\n", "{87316D28-7574-4763-B9CE-BF6A2DF8092C} \t\n", "{CD98680D-A8DD-4106-A18E-15EE2A908D75} \t\n", "{64A9018E-4F56-47CD-941F-43F6F0C4285B} \t\n", "{459F183A-D0C2-4F8A-8B5F-C498EFDE366D} \t\n", "{237D41CC-991E-4308-8986-42ABFB4F7431} \t\n", "{23D8CA22-0C82-4453-A11E-B3F2B3116DB4} \t\n" ] } ], "source": [ "import json\n", "import os\n", "\n", "path = os.path.join('data', 'rotterdam_subset.json')\n", "with open(path) as fin:\n", " cm = json.loads(fin.read())\n", " \n", "print(f\"There are {len(cm['CityObjects'])} CityObjects\")\n", "\n", "# list all IDs\n", "for id in cm['CityObjects']:\n", " print(id, \"\\t\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "+ Working with a CityJSON file is straightforward. One can open it with the standard library and get going.\n", "+ But you need to know the schema well.\n", "+ And you need to write everything from scratch." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "That is why we are developing **cjio**. \n", "\n", "**cjio** is how *we eat what we cook*\n", "\n", "Aims to help to actually work with and analyse 3D city models, and extract more value from them. Instead of letting them gather dust in some governmental repository." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## `cjio` has a (quite) stable CLI\n", "\n", "```bash\n", "$ cjio city_model.json reproject 2056 export --format glb /out/model.glb\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "## and an experimental API\n", "\n", "```python\n", "from cjio import cityjson\n", "\n", "cm = cityjson.load('city_model.json')\n", "\n", "cm.get_cityobjects(type='building')\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "**`pip install cjio`**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "This notebook is based on the develop branch." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "**`pip install git+https://github.com/tudelft3d/cjio@develop`**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# `cjio`'s CLI" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "pycharm": { "is_executing": false }, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Usage: cjio [OPTIONS] INPUT COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]...\r\n", "\r\n", " Process and manipulate a CityJSON file, and allow different outputs. The\r\n", " different operators can be chained to perform several processing in one\r\n", " step, the CityJSON model goes through the different operators.\r\n", "\r\n", " To get help on specific command, eg for 'validate':\r\n", "\r\n", " cjio validate --help\r\n", "\r\n", " Usage examples:\r\n", "\r\n", " cjio example.json info validate\r\n", " cjio example.json assign_epsg 7145 remove_textures export output.obj\r\n", " cjio example.json subset --id house12 save out.json\r\n", "\r\n", "Options:\r\n", " --version Show the version and exit.\r\n", " --ignore_duplicate_keys Load a CityJSON file even if some City Objects have\r\n", " the same IDs (technically invalid file)\r\n", " --help Show this message and exit.\r\n", "\r\n", "Commands:\r\n", " assign_epsg Assign a (new) EPSG.\r\n", " clean Clean = remove_duplicate_vertices +...\r\n", " compress Compress a CityJSON file, ie stores its...\r\n", " decompress Decompress a CityJSON file, ie remove the...\r\n", " export Export the CityJSON to another format.\r\n", " extract_lod Extract only one LoD for a dataset.\r\n", " info Output info in simple JSON.\r\n", " locate_textures Output the location of the texture files.\r\n", " merge Merge the current CityJSON with others.\r\n", " partition Partition the city model into tiles.\r\n", " remove_duplicate_vertices Remove duplicate vertices a CityJSON file.\r\n", " remove_materials Remove all materials from a CityJSON file.\r\n", " remove_orphan_vertices Remove orphan vertices a CityJSON file.\r\n", " remove_textures Remove all textures from a CityJSON file.\r\n", " reproject Reproject the CityJSON to a new EPSG.\r\n", " save Save the city model to a CityJSON file.\r\n", " subset Create a subset of a CityJSON file.\r\n", " translate Translate the file by its (-minx, -miny,...\r\n", " update_bbox Update the bbox of a CityJSON file.\r\n", " update_textures Update the location of the texture files.\r\n", " upgrade_version Upgrade the CityJSON to the latest version.\r\n", " validate Validate the CityJSON file: (1) against its...\r\n" ] } ], "source": [ "! cjio --help" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "pycharm": { "is_executing": false }, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[30m\u001b[46mParsing data/rotterdam_subset.json\u001b[0m\r\n", "{\r\n", " \"cityjson_version\": \"1.0\",\r\n", " \"epsg\": 7415,\r\n", " \"bbox\": [\r\n", " 90454.18900000001,\r\n", " 435614.88,\r\n", " 0.0,\r\n", " 91002.41900000001,\r\n", " 436048.217,\r\n", " 18.29\r\n", " ],\r\n", " \"transform/compressed\": true,\r\n", " \"cityobjects_total\": 16,\r\n", " \"cityobjects_present\": [\r\n", " \"Building\"\r\n", " ],\r\n", " \"materials\": false,\r\n", " \"textures\": true\r\n", "}\r\n" ] } ], "source": [ "! cjio data/rotterdam_subset.json info" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "pycharm": { "is_executing": false }, "slideshow": { "slide_type": "skip" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[30m\u001b[46mParsing data/rotterdam_subset.json\u001b[0m\n", "\u001b[30m\u001b[46m===== Validation (with official CityJSON schemas) =====\u001b[0m\n", "-- Validating the syntax of the file\n", "\t(using the schemas 1.0.0)\n", "-- Validating the internal consistency of the file (see docs for list)\n", "\t--Vertex indices coherent\n", "\t--Specific for CityGroups\n", "\t--Semantic arrays coherent with geometry\n", "\t--Root properties\n", "\t--Empty geometries\n", "\t--Duplicate vertices\n", "\t--Orphan vertices\n", "\t--CityGML attributes\n", "=====\n", "\u001b[32mFile is valid\u001b[0m\n", "\u001b[31mFile has warnings\u001b[0m\n", "--- WARNINGS ---\n", "WARNING: attributes 'TerrainHeight' not in CityGML schema\n", "\t(16 CityObjects have this warning)\n", "WARNING: attributes 'bron_tex' not in CityGML schema\n", "\t(16 CityObjects have this warning)\n", "WARNING: attributes 'voll_tex' not in CityGML schema\n", "\t(16 CityObjects have this warning)\n", "WARNING: attributes 'bron_geo' not in CityGML schema\n", "\t(16 CityObjects have this warning)\n", "WARNING: attributes 'status' not in CityGML schema\n", "\t(16 CityObjects have this warning)\n", "=====================================\n" ] } ], "source": [ "! cjio data/rotterdam_subset.json validate" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "pycharm": { "is_executing": false }, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[30m\u001b[46mParsing data/rotterdam_subset.json\u001b[0m\n", "\u001b[30m\u001b[46mSubset of CityJSON\u001b[0m\n", "\u001b[30m\u001b[46mMerging files\u001b[0m\n", "\u001b[30m\u001b[46mReproject to EPSG:2056\u001b[0m\n", "\u001b[?25l [####################################] 100% \u001b[?25h\n", "\u001b[30m\u001b[46mSaving CityJSON to a file /home/balazs/Reports/talk_cjio_foss4g_2019/data/test_rotterdam.json\u001b[0m\n" ] } ], "source": [ "! cjio data/rotterdam_subset.json \\\n", " subset --exclude --id \"{CD98680D-A8DD-4106-A18E-15EE2A908D75}\" \\\n", " merge data/rotterdam_one.json \\\n", " reproject 2056 \\\n", " save data/test_rotterdam.json" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "+ The CLI was first, no plans for API\n", "\n", "+ **Works with whole city model only**\n", "\n", "+ Functions for the CLI work with the JSON directly, passing it along\n", "\n", "+ Simple and effective architecture" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# `cjio`'s API\n", "\n", "Allow *read* --> *explore* --> *modify* --> *write* iteration\n", "\n", "Work with CityObjects and their parts\n", "\n", "Functions for common operations\n", "\n", "Inspired by the *tidyverse* from the R ecosystem" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "pycharm": { "is_executing": false }, "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "import os\n", "from copy import deepcopy\n", "from cjio import cityjson\n", "from shapely.geometry import Polygon\n", "import matplotlib.pyplot as plt\n", "plt.close('all')\n", "from sklearn.preprocessing import FunctionTransformer\n", "from sklearn import cluster\n", "import numpy as np" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" }, "slideshow": { "slide_type": "skip" } }, "source": [ "In the following we work with a subset of the 3D city model of Rotterdam\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Load a CityJSON" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" }, "slideshow": { "slide_type": "skip" } }, "source": [ "The `load()` method loads a CityJSON file into a CityJSON object." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "pycharm": { "is_executing": false, "name": "#%%\n" }, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I just got sent a CityGML file. pic.twitter.com/jnTVoRnVLS
— James Fee (@jamesmfee) June 29, 2016
| \n", " | creationDate | \n", "Geomtype | \n", "nr_vertices | \n", "fp_area | \n", "class | \n", "Herkunft | \n", "QualitaetStatus | \n", "FileCreationDate | \n", "Region | \n", "GebaeudeStatus | \n", "
|---|---|---|---|---|---|---|---|---|---|---|
| UUID_93fc5bae-4446-4336-9ff8-6679ebfdfde3 | \n", "2017-01-23 | \n", "1.0 | \n", "24 | \n", "65.209763 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
| UUID_c9884c4e-1cac-47f5-b88b-6fb074c0ae50 | \n", "2017-01-23 | \n", "NaN | \n", "0 | \n", "0.000000 | \n", "BB01 | \n", "EE_LB_2007 | \n", "1.0 | \n", "2012-02-23 | \n", "2.0 | \n", "1.0 | \n", "
| UUID_a4a09780-153f-4385-ad19-3a92a6c4eec4 | \n", "2017-01-23 | \n", "1.0 | \n", "38 | \n", "20.784309 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
| UUID_ba0bb815-5276-4e35-b4c1-878cbf6ba934 | \n", "2017-01-23 | \n", "NaN | \n", "0 | \n", "0.000000 | \n", "BB07 | \n", "EE_LB_2007 | \n", "1.0 | \n", "2012-02-23 | \n", "2.0 | \n", "1.0 | \n", "
| UUID_bb1835bc-7437-453f-ac08-885de0503aaa | \n", "2017-01-23 | \n", "1.0 | \n", "87 | \n", "69.363823 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "