├── .DS_Store ├── .ipynb_checkpoints └── Data Science Meetup-checkpoint.ipynb ├── 18271-good-news-everyone-i-was-just-kidding-professor-farnsworth-wallpaper-1280x1280-1-750x410.jpg ├── Data Science Meetup.html ├── Data Science Meetup.ipynb ├── README ├── bokeh_example_1.py ├── bokeh_example_2.py ├── bokeh_example_3.py ├── bqplot_example_1.py ├── bqplot_example_2.py ├── bqplot_example_3.py ├── bqplot_example_4.py ├── c2fo_python.png ├── data_files ├── country_codes.csv └── gdp_per_capita.csv ├── input_output_control_large.png ├── public └── .DS_Store ├── pygal_example_1.py ├── pygal_example_2.py ├── pygal_example_3.py ├── resized_chemistry-cat.jpg ├── sample_script_10.py ├── spyre_script_1.py ├── spyre_script_10.py ├── spyre_script_2.py ├── spyre_script_3.py ├── spyre_script_4.py ├── spyre_script_5.py ├── spyre_script_6.py ├── spyre_script_7.py ├── spyre_script_8.py ├── spyre_script_9.py └── thats-cool-i8t8sz.jpg /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pm8k/dataspyre_tutorial/8ae564967337be2f293cbf30f35cc8a5f9cfe852/.DS_Store -------------------------------------------------------------------------------- /18271-good-news-everyone-i-was-just-kidding-professor-farnsworth-wallpaper-1280x1280-1-750x410.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pm8k/dataspyre_tutorial/8ae564967337be2f293cbf30f35cc8a5f9cfe852/18271-good-news-everyone-i-was-just-kidding-professor-farnsworth-wallpaper-1280x1280-1-750x410.jpg -------------------------------------------------------------------------------- /Data Science Meetup.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "# Leveraging Python for Data Visibility - Maximizing the view into our data by creating a lightweight stand alone webapp and integrating interactive plotting libraries" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "In this talk we aim to help python users maximize their information gain with some easy to use libraries, specifically Spyre, Bokeh, and Pygal" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "---" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "## About me\n", 36 | "My name is Matthew Russell, and I'm one of the Data Scientists here at C2FO, the world's market for working capital. After earning my BS and MS in Physics, I left academia to find something new, and stumbled upon the world of data science. After using python in my graduate research, I naturally gravitated to the libraries that have been making significant headway for data science in the past few years, and I will be sharing and presenting several of these libraries to you today." 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "metadata": {}, 42 | "source": [ 43 | "## Contact Info\n", 44 | " - Email - matthew.russell@c2fo.com\n", 45 | " - Github - pm8k" 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "metadata": {}, 51 | "source": [ 52 | "--------\n" 53 | ] 54 | }, 55 | { 56 | "cell_type": "markdown", 57 | "metadata": {}, 58 | "source": [ 59 | "# Topic Headers\n", 60 | " 1. How as Data Scientists do we access our Data?\n", 61 | " - Introduction to Data Spyre: What is it?\n", 62 | " - Alright, this looks Cool! How do I make my own Webapp?\n", 63 | " - How do I make my Cool webapp even Cooler?\n", 64 | " - Let's get Interactive with some plotting libraries!\n", 65 | " - The Grand Finale: Interactive plots in Data Spyre!\n", 66 | " - Questions?\n" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "metadata": {}, 72 | "source": [ 73 | "--------" 74 | ] 75 | }, 76 | { 77 | "cell_type": "markdown", 78 | "metadata": {}, 79 | "source": [ 80 | "# 1. How as Data Scientists do we access our Data?\n", 81 | " - What are some of the common tools you work with visualize your data?\n", 82 | " - What problems challenge you with your workflow?" 83 | ] 84 | }, 85 | { 86 | "cell_type": "markdown", 87 | "metadata": {}, 88 | "source": [ 89 | "## Our talk will help to address the following questions:\n", 90 | "- How can I provide the best view into my data? \n", 91 | "- How can I easily introduce aggregations and filtering into my workflow? \n", 92 | "- How do I share my data with decision makers?\n", 93 | "- How can I maximize my information within one visualization?" 94 | ] 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "metadata": {}, 99 | "source": [ 100 | "---" 101 | ] 102 | }, 103 | { 104 | "cell_type": "markdown", 105 | "metadata": {}, 106 | "source": [ 107 | "" 108 | ] 109 | }, 110 | { 111 | "cell_type": "markdown", 112 | "metadata": {}, 113 | "source": [ 114 | "## Good News! Python has some new libraries to help us in our just cause in the pursuit of data!\n", 115 | "\n", 116 | "### In this talk I'm going to introduce Data Spyre, a lightweight interactive web application built on python. Inspired by R's Shiny, Data Spyre creates an easy to use framework to customize how you need to look at your data.\n", 117 | "\n", 118 | "### I will also be covering Pygal, Bokeh, and BQplot, a series of libraries to add some interactivity to your plotting toolkit." 119 | ] 120 | }, 121 | { 122 | "cell_type": "markdown", 123 | "metadata": {}, 124 | "source": [ 125 | "## Here is the location of all the libraries we will be discussing\n", 126 | " - Data Spyre - https://github.com/adamhajari/spyre\n", 127 | " - Bokeh - http://bokeh.pydata.org/en/latest/\n", 128 | " - Pygal - http://www.pygal.org/en/latest/\n", 129 | " - BQPlot - https://github.com/bloomberg/bqplot" 130 | ] 131 | }, 132 | { 133 | "cell_type": "markdown", 134 | "metadata": {}, 135 | "source": [ 136 | "-------" 137 | ] 138 | }, 139 | { 140 | "cell_type": "markdown", 141 | "metadata": {}, 142 | "source": [ 143 | "# 2. Introduction to Data Spyre: What is it?" 144 | ] 145 | }, 146 | { 147 | "cell_type": "markdown", 148 | "metadata": {}, 149 | "source": [ 150 | "### Data Spyre is a python implementation of a web facing application inspired by R's Shiny. It is structured to cover most of the front end and back end work to standing up a web application, only requiring you to define what to plot and what data to show. In order to accomplish this, data spyre leverages the power of 4 well established libraries:\n", 151 | "\n", 152 | " - Cherrypy - Python Web application library to handle front and back end (Webapp)\n", 153 | " - Jinja2 - Python Templating library based off of Django's templates (HTML and Javascript)\n", 154 | " - Pandas - Python library for data aggregation, filtering, and plotting (Data Manipulation)\n", 155 | " - Matplotlib - Python's plotting library (Plots)" 156 | ] 157 | }, 158 | { 159 | "cell_type": "markdown", 160 | "metadata": {}, 161 | "source": [ 162 | "## Script 1" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": null, 168 | "metadata": { 169 | "collapsed": true 170 | }, 171 | "outputs": [], 172 | "source": [ 173 | "from spyre import server\n", 174 | "\n", 175 | "class SimpleApp(server.App):\n", 176 | " title = \"Simple App\"\n", 177 | " inputs = [{ \"type\":\"text\",\n", 178 | " \"key\":\"words\",\n", 179 | " \"label\": \"write here\",\n", 180 | " \"value\":\"hello world\"}]\n", 181 | " outputs = [{\"type\":\"html\",\n", 182 | " \"id\":\"some_html\",\n", 183 | " \"control_id\":\"button1\"}]\n", 184 | " controls = [{\"type\":\"button\",\n", 185 | " \"label\":\"press to update\",\n", 186 | " \"id\":\"button1\"}]\n", 187 | " def getHTML(self, params):\n", 188 | " words = params['words']\n", 189 | " return \"Here are some words: %s\"%words\n", 190 | "\n", 191 | "app = SimpleApp()\n", 192 | "#app.launch()" 193 | ] 194 | }, 195 | { 196 | "cell_type": "markdown", 197 | "metadata": {}, 198 | "source": [ 199 | "### With just a few lines of code, we have a webapp we can launch from our browser. While we aren't looking at any data in this example, we have all of the important elements for our web application:\n", 200 | " - An input to help control what our web app displays\n", 201 | " - A control mechanism that updates the text on the page\n", 202 | " - A function that creates the output onto the webapp" 203 | ] 204 | }, 205 | { 206 | "cell_type": "markdown", 207 | "metadata": {}, 208 | "source": [ 209 | "### Let's look at something with some data... how about a simple sine wave?" 210 | ] 211 | }, 212 | { 213 | "cell_type": "markdown", 214 | "metadata": {}, 215 | "source": [ 216 | "## Script 2" 217 | ] 218 | }, 219 | { 220 | "cell_type": "code", 221 | "execution_count": null, 222 | "metadata": { 223 | "collapsed": true 224 | }, 225 | "outputs": [], 226 | "source": [ 227 | "from spyre import server\n", 228 | "\n", 229 | "import matplotlib.pyplot as plt\n", 230 | "import numpy as np\n", 231 | "\n", 232 | "class SimpleSineApp(server.App):\n", 233 | " title = \"Simple Sine App\"\n", 234 | " inputs = [{ \"type\":\"text\",\n", 235 | " \"key\":\"freq\",\n", 236 | " \"value\":5,\n", 237 | " \"label\":\"frequency\",\n", 238 | " \"action_id\":\"sine_wave_plot\"}]\n", 239 | " outputs = [{\"type\":\"plot\",\n", 240 | " \"id\":\"sine_wave_plot\"}]\n", 241 | " controls = [{\"type\":\"HIDDEN\",\n", 242 | " \"id\":\"sine_wave_plot\"}]\n", 243 | " def getPlot(self, params):\n", 244 | " f = float(params['freq'])\n", 245 | " x = np.arange(0,2*np.pi,np.pi/150)\n", 246 | " y = np.sin(f*x)\n", 247 | " fig = plt.figure()\n", 248 | " splt1 = fig.add_subplot(1,1,1)\n", 249 | " splt1.plot(x,y)\n", 250 | " return fig\n", 251 | "\n", 252 | "if __name__ == '__main__':\n", 253 | " app = SimpleSineApp()\n", 254 | " #app.launch()" 255 | ] 256 | }, 257 | { 258 | "cell_type": "markdown", 259 | "metadata": {}, 260 | "source": [ 261 | "### Similar to the previous app, we have defined an input, a control, and a function to generate output onto our webapp, all in just a few lines of code! " 262 | ] 263 | }, 264 | { 265 | "cell_type": "markdown", 266 | "metadata": {}, 267 | "source": [ 268 | "----------------------------" 269 | ] 270 | }, 271 | { 272 | "cell_type": "markdown", 273 | "metadata": {}, 274 | "source": [ 275 | "# 3. Alright, this looks Cool! How do I make my own?" 276 | ] 277 | }, 278 | { 279 | "cell_type": "markdown", 280 | "metadata": {}, 281 | "source": [ 282 | "### So far we've seen a couple of these webapps in action, so let's go down the rabbit hole a bit further and see what's actually going on under the hood of our Data Spyre class. Let's look again at the Sine App we just had up" 283 | ] 284 | }, 285 | { 286 | "cell_type": "markdown", 287 | "metadata": {}, 288 | "source": [ 289 | "## Script 3" 290 | ] 291 | }, 292 | { 293 | "cell_type": "code", 294 | "execution_count": null, 295 | "metadata": { 296 | "collapsed": true 297 | }, 298 | "outputs": [], 299 | "source": [ 300 | "from spyre import server\n", 301 | "\n", 302 | "import matplotlib.pyplot as plt\n", 303 | "import numpy as np\n", 304 | "\n", 305 | "class SimpleSineApp(server.App):\n", 306 | " title = \"Simple Sine App\"\n", 307 | " inputs = [{ \"type\":\"text\",\n", 308 | " \"key\":\"freq\",\n", 309 | " \"value\":5,\n", 310 | " \"label\":\"frequency\",\n", 311 | " \"action_id\":\"sine_wave_plot\"}]\n", 312 | " outputs = [{\"type\":\"plot\",\n", 313 | " \"id\":\"sine_wave_plot\"}]\n", 314 | " controls = [{\"type\":\"HIDDEN\",\n", 315 | " \"id\":\"sine_wave_plot\"}]\n", 316 | " def getPlot(self, params):\n", 317 | " f = float(params['freq'])\n", 318 | " x = np.arange(0,2*np.pi,np.pi/150)\n", 319 | " y = np.sin(f*x)\n", 320 | " fig = plt.figure()\n", 321 | " splt1 = fig.add_subplot(1,1,1)\n", 322 | " splt1.plot(x,y)\n", 323 | " return fig\n", 324 | "\n", 325 | "if __name__ == '__main__':\n", 326 | " app = SimpleSineApp()\n", 327 | " #app.launch()" 328 | ] 329 | }, 330 | { 331 | "cell_type": "markdown", 332 | "metadata": {}, 333 | "source": [ 334 | "### The main wrapper for our web application is a python class, which inherits from dataspyre's server.App class. Don't worry too much of the details of the class inheritance, other than the structure of your class objects needs to be correctly defined for your webapp to run smoothly. So we start with naming our class, and pass in server.App as the inherited class. Now within the class we need to define a few parameters that is the key to any app:" 335 | ] 336 | }, 337 | { 338 | "cell_type": "markdown", 339 | "metadata": {}, 340 | "source": [ 341 | "### title \n", 342 | "A string that represents the name of your webapp. In our case, it is \"Simple Sine App\". Only one title is assigned per webapp" 343 | ] 344 | }, 345 | { 346 | "cell_type": "markdown", 347 | "metadata": {}, 348 | "source": [ 349 | "### inputs\n", 350 | "The inputs variable is a python list of dictionaries, with each dictionary representing another input variable. In our example, we have one input: frequency. Let's breakdown each of the elements quickly that make up an input:\n", 351 | " 1. label - The text name to be displayed for your key\n", 352 | " 2. type - The type of input to be created. In our webapp, we have a text box, which is created as type 'text'. We have also seen type 'slider' in our previous example.\n", 353 | " 3. value - The default value for the webapp upon initial load. When the value is changed by the user, the dictionary reflects this change\n", 354 | " 4. key - The key is used as the name reference in the data and plotting functions. They are stored in class dictionary called 'params' keyed by this key value. \n", 355 | " 5. Action Id - The Action Id is used to tie which control to use, which we will be going over next." 356 | ] 357 | }, 358 | { 359 | "cell_type": "markdown", 360 | "metadata": {}, 361 | "source": [ 362 | "### controls\n", 363 | "The control variable is also a list of python dictionaries. Each dictionary contains one control to tie a set of inputs and outputs together. What exactly does the control do? The control updates your data based on any changes you make to the input. When there are multiple inputs and/or multiple outputs, multiple controls allow you to refresh specific points in your data. The control has three properties:\n", 364 | " 1. type - defines whether a control is 'hidden' or is a 'button'. Hidden allows the output to update upon change of input, while a button must be pressed to update your changes.\n", 365 | "\n", 366 | " 2. label - if the control type is a button, the label will be the text on the button.\n", 367 | "\n", 368 | " 3. id - the control id to identify which inputs and outputs are controlled by this id. Any inputs with the 'action_id' the same as this id trigger this control, and all outputs with an action_id with this id will be refreshed with new data." 369 | ] 370 | }, 371 | { 372 | "cell_type": "markdown", 373 | "metadata": {}, 374 | "source": [ 375 | "### outputs\n", 376 | "And once again, our output variable is defined as a list of dictionaries, with each dicitonary tied to a single output. In our webapp, an output is a data object being returned to our webapp to be displayed. Lets dive back in to what makes up an output entry:\n", 377 | " 1. type - This tells the webapp which kind of data object is being returned as an output. The main three types of output are table (pandas dataframe), plot (matplotlib figure object), or html.\n", 378 | "\n", 379 | " 2. control_id - Once again, this id ties back to a control we've already defined. This output will update when the specified control is triggered by the output.\n", 380 | "\n", 381 | " 3. tab - The name of the tab to display your output. So far we've only demonstrated a single output webapp, but when you have multiple outputs, you can specify what location each output goes to. We'll dive a bit more into this later.\n", 382 | "\n", 383 | " 4. on page load - a boolean flag to tell the webapp whether to load the page upon connecting to the web server. Generally you will want to set this to true.\n", 384 | "\n", 385 | " 5. id - a seemingly deceptive trait. Each output requires an id name which will be parsed to act as an identifier for the output. However, the true functionality comes with function overloading. Again, let's get a simple app up and running and we can dive more into the customization we can introduce.\n", 386 | " " 387 | ] 388 | }, 389 | { 390 | "cell_type": "markdown", 391 | "metadata": {}, 392 | "source": [ 393 | "" 394 | ] 395 | }, 396 | { 397 | "cell_type": "markdown", 398 | "metadata": {}, 399 | "source": [ 400 | "### Sweet! All of our inputs and outputs are created, and we know how to control everything! Now all we need to do is define where we get our data from. Data Spyre has built in function types to handle our main 3 output types: getData, getPlot, getHTML. Each one has its own return type as previously specified. And here is where the magic happens: The user can define these functions to create the data representation that they want to return, return the appropriate object, and your webapp is ready to go! Lets look at the sine getPlot example:" 401 | ] 402 | }, 403 | { 404 | "cell_type": "markdown", 405 | "metadata": {}, 406 | "source": [ 407 | "## Plot Function" 408 | ] 409 | }, 410 | { 411 | "cell_type": "code", 412 | "execution_count": null, 413 | "metadata": { 414 | "collapsed": true 415 | }, 416 | "outputs": [], 417 | "source": [ 418 | "def getPlot(self, params):\n", 419 | " f = float(params['freq'])\n", 420 | " x = np.arange(0,2*np.pi,np.pi/150)\n", 421 | " y = np.sin(f*x)\n", 422 | " fig = plt.figure()\n", 423 | " splt1 = fig.add_subplot(1,1,1)\n", 424 | " splt1.plot(x,y)\n", 425 | " return fig" 426 | ] 427 | }, 428 | { 429 | "cell_type": "markdown", 430 | "metadata": {}, 431 | "source": [ 432 | "### Our getPlot function takes 2 arguments: self, because we are working with a class object, as well as params, which is the current values of all objects in our input. Note that we don't actually call this function ourselves, Data Spyre does it for us, and it is expecting us to pass the params object, so even if your function doesn't require the params dictionary, it still needs to be passed in. The rest of the function is a simple matplotlib figure. As you can see, we get our frequency from the params dictionary by subsetting on the name 'freq' which we defined in the inputs. At the end we return a matplotlib figure, which Data Spyre takes and displays on the web app." 433 | ] 434 | }, 435 | { 436 | "cell_type": "markdown", 437 | "metadata": {}, 438 | "source": [ 439 | "### Alright, cool, we've got ourselves a simple webapp with a graph. What if we wanted to display not just the plot, but the data behind it as well? That's easy! We just need to introduce tabs. Tabs is a list of strings that will be created in the webapp. Each tab should be tied to one unique output. As explained earlier, we can tie in the tab name as a parameter of the output. Let's look back to our sine example:" 440 | ] 441 | }, 442 | { 443 | "cell_type": "markdown", 444 | "metadata": {}, 445 | "source": [ 446 | "## Script 4" 447 | ] 448 | }, 449 | { 450 | "cell_type": "code", 451 | "execution_count": null, 452 | "metadata": { 453 | "collapsed": true 454 | }, 455 | "outputs": [], 456 | "source": [ 457 | "from spyre import server\n", 458 | "\n", 459 | "import matplotlib.pyplot as plt\n", 460 | "import numpy as np\n", 461 | "import pandas as pd\n", 462 | "\n", 463 | "class SimpleSineApp(server.App):\n", 464 | " title = \"Simple Sine App\"\n", 465 | " inputs = [{ \"type\":\"text\",\n", 466 | " \"key\":\"freq\",\n", 467 | " \"value\":5,\n", 468 | " \"label\":\"frequency\",\n", 469 | " \"action_id\":\"sine_wave_plot\"}]\n", 470 | " tabs=[\"Plot\",\"Data\"]\n", 471 | " outputs = [{\"type\":\"plot\",\n", 472 | " \"id\":\"wave_plot\",\n", 473 | " \"tab\":\"Plot\",\n", 474 | " \"control_id\":\"sine_wave_plot\"},\n", 475 | " {\"type\":\"table\",\n", 476 | " \"id\":\"wave_data\",\n", 477 | " \"tab\":\"Data\",\n", 478 | " \"control_id\":\"sine_wave_plot\"}]\n", 479 | " controls = [{\"type\":\"HIDDEN\",\n", 480 | " \"id\":\"sine_wave_plot\"}]\n", 481 | " def getPlot(self, params):\n", 482 | " f = float(params['freq'])\n", 483 | " df=self.getData(params)\n", 484 | " fig = plt.figure()\n", 485 | " splt1 = fig.add_subplot(1,1,1)\n", 486 | " splt1.plot(df.x,df.y)\n", 487 | " return fig\n", 488 | " def getData(self,params):\n", 489 | " f=float(params['freq'])\n", 490 | " x = pd.Series(np.arange(0,2*np.pi,np.pi/150))\n", 491 | " y = pd.Series(np.sin(f*x))\n", 492 | " df=pd.concat([x,y],axis=1)\n", 493 | " df.columns=['x','y']\n", 494 | " return df\n", 495 | "\n", 496 | "if __name__ == '__main__':\n", 497 | " app = SimpleSineApp()\n", 498 | " #app.launch()" 499 | ] 500 | }, 501 | { 502 | "cell_type": "markdown", 503 | "metadata": {}, 504 | "source": [ 505 | "### Lets dive into what's new to our code:\n", 506 | "\n", 507 | " 1. We've added a tabs list to control how we want our outputs organized\n", 508 | " 2. Each ouput now has a \"tab\" parameter which we can link to our tabs list we created\n", 509 | " 3. We've added a getData function to our class. Note that it takes the same arguments as the getPlot function. DataSpyre knows to call the getPlot function for the plot tab and it knows to call the getData function for the table tab. \n", 510 | " 4. We've now introduced pandas into our workflow. As you can see, we create a pandas dataframe, and return it for the getData Function\n", 511 | " 5. In addition, we now utilize our getData function in our getPlot function, so we only have one function to generate the data used for the plot and table." 512 | ] 513 | }, 514 | { 515 | "cell_type": "markdown", 516 | "metadata": {}, 517 | "source": [ 518 | "### We've now got a working webapp with a control as well as multiple tabs to show both plot and data! And the best part, is it took less than 40 lines of code, including import statements. This simple framework can get you running with your data quickly with little overhead. " 519 | ] 520 | }, 521 | { 522 | "cell_type": "markdown", 523 | "metadata": {}, 524 | "source": [ 525 | "" 526 | ] 527 | }, 528 | { 529 | "cell_type": "markdown", 530 | "metadata": {}, 531 | "source": [ 532 | "---" 533 | ] 534 | }, 535 | { 536 | "cell_type": "markdown", 537 | "metadata": {}, 538 | "source": [ 539 | "# 4. How do I make my Cool WebApp even Cooler?" 540 | ] 541 | }, 542 | { 543 | "cell_type": "markdown", 544 | "metadata": {}, 545 | "source": [ 546 | "### Alright, we've got a easy, lightweight to use app. However, as with any data project, our needs move outside the realm of simple and require us to dive in deeper. Let's go into how we can increase the functionality in our webapp." 547 | ] 548 | }, 549 | { 550 | "cell_type": "markdown", 551 | "metadata": {}, 552 | "source": [ 553 | "## A. Maximize the most out of our getData Function\n", 554 | "We had a really simple getData Function before, where we input a frequency and generated a sine wave. Generally, we won't be generating data on the fly. We'll want to select a portion of our data that we already have. There are many ways to do this.\n", 555 | " - We can define a global dataFrame and subset that based on our input\n", 556 | " - We can read in data locally from the filesystem\n", 557 | " - We can create some dynamic sql and pull in data based on our input \n", 558 | " - We could even scrape the data from a website given some input\n", 559 | " \n", 560 | "Long story short, we have a number of ways to get the data we want into our webapp, the question is about which method best suits your needs." 561 | ] 562 | }, 563 | { 564 | "cell_type": "markdown", 565 | "metadata": {}, 566 | "source": [ 567 | "## B. Function Overload!" 568 | ] 569 | }, 570 | { 571 | "cell_type": "markdown", 572 | "metadata": {}, 573 | "source": [ 574 | "So far we've mentioned how we can define getData, getPlot, getHTML functions in order to tell Data Spyre what type of data to generate for the web application. However, this becomes a problem when we want to have multiple functions of the same datatypes. Data Spyre has a simple solution to this, function overloading! " 575 | ] 576 | }, 577 | { 578 | "cell_type": "markdown", 579 | "metadata": {}, 580 | "source": [ 581 | "## Script 5" 582 | ] 583 | }, 584 | { 585 | "cell_type": "code", 586 | "execution_count": null, 587 | "metadata": { 588 | "collapsed": true 589 | }, 590 | "outputs": [], 591 | "source": [ 592 | "from spyre import server\n", 593 | "\n", 594 | "import matplotlib.pyplot as plt\n", 595 | "import numpy as np\n", 596 | "import pandas as pd\n", 597 | "\n", 598 | "class SimpleSineApp(server.App):\n", 599 | " title = \"Simple Sine App\"\n", 600 | " inputs = [{ \"type\":\"text\",\n", 601 | " \"key\":\"freq\",\n", 602 | " \"value\":5,\n", 603 | " \"label\":\"frequency\",\n", 604 | " \"action_id\":\"sine_wave_plot\"}]\n", 605 | " tabs=[\"Plot1\",\"Plot2\",\"Data\"]\n", 606 | " outputs = [{\"type\":\"plot\",\n", 607 | " \"id\":\"wave_plot\",\n", 608 | " \"tab\":\"Plot1\",\n", 609 | " \"control_id\":\"sine_wave_plot\"},\n", 610 | " {\"type\":\"plot\",\n", 611 | " \"id\":\"wave_plot2\",\n", 612 | " \"tab\":\"Plot2\",\n", 613 | " \"control_id\":\"sine_wave_plot\"},\n", 614 | " {\"type\":\"table\",\n", 615 | " \"id\":\"wave_data\",\n", 616 | " \"tab\":\"Data\",\n", 617 | " \"control_id\":\"sine_wave_plot\"}]\n", 618 | " controls = [{\"type\":\"HIDDEN\",\n", 619 | " \"id\":\"sine_wave_plot\"}]\n", 620 | " def wave_plot(self, params):\n", 621 | " f = float(params['freq'])\n", 622 | " df=self.wave_data(params)\n", 623 | " fig = plt.figure()\n", 624 | " splt1 = fig.add_subplot(1,1,1)\n", 625 | " splt1.plot(df.x,df.y1)\n", 626 | " return fig\n", 627 | " def wave_plot2(self, params):\n", 628 | " f = float(params['freq'])\n", 629 | " df=self.wave_data(params)\n", 630 | " fig = plt.figure()\n", 631 | " splt1 = fig.add_subplot(1,1,1)\n", 632 | " splt1.plot(df.x,df.y2)\n", 633 | " return fig\n", 634 | " def wave_data(self,params):\n", 635 | " f=float(params['freq'])\n", 636 | " x = pd.Series(np.arange(0,2*np.pi,np.pi/150))\n", 637 | " y1 = pd.Series(np.sin(f*x))\n", 638 | " y2 = pd.Series(np.sin(2*f*x))\n", 639 | " df=pd.concat([x,y1,y2],axis=1)\n", 640 | " df.columns=['x','y1','y2']\n", 641 | " return df\n", 642 | "\n", 643 | "if __name__ == '__main__':\n", 644 | " app = SimpleSineApp()\n", 645 | " #app.launch()" 646 | ] 647 | }, 648 | { 649 | "cell_type": "markdown", 650 | "metadata": {}, 651 | "source": [ 652 | "Let's look at our new class object. What exactly did we do here?\n", 653 | "- In this example we've introduced function overloading. We've renamed our getData and getPlot functions to represent the \"id\" of each output tied to the output. \n", 654 | "- Because of this, we're no longer tied to overriding Data Spyre's getData, getPlot and getHTML functions.\n", 655 | "- Why does this work? Data spyre will parse the class function names for the given output ids, and if it detects any matches, it will call the given function instead of the type default." 656 | ] 657 | }, 658 | { 659 | "cell_type": "markdown", 660 | "metadata": {}, 661 | "source": [ 662 | "## C. One input is never enough!" 663 | ] 664 | }, 665 | { 666 | "cell_type": "markdown", 667 | "metadata": {}, 668 | "source": [ 669 | "So far we've worked with a single text input. There are multiple other inputs we can use in addition or instead of a text box. Let's look at all of the options in another webapp:" 670 | ] 671 | }, 672 | { 673 | "cell_type": "markdown", 674 | "metadata": {}, 675 | "source": [ 676 | "## Script 6" 677 | ] 678 | }, 679 | { 680 | "cell_type": "code", 681 | "execution_count": null, 682 | "metadata": { 683 | "collapsed": true 684 | }, 685 | "outputs": [], 686 | "source": [ 687 | "from spyre import server\n", 688 | "\n", 689 | "import matplotlib.pyplot as plt\n", 690 | "import numpy as np\n", 691 | "import pandas as pd\n", 692 | "\n", 693 | "class SimpleSineApp(server.App):\n", 694 | " title = \"Simple Sine App\"\n", 695 | " inputs = [{ \"type\":\"text\",\n", 696 | " \"key\":\"freq\",\n", 697 | " \"value\":5,\n", 698 | " \"label\":\"frequency\",\n", 699 | " \"action_id\":\"sine_wave_plot\"},\n", 700 | " { \"type\":\"radiobuttons\",\n", 701 | " \"key\":\"func_type\",\n", 702 | " \"label\":\"func_type\",\n", 703 | " \"action_id\":\"sine_wave_plot\",\n", 704 | " \"options\":[\n", 705 | " {\"label\":\"Sine\",\"value\":\"sin\",\"checked\":True},\n", 706 | " {\"label\":\"Cosine\",\"value\":\"cos\"}]},\n", 707 | " { \"type\":\"dropdown\",\n", 708 | " \"key\":\"datatoplot\",\n", 709 | " \"options\":[\n", 710 | " {\"label\":\"x\",\"value\":\"y1\"},\n", 711 | " {\"label\":\"2x\",\"value\":\"y2\"}],\n", 712 | " \"label\":\"Data to Plot\",\n", 713 | " \"action_id\":\"sine_wave_plot\"},\n", 714 | " { \"type\":\"slider\",\n", 715 | " \"key\":\"x_slider\",\n", 716 | " \"value\":100,\n", 717 | " \"min\":1,\n", 718 | " \"max\":200,\n", 719 | " \"label\":\"x_axis\",\n", 720 | " \"action_id\":\"sine_wave_plot\"},\n", 721 | " { \"type\":\"checkboxgroup\",\n", 722 | " \"key\":\"checkboxes\",\n", 723 | " \"options\":[\n", 724 | " {\"label\":\"show x gridlines\",\"value\":\"showx\",\"checked\":True},\n", 725 | " {\"label\":\"show y gridlines\",\"value\":\"showy\"}\n", 726 | " ],\n", 727 | " \"label\":\"Plot Options\",\n", 728 | " \"action_id\":\"sine_wave_plot\"}]\n", 729 | " tabs=[\"Plot\",\"Data\"]\n", 730 | " outputs = [{\"type\":\"plot\",\n", 731 | " \"id\":\"wave_plot\",\n", 732 | " \"tab\":\"Plot\",\n", 733 | " \"control_id\":\"sine_wave_plot\"},\n", 734 | " {\"type\":\"table\",\n", 735 | " \"id\":\"wave_data\",\n", 736 | " \"tab\":\"Data\",\n", 737 | " \"control_id\":\"sine_wave_plot\"}]\n", 738 | " controls = [{\"type\":\"HIDDEN\",\n", 739 | " \"id\":\"sine_wave_plot\"}]\n", 740 | " def getPlot(self, params):\n", 741 | " f = float(params['freq'])\n", 742 | " data = params['datatoplot']\n", 743 | " checkboxlist=params['checkboxes']\n", 744 | " df=self.getData(params)\n", 745 | " fig = plt.figure()\n", 746 | " splt1 = fig.add_subplot(1,1,1)\n", 747 | " splt1.plot(df.x,df[data])\n", 748 | " if 'showx' in checkboxlist:\n", 749 | " splt1.xaxis.grid(True)\n", 750 | " if 'showy' in checkboxlist:\n", 751 | " splt1.yaxis.grid(True)\n", 752 | " return fig\n", 753 | " def getData(self,params):\n", 754 | " f=float(params['freq'])\n", 755 | " index=int(params['x_slider'])\n", 756 | " functouse=params['func_type']\n", 757 | " funcdict={\"sin\":np.sin,\"cos\":np.cos}\n", 758 | " func=funcdict[functouse]\n", 759 | " x = pd.Series(np.arange(0,2*np.pi,np.pi/150))\n", 760 | " y1 = pd.Series(func(f*x))\n", 761 | " y2 = pd.Series(func(2*f*x))\n", 762 | " df=pd.concat([x,y1,y2],axis=1)\n", 763 | " df.columns=['x','y1','y2']\n", 764 | " return df[:index]\n", 765 | "\n", 766 | "if __name__ == '__main__':\n", 767 | " app = SimpleSineApp()\n", 768 | " #app.launch()" 769 | ] 770 | }, 771 | { 772 | "cell_type": "markdown", 773 | "metadata": {}, 774 | "source": [ 775 | "As you can see, we've got 5 types of inputs. Each has its own quirks in terms of how you structure the input, but follow the same basic structure as the text. Let's play around with a few...\n", 776 | "\n", 777 | "Alright! As we all know, various use cases require unique solutions, and this should cover most if not all." 778 | ] 779 | }, 780 | { 781 | "cell_type": "markdown", 782 | "metadata": {}, 783 | "source": [ 784 | "## D. Multiple Controls to handle the inputs amongst your tabs" 785 | ] 786 | }, 787 | { 788 | "cell_type": "markdown", 789 | "metadata": {}, 790 | "source": [ 791 | "So far we've created multiple inputs in order to update our webapp. However, we've limited it all to a single control. If any input was changed, all tabs will refresh. Sometimes this is unnecessary, and potentially unwanted. Let's look at an example where we have multiple controls:" 792 | ] 793 | }, 794 | { 795 | "cell_type": "markdown", 796 | "metadata": {}, 797 | "source": [ 798 | "## Script 7" 799 | ] 800 | }, 801 | { 802 | "cell_type": "code", 803 | "execution_count": null, 804 | "metadata": { 805 | "collapsed": true 806 | }, 807 | "outputs": [], 808 | "source": [ 809 | "from spyre import server\n", 810 | "\n", 811 | "import matplotlib.pyplot as plt\n", 812 | "import numpy as np\n", 813 | "import pandas as pd\n", 814 | "\n", 815 | "class SimpleSineApp(server.App):\n", 816 | " title = \"Simple Sine App\"\n", 817 | " inputs = [{ \"type\":\"slider\",\n", 818 | " \"key\":\"x_slider\",\n", 819 | " \"value\":200,\n", 820 | " \"min\":1,\n", 821 | " \"max\":200,\n", 822 | " \"label\":\"x_axis\",\n", 823 | " \"action_id\":\"sine_wave_plot\"},{ \"type\":\"text\",\n", 824 | " \"key\":\"freq\",\n", 825 | " \"value\":5,\n", 826 | " \"label\":\"frequency\",\n", 827 | " \"action_id\":\"sine_wave_data\"}]\n", 828 | " tabs=[\"Plot\",\"Data\"]\n", 829 | " outputs = [{\"type\":\"plot\",\n", 830 | " \"id\":\"wave_plot\",\n", 831 | " \"tab\":\"Plot\",\n", 832 | " \"control_id\":\"sine_wave_data\"},\n", 833 | " {\"type\":\"table\",\n", 834 | " \"id\":\"wave_data\",\n", 835 | " \"tab\":\"Data\",\n", 836 | " \"control_id\":\"sine_wave_plot\"}]\n", 837 | " controls = [{\"type\":\"HIDDEN\",\n", 838 | " \"id\":\"sine_wave_plot\"},\n", 839 | " {\"type\":\"HIDDEN\",\"id\":\"sine_wave_data\"}]\n", 840 | " def getPlot(self, params):\n", 841 | " f = float(params['freq'])\n", 842 | " index=int(params['x_slider'])\n", 843 | " df=self.getData(params)\n", 844 | " fig = plt.figure()\n", 845 | " splt1 = fig.add_subplot(1,1,1)\n", 846 | " splt1.plot(df.x,df.y)\n", 847 | " return fig\n", 848 | " def getData(self,params):\n", 849 | " f=float(params['freq'])\n", 850 | " index=int(params['x_slider'])\n", 851 | " x = pd.Series(np.arange(0,2*np.pi,np.pi/150))\n", 852 | " y = pd.Series(np.sin(f*x))\n", 853 | " df=pd.concat([x,y],axis=1)\n", 854 | " df.columns=['x','y']\n", 855 | " return df[:index]\n", 856 | "\n", 857 | "if __name__ == '__main__':\n", 858 | " app = SimpleSineApp()\n", 859 | " #app.launch()" 860 | ] 861 | }, 862 | { 863 | "cell_type": "markdown", 864 | "metadata": {}, 865 | "source": [ 866 | "While this may not demonstrate the best use case for it, we can clearly see how multiple controls allow us to modify the data in some tabs within our webapp while leaving others untouched. This is all controlled through the list of controls above, and tying each input and output with the respective control id" 867 | ] 868 | }, 869 | { 870 | "cell_type": "markdown", 871 | "metadata": {}, 872 | "source": [ 873 | "## E. Accessing Cherrypy root objects to store local files" 874 | ] 875 | }, 876 | { 877 | "cell_type": "markdown", 878 | "metadata": {}, 879 | "source": [ 880 | "Alright, lets take a step back a minute and go back to our roots, literally. As I mentioned in the beginning of this talk, Data Spyre is built on top of Cherrypy for the backend web portion. However, as with any wrapper, you may lose functionality that the more granular class object has. In our example, we don't have access to all of the features of Cherrypy. While there are other features that may be lost, an important one that is useful is being able to access specified directories from the filesystem as part of the webapp. Let's go through the process, and we'll see a great example of how this is useful." 881 | ] 882 | }, 883 | { 884 | "cell_type": "markdown", 885 | "metadata": {}, 886 | "source": [ 887 | "## Access Cherrypy Root" 888 | ] 889 | }, 890 | { 891 | "cell_type": "code", 892 | "execution_count": null, 893 | "metadata": { 894 | "collapsed": true 895 | }, 896 | "outputs": [], 897 | "source": [ 898 | "def initiate_directs(self,params):\n", 899 | " root=self.getRoot()\n", 900 | " current_dir=os.path.dirname(os.path.abspath(\"__file__\"))\n", 901 | " config_public={\n", 902 | " '/':{\n", 903 | " 'tools.staticdir.root' : current_dir,\n", 904 | " },\n", 905 | " '/static': {\n", 906 | " 'tools.staticdir.on': True,\n", 907 | " 'tools.staticdir.dir': 'public',\n", 908 | " 'tools.staticdir.content_types':{'.min.js':\"text/javascript\",'svg':\"image/svg+xml\"}\n", 909 | "\n", 910 | " }\n", 911 | " }\n", 912 | " cherrypy.tree.mount(root, \"/\", config=config_public)\n" 913 | ] 914 | }, 915 | { 916 | "cell_type": "markdown", 917 | "metadata": {}, 918 | "source": [ 919 | "In order to directly modify our cherrypy instance, we must get access to its root object. After experimenting around a bit, I got the following method to work. Keeping in mind that the Data Spyre application inherits the properties of the Cherrypy app class, we can directly access the root once the class has been initiated. I managed to do this by defining a function and calling it through the output directories in data spyre. It isn't linked to a tab, but the code still runs. I list it first in my list so that it will run first, guaranteeing i have access for all my output runs.\n", 920 | "\n", 921 | "Lets dive into what's going on here: The gist of the config_public dictionary links specific directories in my file system to my webapp. In this example, the directory I am in has a folder 'public', and it is accessable by adding '/static/' to your hyperlink within your webapp. Once we've established this linking, we mount it onto our cherrypy instance. And voila! We now have access to our filesystem through our cherrypy server.\n" 922 | ] 923 | }, 924 | { 925 | "cell_type": "markdown", 926 | "metadata": {}, 927 | "source": [ 928 | "## F. Let's build an app with multiple elements on a single page!" 929 | ] 930 | }, 931 | { 932 | "cell_type": "markdown", 933 | "metadata": {}, 934 | "source": [ 935 | "So far we've leveraged the ability to create multiple tabs, either with data or plots on each tab. However, we currently don't have the capability to introduce multiple elements onto a single page. We could concat multiple dataframes in order to show them all in one tab, and we could leverage matplotlibs subplots to get multiple plots in a single figure. However, we can't get plots and tables onto a single page. In order to do this, we can leverage the getHTML function (along with our cherrypy root) in order to get everything we want into a single page." 936 | ] 937 | }, 938 | { 939 | "cell_type": "markdown", 940 | "metadata": {}, 941 | "source": [ 942 | "## Script 8" 943 | ] 944 | }, 945 | { 946 | "cell_type": "code", 947 | "execution_count": null, 948 | "metadata": { 949 | "collapsed": true 950 | }, 951 | "outputs": [], 952 | "source": [ 953 | "from spyre import server\n", 954 | "\n", 955 | "import matplotlib.pyplot as plt\n", 956 | "import numpy as np\n", 957 | "import pandas as pd\n", 958 | "import os\n", 959 | "import cherrypy\n", 960 | "class SimpleSineApp(server.App):\n", 961 | " title = \"Simple Sine App\"\n", 962 | " inputs = [{ \"type\":\"text\",\n", 963 | " \"key\":\"freq\",\n", 964 | " \"value\":5,\n", 965 | " \"label\":\"frequency\",\n", 966 | " \"action_id\":\"sine_wave_plot\"}]\n", 967 | " outputs = [{\"type\" : \"html\",\n", 968 | " \"id\" : \"initiate_directs\",\n", 969 | " \"on_page_load\" : True },\n", 970 | " {\"type\":\"html\",\n", 971 | " \"id\":\"wave_plot_and_data\",\n", 972 | " \"control_id\":\"sine_wave_plot\"}]\n", 973 | " controls = [{\"type\":\"HIDDEN\",\n", 974 | " \"id\":\"sine_wave_plot\"}]\n", 975 | " def initiate_directs(self,params):\n", 976 | " root=self.getRoot()\n", 977 | " current_dir=os.path.dirname(os.path.abspath(\"__file__\"))\n", 978 | " config_public={\n", 979 | " '/':{\n", 980 | " 'tools.staticdir.root' : current_dir,\n", 981 | " },\n", 982 | " '/static': {\n", 983 | " 'tools.staticdir.on': True,\n", 984 | " 'tools.staticdir.dir': 'public',\n", 985 | " 'tools.staticdir.content_types':{'.min.js':\"text/javascript\",'svg':\"image/svg+xml\"}\n", 986 | " }\n", 987 | " }\n", 988 | " cherrypy.tree.mount(root, \"/\", config=config_public)\n", 989 | " def wave_plot_and_data(self, params):\n", 990 | " f = float(params['freq'])\n", 991 | " df=self.getData(params)\n", 992 | " fig = plt.figure()\n", 993 | " splt1 = fig.add_subplot(1,1,1)\n", 994 | " splt1.plot(df.x,df.y)\n", 995 | " fig.savefig('public/ourfig.png')\n", 996 | " dfhtml=df[:20].to_html(index=False)\n", 997 | " html=''\n", 998 | " finalhtml=html+\"
\"+dfhtml\n", 999 | " return finalhtml\n", 1000 | " def getData(self,params):\n", 1001 | " f=float(params['freq'])\n", 1002 | " x = pd.Series(np.arange(0,2*np.pi,np.pi/150))\n", 1003 | " y = pd.Series(np.sin(f*x))\n", 1004 | " df=pd.concat([x,y],axis=1)\n", 1005 | " df.columns=['x','y']\n", 1006 | " return df\n", 1007 | "\n", 1008 | "if __name__ == '__main__':\n", 1009 | " app = SimpleSineApp()\n", 1010 | " #app.launch()" 1011 | ] 1012 | }, 1013 | { 1014 | "cell_type": "markdown", 1015 | "metadata": {}, 1016 | "source": [ 1017 | "Now, lets go into what just happened here really quickly. \n", 1018 | " - We've created a function that returns some html to be loaded. \n", 1019 | " - To get our image and dataframe onto the same page, we had to mount a directory onto the cherrypy server. \n", 1020 | " - We added a simple image tag in our html, citing the source as our relative html path defined by our cherrypy server. \n", 1021 | " - We saved our file to the directory 'public', which maps to the '/static/' directory in our webapp, allowing us to access our image. \n", 1022 | " - Lastly, pandas dataframes have a handy to_html function which lets us create an html table from our dataframe!\n", 1023 | " \n", 1024 | "Now while I haven't done any formatting, some simple python string replacement functions can be used to modify the html we just created to customize any number of features of our html page, allowing you to present a customly designed front end to data spyre!" 1025 | ] 1026 | }, 1027 | { 1028 | "cell_type": "markdown", 1029 | "metadata": {}, 1030 | "source": [ 1031 | "## G. Yeshup? No, Nohup!" 1032 | ] 1033 | }, 1034 | { 1035 | "cell_type": "markdown", 1036 | "metadata": {}, 1037 | "source": [ 1038 | "From what we've seen in these examples, we have a python connection that stays open in the terminal while we have our webapp running. However, we can make this a background process with nohup! we simply need to call our script as:\n", 1039 | "\n", 1040 | " nohup python script.py &\n", 1041 | "\n", 1042 | "\n", 1043 | "This will run the webapp as a background process. Woo!\n" 1044 | ] 1045 | }, 1046 | { 1047 | "cell_type": "markdown", 1048 | "metadata": {}, 1049 | "source": [ 1050 | "## H. Updating your webapp\n", 1051 | "\n", 1052 | "So far we've also run through several example of how we can update our webapp. However, you don't always want to restart your webapp, especially if you used nohup. An easy way to update your server is by simply updating the file that the server is referencing. If you make some changes and save it, or replace the file with a new file of the same name, your webapp will automatically update the chanages! Simple, but effective." 1053 | ] 1054 | }, 1055 | { 1056 | "cell_type": "markdown", 1057 | "metadata": {}, 1058 | "source": [ 1059 | "---" 1060 | ] 1061 | }, 1062 | { 1063 | "cell_type": "markdown", 1064 | "metadata": {}, 1065 | "source": [ 1066 | "# 5. Let's get Interactive with some plotting libraries!" 1067 | ] 1068 | }, 1069 | { 1070 | "cell_type": "markdown", 1071 | "metadata": {}, 1072 | "source": [ 1073 | "### We've been getting in depth into all the inner workings of Data Spyre , so let's take a step back and focus on our visualizations. While matplotlib is very extensible for most purposes, there are some other great plotting libraries that bring your plotting visualizations to a whole new level, especially with interactivity. Let's dive into a few of them:" 1074 | ] 1075 | }, 1076 | { 1077 | "cell_type": "markdown", 1078 | "metadata": {}, 1079 | "source": [ 1080 | "## A. Bokeh" 1081 | ] 1082 | }, 1083 | { 1084 | "cell_type": "markdown", 1085 | "metadata": {}, 1086 | "source": [ 1087 | "Bokeh is a Python interactive visualization library that targets modern web browsers for presentation. Its goal is to provide elegant, concise construction of novel graphics in the style of D3.js, but also deliver this capability with high-performance interactivity over very large or streaming datasets.\n", 1088 | "\n", 1089 | "Bokeh is very easy to use, and offers a variety of tools to enhance your plot experience, such as hovering, zooming, and selection. It also has a variety of outputs, such as exporting your plot to its own html page, or you could embed it into another html page. It is also built for Jupyter notebook integration, as you can see below." 1090 | ] 1091 | }, 1092 | { 1093 | "cell_type": "markdown", 1094 | "metadata": {}, 1095 | "source": [ 1096 | "## Bokeh Example 1 - Zooming, Panning, and Selection" 1097 | ] 1098 | }, 1099 | { 1100 | "cell_type": "code", 1101 | "execution_count": null, 1102 | "metadata": { 1103 | "collapsed": false 1104 | }, 1105 | "outputs": [], 1106 | "source": [ 1107 | "import numpy as np\n", 1108 | "\n", 1109 | "from bokeh.plotting import figure, show, output_file, vplot\n", 1110 | "from bokeh.io import output_notebook\n", 1111 | "N = 100\n", 1112 | "\n", 1113 | "x = np.linspace(0, 4*np.pi, N)\n", 1114 | "y = np.sin(x)\n", 1115 | "\n", 1116 | "#output_file(\"legend.html\", title=\"legend.py example\")\n", 1117 | "\n", 1118 | "TOOLS = \"pan,wheel_zoom,box_zoom,reset,save,box_select\"\n", 1119 | "\n", 1120 | "p2 = figure(title=\"Another Legend Example\", tools=TOOLS)\n", 1121 | "\n", 1122 | "p2.circle(x, y, legend=\"sin(x)\")\n", 1123 | "p2.line(x, y, legend=\"sin(x)\")\n", 1124 | "\n", 1125 | "p2.line(x, 2*y, legend=\"2*sin(x)\",\n", 1126 | " line_dash=[4, 4], line_color=\"orange\", line_width=2)\n", 1127 | "\n", 1128 | "p2.square(x, 3*y, legend=\"3*sin(x)\", fill_color=None, line_color=\"green\")\n", 1129 | "p2.line(x, 3*y, legend=\"3*sin(x)\", line_color=\"green\")\n", 1130 | "output_notebook()\n", 1131 | "show(p2)# open a browser" 1132 | ] 1133 | }, 1134 | { 1135 | "cell_type": "markdown", 1136 | "metadata": {}, 1137 | "source": [ 1138 | "## Bokeh Example 2 - Hovering" 1139 | ] 1140 | }, 1141 | { 1142 | "cell_type": "code", 1143 | "execution_count": null, 1144 | "metadata": { 1145 | "collapsed": false 1146 | }, 1147 | "outputs": [], 1148 | "source": [ 1149 | "from bokeh.plotting import figure, output_file, show, ColumnDataSource\n", 1150 | "from bokeh.models import HoverTool\n", 1151 | "from bokeh.io import output_notebook\n", 1152 | "\n", 1153 | "source = ColumnDataSource(\n", 1154 | " data=dict(\n", 1155 | " x=[1, 2, 3, 4, 5],\n", 1156 | " y=[2, 5, 8, 2, 7],\n", 1157 | " desc=['A', 'b', 'C', 'd', 'E'],\n", 1158 | " imgs = [\n", 1159 | " 'http://bokeh.pydata.org/static/snake.jpg',\n", 1160 | " 'http://bokeh.pydata.org/static/snake2.png',\n", 1161 | " 'http://bokeh.pydata.org/static/snake3D.png',\n", 1162 | " 'http://bokeh.pydata.org/static/snake4_TheRevenge.png',\n", 1163 | " 'http://bokeh.pydata.org/static/snakebite.jpg'\n", 1164 | " ]\n", 1165 | " )\n", 1166 | " )\n", 1167 | "\n", 1168 | "hover = HoverTool(\n", 1169 | " tooltips=\"\"\"\n", 1170 | "
\n", 1171 | "
\n", 1172 | " \n", 1177 | "
\n", 1178 | "
\n", 1179 | " @desc\n", 1180 | " [$index]\n", 1181 | "
\n", 1182 | "
\n", 1183 | " Location\n", 1184 | " ($x, $y)\n", 1185 | "
\n", 1186 | "
\n", 1187 | " \"\"\"\n", 1188 | " )\n", 1189 | "\n", 1190 | "p = figure(plot_width=400, plot_height=400, tools=[hover],\n", 1191 | " title=\"Mouse over the dots\")\n", 1192 | "\n", 1193 | "p.circle('x', 'y', size=20, source=source)\n", 1194 | "output_notebook()\n", 1195 | "show(p)" 1196 | ] 1197 | }, 1198 | { 1199 | "cell_type": "markdown", 1200 | "metadata": {}, 1201 | "source": [ 1202 | "## Bokeh Example 3 - Color Based Selection and Lasso Selection" 1203 | ] 1204 | }, 1205 | { 1206 | "cell_type": "code", 1207 | "execution_count": null, 1208 | "metadata": { 1209 | "collapsed": false 1210 | }, 1211 | "outputs": [], 1212 | "source": [ 1213 | "import numpy as np\n", 1214 | "from six.moves import zip\n", 1215 | "\n", 1216 | "from bokeh.plotting import figure, show, output_file\n", 1217 | "from bokeh.io import output_notebook\n", 1218 | "N = 4000\n", 1219 | "\n", 1220 | "x = np.random.random(size=N) * 100\n", 1221 | "y = np.random.random(size=N) * 100\n", 1222 | "radii = np.random.random(size=N) * 1.5\n", 1223 | "colors = [\"#%02x%02x%02x\" % (r, g, 150) for r, g in zip(np.floor(50+2*x), np.floor(30+2*y))]\n", 1224 | "\n", 1225 | "TOOLS=\"resize,crosshair,pan,wheel_zoom,box_zoom,reset,tap,previewsave,box_select,poly_select,lasso_select\"\n", 1226 | "\n", 1227 | "\n", 1228 | "p = figure(tools=TOOLS)\n", 1229 | "p.scatter(x, y, radius=radii, fill_color=colors, fill_alpha=0.6, line_color=None)\n", 1230 | "output_notebook()\n", 1231 | "show(p) # open a browser" 1232 | ] 1233 | }, 1234 | { 1235 | "cell_type": "markdown", 1236 | "metadata": {}, 1237 | "source": [ 1238 | "Awesome! We've got some awesome plots! Let's take a look at pygal next." 1239 | ] 1240 | }, 1241 | { 1242 | "cell_type": "markdown", 1243 | "metadata": {}, 1244 | "source": [ 1245 | "## B. Pygal" 1246 | ] 1247 | }, 1248 | { 1249 | "cell_type": "markdown", 1250 | "metadata": {}, 1251 | "source": [ 1252 | "Pygal is library that claims to offer both 'Sexy Python Charting' and 'Simple Python Charting'. If you don't believe me, look up their site. But honestly, this library is very easy to use, and offers some cool interactive plotting features, including hovering as well as toggling for data sets. \n", 1253 | "\n", 1254 | "Disclaimer! In this talk I have some pygal plots rendering in the iPython Notebook, but the full functionality is not present. We will get a better feel for the full functionality in a webapp example at the end of the talk." 1255 | ] 1256 | }, 1257 | { 1258 | "cell_type": "markdown", 1259 | "metadata": {}, 1260 | "source": [ 1261 | "## Pygal Example 1 - Line Highlighting" 1262 | ] 1263 | }, 1264 | { 1265 | "cell_type": "code", 1266 | "execution_count": null, 1267 | "metadata": { 1268 | "collapsed": false 1269 | }, 1270 | "outputs": [], 1271 | "source": [ 1272 | "%matplotlib inline\n", 1273 | "from IPython.display import SVG, HTML\n", 1274 | "html_pygal = \"\"\"\n", 1275 | "\n", 1276 | "\n", 1277 | " \n", 1278 | " \n", 1279 | " \n", 1280 | " \n", 1281 | " \n", 1282 | " \n", 1283 | "
\n", 1284 | " {pygal_render}\n", 1285 | "
\n", 1286 | " \n", 1287 | "\n", 1288 | "\"\"\"\n", 1289 | "\n", 1290 | "import pygal\n", 1291 | "line_chart = pygal.Line()\n", 1292 | "line_chart.title = 'Browser usage evolution (in %)'\n", 1293 | "line_chart.x_labels = map(str, range(2002, 2013))\n", 1294 | "line_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1])\n", 1295 | "line_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3])\n", 1296 | "line_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1])\n", 1297 | "line_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5])\n", 1298 | "HTML(html_pygal.format(pygal_render=line_chart.render()))\n" 1299 | ] 1300 | }, 1301 | { 1302 | "cell_type": "markdown", 1303 | "metadata": {}, 1304 | "source": [ 1305 | "## Pygal Example 2 - Area Highlighting" 1306 | ] 1307 | }, 1308 | { 1309 | "cell_type": "code", 1310 | "execution_count": null, 1311 | "metadata": { 1312 | "collapsed": false 1313 | }, 1314 | "outputs": [], 1315 | "source": [ 1316 | "%matplotlib inline\n", 1317 | "from IPython.display import SVG, HTML\n", 1318 | "html_pygal = \"\"\"\n", 1319 | "\n", 1320 | "\n", 1321 | " \n", 1322 | " \n", 1323 | " \n", 1324 | " \n", 1325 | " \n", 1326 | " \n", 1327 | "
\n", 1328 | " {pygal_render}\n", 1329 | "
\n", 1330 | " \n", 1331 | "\n", 1332 | "\"\"\"\n", 1333 | "\n", 1334 | "import pygal\n", 1335 | "stackedline_chart = pygal.StackedLine(fill=True)\n", 1336 | "stackedline_chart.title = 'Browser usage evolution (in %)'\n", 1337 | "stackedline_chart.x_labels = map(str, range(2002, 2013))\n", 1338 | "stackedline_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1])\n", 1339 | "stackedline_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3])\n", 1340 | "stackedline_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1])\n", 1341 | "stackedline_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5])\n", 1342 | "HTML(html_pygal.format(pygal_render=stackedline_chart.render()))" 1343 | ] 1344 | }, 1345 | { 1346 | "cell_type": "markdown", 1347 | "metadata": {}, 1348 | "source": [ 1349 | "## Pygal Example 3 - Multiple Line Types" 1350 | ] 1351 | }, 1352 | { 1353 | "cell_type": "code", 1354 | "execution_count": null, 1355 | "metadata": { 1356 | "collapsed": false 1357 | }, 1358 | "outputs": [], 1359 | "source": [ 1360 | "%matplotlib inline\n", 1361 | "from IPython.display import SVG, HTML\n", 1362 | "html_pygal = \"\"\"\n", 1363 | "\n", 1364 | "\n", 1365 | " \n", 1366 | " \n", 1367 | " \n", 1368 | " \n", 1369 | " \n", 1370 | " \n", 1371 | "
\n", 1372 | " {pygal_render}\n", 1373 | "
\n", 1374 | " \n", 1375 | "\n", 1376 | "\"\"\"\n", 1377 | "import pygal\n", 1378 | "from math import cos\n", 1379 | "xy_chart = pygal.XY()\n", 1380 | "xy_chart.title = 'XY Cosinus'\n", 1381 | "xy_chart.add('x = cos(y)', [(cos(x / 10.), x / 10.) for x in range(-50, 50, 5)])\n", 1382 | "xy_chart.add('y = cos(x)', [(x / 10., cos(x / 10.)) for x in range(-50, 50, 5)])\n", 1383 | "xy_chart.add('x = 1', [(1, -5), (1, 5)])\n", 1384 | "xy_chart.add('x = -1', [(-1, -5), (-1, 5)])\n", 1385 | "xy_chart.add('y = 1', [(-5, 1), (5, 1)])\n", 1386 | "xy_chart.add('y = -1', [(-5, -1), (5, -1)])\n", 1387 | "HTML(html_pygal.format(pygal_render=xy_chart.render()))" 1388 | ] 1389 | }, 1390 | { 1391 | "cell_type": "markdown", 1392 | "metadata": {}, 1393 | "source": [ 1394 | "Beautiful! We can see their full functionality later on, but for now let's move onto BQPlot" 1395 | ] 1396 | }, 1397 | { 1398 | "cell_type": "markdown", 1399 | "metadata": {}, 1400 | "source": [ 1401 | "## C. BQplot" 1402 | ] 1403 | }, 1404 | { 1405 | "cell_type": "markdown", 1406 | "metadata": {}, 1407 | "source": [ 1408 | "Last month Bloomberg open sourced their internal python plotting library, known as bqplot! It is built on top of the ipython widgets library for use within a Jupyter notebook. We will explore some of its functionality within the notebook here:" 1409 | ] 1410 | }, 1411 | { 1412 | "cell_type": "markdown", 1413 | "metadata": {}, 1414 | "source": [ 1415 | "## BQplot Example 1 - Highlighting Sections of Data" 1416 | ] 1417 | }, 1418 | { 1419 | "cell_type": "code", 1420 | "execution_count": null, 1421 | "metadata": { 1422 | "collapsed": true 1423 | }, 1424 | "outputs": [], 1425 | "source": [ 1426 | "import pandas as pd\n", 1427 | "import numpy as np\n", 1428 | "symbol = 'Security 1'\n", 1429 | "price_data = pd.DataFrame(np.cumsum(np.random.randn(150, 2).dot([[0.5, 0.4], [0.4, 1.0]]), axis=0) + 100,\n", 1430 | " columns=['Security 1', 'Security 2'], index=pd.date_range(start='01-01-2007', periods=150))\n", 1431 | "\n", 1432 | "dates_actual = price_data.index.values\n", 1433 | "prices = price_data[symbol].values\n", 1434 | "\n", 1435 | "from bqplot import *\n", 1436 | "from bqplot.interacts import *\n", 1437 | "from traitlets import link\n", 1438 | "\n", 1439 | "from IPython.display import display\n", 1440 | "from ipywidgets import Latex, ToggleButtons, VBox\n", 1441 | "\n", 1442 | "\n", 1443 | "## call back for selectors\n", 1444 | "def interval_change_callback(name, value):\n", 1445 | " db.value = str(value)\n", 1446 | "\n", 1447 | "## call back for selectors\n", 1448 | "def date_interval_change_callback(name, value):\n", 1449 | " db_date.value = str(value)\n", 1450 | " \n", 1451 | "from datetime import datetime as py_dtime\n", 1452 | "\n", 1453 | "dt_x = DateScale(min=np.datetime64(py_dtime(2006, 6, 1)))\n", 1454 | "\n", 1455 | "\n", 1456 | "lc2_y = LinearScale()\n", 1457 | "\n", 1458 | "lc2 = Lines(x=dates_actual, y=prices,\n", 1459 | " scales={'x': dt_x, 'y': lc2_y})\n", 1460 | "\n", 1461 | "x_ax1 = Axis(label=\"Date\", scale = dt_x)\n", 1462 | "x_ay2 = Axis(label=(symbol + \" Price\"), scale = lc2_y, orientation=\"vertical\", tick_format=\"0.2f\")\n", 1463 | "\n", 1464 | "intsel_date = FastIntervalSelector(scale=dt_x, marks=[lc2])\n", 1465 | "db_date = Latex()\n", 1466 | "db_date.value = str(intsel_date.selected)\n", 1467 | "display(db_date)\n", 1468 | "lc2.on_trait_change(date_interval_change_callback, name='selected')\n", 1469 | "\n", 1470 | "fig = Figure(marks=[lc2], axes=[x_ax1, x_ay2], interaction=intsel_date)\n", 1471 | "display(fig)\n", 1472 | "\n", 1473 | "intsel_date = BrushIntervalSelector(scale=dt_x, marks=[lc2], color='blue')\n", 1474 | "lc2.on_trait_change(date_interval_change_callback, name='selected')\n", 1475 | "fig.interaction = intsel_date" 1476 | ] 1477 | }, 1478 | { 1479 | "cell_type": "markdown", 1480 | "metadata": {}, 1481 | "source": [ 1482 | "## BQPlot Example 2 -Zooming and Panning" 1483 | ] 1484 | }, 1485 | { 1486 | "cell_type": "code", 1487 | "execution_count": null, 1488 | "metadata": { 1489 | "collapsed": true 1490 | }, 1491 | "outputs": [], 1492 | "source": [ 1493 | "from __future__ import print_function\n", 1494 | "from bqplot import pyplot as plt\n", 1495 | "from bqplot import topo_load\n", 1496 | "from bqplot.interacts import panzoom\n", 1497 | "from numpy import *\n", 1498 | "import pandas as pd\n", 1499 | "\n", 1500 | "random.seed(0)\n", 1501 | "size = 100\n", 1502 | "y_data = cumsum(random.randn(size) * 100.0)\n", 1503 | "y_data_2 = cumsum(random.randn(size))\n", 1504 | "y_data_3 = cumsum(random.randn(size) * 100.)\n", 1505 | "\n", 1506 | "plt.figure(1)\n", 1507 | "n = 100\n", 1508 | "x = linspace(0.0, 10.0, n)\n", 1509 | "plt.plot(x, y_data, axes_options={'y': {'grid_lines': 'dashed'}})\n", 1510 | "plt.show()" 1511 | ] 1512 | }, 1513 | { 1514 | "cell_type": "markdown", 1515 | "metadata": {}, 1516 | "source": [ 1517 | "## BQPlot Example 3 - Hovering" 1518 | ] 1519 | }, 1520 | { 1521 | "cell_type": "code", 1522 | "execution_count": null, 1523 | "metadata": { 1524 | "collapsed": true 1525 | }, 1526 | "outputs": [], 1527 | "source": [ 1528 | "from __future__ import print_function\n", 1529 | "import numpy as np\n", 1530 | "import pandas as pd\n", 1531 | "from IPython.display import display\n", 1532 | "from bqplot import *\n", 1533 | "\n", 1534 | "price_data = pd.DataFrame(np.cumsum(np.random.randn(150, 2).dot([[1.0, -0.8], [-0.8, 1.0]]), axis=0) + 100,\n", 1535 | " columns=['Security 1', 'Security 2'], index=pd.date_range(start='01-01-2007', periods=150))\n", 1536 | "size = 100\n", 1537 | "np.random.seed(0)\n", 1538 | "x_data = range(size)\n", 1539 | "y_data = np.cumsum(np.random.randn(size) * 100.0)\n", 1540 | "ord_keys = np.array(['A', 'B', 'C', 'D', 'E', 'F'])\n", 1541 | "ordinal_data = np.random.randint(5, size=size)\n", 1542 | "x_sc = LinearScale()\n", 1543 | "y_sc = LinearScale()\n", 1544 | "\n", 1545 | "x_data = x_data[:50]\n", 1546 | "y_data = y_data[:50]\n", 1547 | "\n", 1548 | "def_tt = Tooltip(fields=['x', 'y'], formats=['', '.2f'])\n", 1549 | "\n", 1550 | "scatter_chart = Scatter(x=x_data, y=y_data, scales= {'x': x_sc, 'y': y_sc}, default_colors=['dodgerblue'],\n", 1551 | " tooltip=def_tt)\n", 1552 | "ax_x = Axis(scale=x_sc)\n", 1553 | "ax_y = Axis(scale=y_sc, orientation='vertical', tick_format='0.2f')\n", 1554 | "\n", 1555 | "fig = Figure(marks=[scatter_chart], axes=[ax_x, ax_y])\n", 1556 | "display(fig)" 1557 | ] 1558 | }, 1559 | { 1560 | "cell_type": "markdown", 1561 | "metadata": {}, 1562 | "source": [ 1563 | "## BQPlot Example 4 - Hovering over a plot to get another Plot!" 1564 | ] 1565 | }, 1566 | { 1567 | "cell_type": "code", 1568 | "execution_count": null, 1569 | "metadata": { 1570 | "collapsed": false 1571 | }, 1572 | "outputs": [], 1573 | "source": [ 1574 | "import pandas as pd\n", 1575 | "from IPython.display import display\n", 1576 | "from ipywidgets import Latex\n", 1577 | "from bqplot import *\n", 1578 | "from bqplot.market_map import MarketMap\n", 1579 | "\n", 1580 | "data = pd.read_csv('data_files/country_codes.csv', index_col=[0])\n", 1581 | "country_codes = data.index.values\n", 1582 | "country_names = data['Name']\n", 1583 | "\n", 1584 | "gdp_data = pd.read_csv('data_files/gdp_per_capita.csv', index_col=[0], parse_dates=True)\n", 1585 | "gdp_data.fillna(method='backfill', inplace=True)\n", 1586 | "gdp_data.fillna(method='ffill', inplace=True)\n", 1587 | "\n", 1588 | "col = ColorScale(scheme='Greens')\n", 1589 | "continents = data['Continent'].values\n", 1590 | "ax_c = ColorAxis(scale=col, label='GDP per Capita', visible=False)\n", 1591 | "\n", 1592 | "data['GDP'] = gdp_data.ix[-1]\n", 1593 | "\n", 1594 | "market_map = MarketMap(names=country_codes, groups=continents, # Basic data which needs to set for each map\n", 1595 | " cols=25, row_groups=3, # Properties for the visualization\n", 1596 | " ref_data=data, # Data frame used for different properties of the map\n", 1597 | " tooltip_fields=['Name', 'Continent', 'GDP'], # Columns from data frame to be displayed as tooltip\n", 1598 | " tooltip_formats=['', '', '.1f'],\n", 1599 | " scales={'color': col}, axes=[ax_c]) # Axis and scale for color data\n", 1600 | "\n", 1601 | "deb_output = Latex()\n", 1602 | "def selected_index_changed(name, value):\n", 1603 | " deb_output.value = str(value)\n", 1604 | " \n", 1605 | "market_map.on_trait_change(selected_index_changed, name='selected')\n", 1606 | "\n", 1607 | "# Creating the figure to be displayed as the tooltip\n", 1608 | "sc_x = DateScale()\n", 1609 | "sc_y = LinearScale()\n", 1610 | "\n", 1611 | "ax_x = Axis(scale=sc_x, grid_lines='dashed', label='Date')\n", 1612 | "ax_y = Axis(scale=sc_y, orientation='vertical', grid_lines='dashed',\n", 1613 | " label='GDP', label_location='end', label_offset='-1em')\n", 1614 | "\n", 1615 | "line = Lines(x= gdp_data.index.values, scales={'x': sc_x, 'y': sc_y}, colors=['orange'])\n", 1616 | "fig_tooltip = Figure(marks=[line], axes=[ax_x, ax_y], min_width=600, min_height=400)\n", 1617 | "\n", 1618 | "market_map = MarketMap(names=country_codes, groups=continents,\n", 1619 | " cols=25, row_groups=3,\n", 1620 | " color=data['GDP'], scales={'color': col}, axes=[ax_c],\n", 1621 | " ref_data=data, tooltip_widget=fig_tooltip)\n", 1622 | "\n", 1623 | "# Update the tooltip chart\n", 1624 | "hovered_symbol = ''\n", 1625 | "def hover_handler(self, content):\n", 1626 | " global hovered_symbol\n", 1627 | " symbol = content.get('ref_data', {}).get('Country Code', '')\n", 1628 | " if(symbol != hovered_symbol):\n", 1629 | " hovered_symbol = symbol\n", 1630 | " if(gdp_data.get(hovered_symbol) is not None):\n", 1631 | " line.y = gdp_data[hovered_symbol].values\n", 1632 | " fig_tooltip.title = hovered_symbol\n", 1633 | " \n", 1634 | "# Custom msg sent when a particular cell is hovered on\n", 1635 | "market_map.on_hover(hover_handler)\n", 1636 | "display(market_map)" 1637 | ] 1638 | }, 1639 | { 1640 | "cell_type": "markdown", 1641 | "metadata": {}, 1642 | "source": [ 1643 | "Wow! We have tons of cool ways to visualize our data. The next step is to incorporate these styles of plots into our Data Spyre application. As I said previously, both Bokeh and Pygal are easy to move over with HTML or SVG files, respectively. BQPlot is currently built on the ipython widgets library, which is currently only supported in an iPython environment. However, there is an effort underway to export ipython widget functionality outside of the notebook environment, giving hope that this library will also be able to integrate into Data Spyre in the future." 1644 | ] 1645 | }, 1646 | { 1647 | "cell_type": "markdown", 1648 | "metadata": {}, 1649 | "source": [ 1650 | "# 6. The Grand Finale: Interactive Plots in Data Spyre!" 1651 | ] 1652 | }, 1653 | { 1654 | "cell_type": "markdown", 1655 | "metadata": {}, 1656 | "source": [ 1657 | "Here we are! The final step of our journey tonight. We're now experts in Data Spyre, we have some new plotting tools up our sleeve, and we' ve got some data to plot! All we have left to do is compine all of them. Let's first look at including our Sine Wave as a Bokeh Plot:" 1658 | ] 1659 | }, 1660 | { 1661 | "cell_type": "markdown", 1662 | "metadata": {}, 1663 | "source": [ 1664 | "## Script 9" 1665 | ] 1666 | }, 1667 | { 1668 | "cell_type": "code", 1669 | "execution_count": null, 1670 | "metadata": { 1671 | "collapsed": true 1672 | }, 1673 | "outputs": [], 1674 | "source": [ 1675 | "from spyre import server\n", 1676 | "\n", 1677 | "import matplotlib.pyplot as plt\n", 1678 | "import numpy as np\n", 1679 | "import pandas as pd\n", 1680 | "\n", 1681 | "from bokeh.charts import Donut\n", 1682 | "from bokeh.resources import INLINE\n", 1683 | "from bokeh.resources import CDN\n", 1684 | "from bokeh.embed import components\n", 1685 | "from bokeh.plotting import figure, show, output_file, vplot\n", 1686 | "\n", 1687 | "class SimpleSineApp(server.App):\n", 1688 | " title = \"Simple Sine App\"\n", 1689 | " inputs = [{ \"type\":\"text\",\n", 1690 | " \"key\":\"freq\",\n", 1691 | " \"value\":5,\n", 1692 | " \"label\":\"frequency\",\n", 1693 | " \"action_id\":\"sine_wave_plot\"}]\n", 1694 | " tabs=[\"Plot\",\"Data\"]\n", 1695 | " outputs = [{\"type\":\"html\",\n", 1696 | " \"id\":\"wave_plot\",\n", 1697 | " \"tab\":\"Plot\",\n", 1698 | " \"control_id\":\"sine_wave_plot\"},\n", 1699 | " {\"type\":\"table\",\n", 1700 | " \"id\":\"wave_data\",\n", 1701 | " \"tab\":\"Data\",\n", 1702 | " \"control_id\":\"sine_wave_plot\"}]\n", 1703 | " controls = [{\"type\":\"HIDDEN\",\n", 1704 | " \"id\":\"sine_wave_plot\"}]\n", 1705 | " def getHTML(self, params):\n", 1706 | " f = float(params['freq'])\n", 1707 | " df=self.getData(params)\n", 1708 | "\n", 1709 | " TOOLS = \"pan,wheel_zoom,box_zoom,reset,save,box_select\"\n", 1710 | " p2 = figure(title=\"Another Sine Example\", tools=TOOLS)\n", 1711 | " p2.circle(df.x, df.y, legend=\"sin(x)\")\n", 1712 | " p2.line(df.x, df.y, legend=\"sin(x)\")\n", 1713 | " script, div = components(p2, CDN)\n", 1714 | " html = \"%s\\n%s\"%(script, div)\n", 1715 | "\n", 1716 | " return html\n", 1717 | " \n", 1718 | " def getData(self,params):\n", 1719 | " f=float(params['freq'])\n", 1720 | " x = pd.Series(np.arange(0,2*np.pi,np.pi/150))\n", 1721 | " y = pd.Series(np.sin(f*x))\n", 1722 | " df=pd.concat([x,y],axis=1)\n", 1723 | " df.columns=['x','y']\n", 1724 | " return df\n", 1725 | " \n", 1726 | " def getCustomJS(self):\n", 1727 | " return INLINE.js_raw[0]\n", 1728 | "\n", 1729 | " def getCustomCSS(self):\n", 1730 | " return INLINE.css_raw[0]\n", 1731 | "if __name__ == '__main__':\n", 1732 | " app = SimpleSineApp()\n", 1733 | " #app.launch()" 1734 | ] 1735 | }, 1736 | { 1737 | "cell_type": "markdown", 1738 | "metadata": {}, 1739 | "source": [ 1740 | "As we've done before let's breakdown what we've done here to get this working:\n", 1741 | " - getHTML - Bokeh can return plots as html, so we will want to leverage this functionality of Data Spyre\n", 1742 | " - Script and Div - If you notice, we call the components function from bokeh.embed. This is to pull out the necessary information to get our HTML\n", 1743 | " - Added two new functions - We've overwritten 2 additional functions in our app, specifically getCustomJS and getCustomCSS. We pull out the necessary js and css for our plot straight from Bokeh, and return it. This ensure our plots will have the necessary functionality in our webapp.\n", 1744 | " \n", 1745 | "And that's it! With a few additions and modifications to our code, we have a Bokeh plot in our webapp!" 1746 | ] 1747 | }, 1748 | { 1749 | "cell_type": "markdown", 1750 | "metadata": {}, 1751 | "source": [ 1752 | "Now, let's incorporate the Pygal version of our sine wave (in this case, let's plot two waves on one plot)" 1753 | ] 1754 | }, 1755 | { 1756 | "cell_type": "markdown", 1757 | "metadata": {}, 1758 | "source": [ 1759 | "## Script 10" 1760 | ] 1761 | }, 1762 | { 1763 | "cell_type": "code", 1764 | "execution_count": null, 1765 | "metadata": { 1766 | "collapsed": true 1767 | }, 1768 | "outputs": [], 1769 | "source": [ 1770 | "from spyre import server\n", 1771 | "\n", 1772 | "import matplotlib.pyplot as plt\n", 1773 | "import numpy as np\n", 1774 | "import pandas as pd\n", 1775 | "import pygal\n", 1776 | "import cherrypy\n", 1777 | "import os \n", 1778 | "\n", 1779 | "class SimpleSineApp(server.App):\n", 1780 | " title = \"Simple Sine App\"\n", 1781 | " inputs = [{ \"type\":\"text\",\n", 1782 | " \"key\":\"freq\",\n", 1783 | " \"value\":5,\n", 1784 | " \"label\":\"frequency\",\n", 1785 | " \"action_id\":\"sine_wave_plot\"}]\n", 1786 | " tabs=[\"Plot\",\"Data\"]\n", 1787 | " outputs = [{\"type\" : \"html\",\n", 1788 | " \"id\" : \"initiate_directs\",\n", 1789 | " \"on_page_load\" : True },\n", 1790 | " {\"type\":\"html\",\n", 1791 | " \"id\":\"wave_plot\",\n", 1792 | " \"tab\":\"Plot\",\n", 1793 | " \"control_id\":\"sine_wave_plot\"},\n", 1794 | " {\"type\":\"table\",\n", 1795 | " \"id\":\"wave_data\",\n", 1796 | " \"tab\":\"Data\",\n", 1797 | " \"control_id\":\"sine_wave_plot\"}]\n", 1798 | "\n", 1799 | " controls = [{\"type\":\"HIDDEN\",\n", 1800 | " \"id\":\"sine_wave_plot\"}]\n", 1801 | " \n", 1802 | " def initiate_directs(self,params):\n", 1803 | " root=self.getRoot()\n", 1804 | " current_dir=os.path.dirname(os.path.abspath(\"__file__\"))\n", 1805 | " config_public={\n", 1806 | " '/':{\n", 1807 | " 'tools.staticdir.root' : current_dir,\n", 1808 | " },\n", 1809 | " '/static': {\n", 1810 | " 'tools.staticdir.on': True,\n", 1811 | " 'tools.staticdir.dir': 'public',\n", 1812 | " 'tools.staticdir.content_types':{'.min.js':\"text/javascript\",'svg':\"image/svg+xml\"}\n", 1813 | " }\n", 1814 | " }\n", 1815 | " cherrypy.tree.mount(root, \"/\", config=config_public)\n", 1816 | " def wave_plot(self, params):\n", 1817 | " #self.initiate_directs(params)\n", 1818 | " f = float(params['freq'])\n", 1819 | " df=self.getData(params)\n", 1820 | " line_chart = pygal.Line(height=400,width=600,show_minor_x_labels=False,x_label_rotation=45)\n", 1821 | " line_chart.title = 'Sine Wave in Pygal'\n", 1822 | " line_chart.x_labels = [\"{0:.2f}\".format(a) for a in df.x.tolist()]\n", 1823 | " line_chart.add('Sin(y)',df.y.tolist())\n", 1824 | " line_chart.add('Sin(2y)',df.y2.tolist())\n", 1825 | " \n", 1826 | " line_chart.x_labels_major=line_chart.x_labels[::30]\n", 1827 | " line_chart.render_to_file('public/pygalspyre.svg')\n", 1828 | " html=\"\"\"
\"\"\"\n", 1829 | "\n", 1830 | " return html\n", 1831 | " \n", 1832 | " def getData(self,params):\n", 1833 | " f=float(params['freq'])\n", 1834 | " x = pd.Series(np.arange(0,2*np.pi,np.pi/150))\n", 1835 | " y = pd.Series(np.sin(f*x))\n", 1836 | " y2= pd.Series(np.sin(f*x*2))\n", 1837 | " df=pd.concat([x,y,y2],axis=1)\n", 1838 | " df.columns=['x','y','y2']\n", 1839 | " return df\n", 1840 | "\n", 1841 | "if __name__ == '__main__':\n", 1842 | " app = SimpleSineApp()\n", 1843 | " #app.launch()" 1844 | ] 1845 | }, 1846 | { 1847 | "cell_type": "markdown", 1848 | "metadata": {}, 1849 | "source": [ 1850 | "Here's the breakdown on what we've done to set this up:\n", 1851 | " - Return with html - As with bokeh, we will want to return html for our pygal object. However, we aren't using an export function here. We are saving the file to the filesystem, and accessing with a short html string.\n", 1852 | " - Accessed Cherrypy root - Since we save our SVG's to the filesystem, we will want to reference them in our html. To do this, we need to include the cherrypy root as we did earlier\n", 1853 | "\n", 1854 | "There are a couple stumbling blocks I've encountered that I would also like to point out:\n", 1855 | " - When using the cherrypy initiate_directs function, do NOT include any getHTML overrides. Data Spyre will see the getHTML function, and when it sees the initiate_directs output, it will prioritize the getHTML function over the named function\n", 1856 | " - If you look at the code for the SVG file, you will notice a javascript file that is referenced (it is also referenced earlier to generate our pygal plots in the notebook). This may be a limiting factor when your server doesn't have access to an outside network. You may also just prefer to host the javascript locally for reliability. Pygal plots support custom arguments for javascript files. An easy way to incorporate this into your workflow is store the .js file in your /public/ folder, and reference it locally as we are with the image files." 1857 | ] 1858 | }, 1859 | { 1860 | "cell_type": "markdown", 1861 | "metadata": {}, 1862 | "source": [ 1863 | "# And We're Done!" 1864 | ] 1865 | }, 1866 | { 1867 | "cell_type": "markdown", 1868 | "metadata": {}, 1869 | "source": [ 1870 | "## Let's wrap up everything we've covered:\n", 1871 | "- We've created a basic web application that is easy to set up with minimal coding required\n", 1872 | "- In our webapp, we've added data, plots, and controls to update our data and plot\n", 1873 | "- We've also managed to leverage the power of additional interactive plotting libraries and put them into our plot as well!\n", 1874 | "\n", 1875 | "### With all of that in mind, all of you should have the basic tools to go out and build your own web application." 1876 | ] 1877 | }, 1878 | { 1879 | "cell_type": "markdown", 1880 | "metadata": {}, 1881 | "source": [ 1882 | "# Thanks for Coming!\n", 1883 | "## And Thanks to Adam Hajari, who developed this library, and whose previous talks were used as a jumping off point for this talk\n", 1884 | "# Any Questions?\n" 1885 | ] 1886 | } 1887 | ], 1888 | "metadata": { 1889 | "kernelspec": { 1890 | "display_name": "Python 2", 1891 | "language": "python", 1892 | "name": "python2" 1893 | }, 1894 | "language_info": { 1895 | "codemirror_mode": { 1896 | "name": "ipython", 1897 | "version": 2 1898 | }, 1899 | "file_extension": ".py", 1900 | "mimetype": "text/x-python", 1901 | "name": "python", 1902 | "nbconvert_exporter": "python", 1903 | "pygments_lexer": "ipython2", 1904 | "version": "2.7.10" 1905 | } 1906 | }, 1907 | "nbformat": 4, 1908 | "nbformat_minor": 0 1909 | } 1910 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | DataSpyre Tutorial 2 | 3 | In this repo I attached the ipython notebook and all scripts and data used during my talk on 11/11/15 at the Kansas City Data Science Meetup. The talk focuses on how to build a data spyre webapp in python, and how to integrate some interactive libraries, specifically Bokeh and Pygal. 4 | 5 | 6 | -------------------------------------------------------------------------------- /bokeh_example_1.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from bokeh.plotting import figure, show, output_file, vplot 4 | from bokeh.io import output_notebook 5 | N = 100 6 | 7 | x = np.linspace(0, 4*np.pi, N) 8 | y = np.sin(x) 9 | 10 | #output_file("legend.html", title="legend.py example") 11 | 12 | TOOLS = "pan,wheel_zoom,box_zoom,reset,save,box_select" 13 | 14 | p2 = figure(title="Another Legend Example", tools=TOOLS) 15 | 16 | p2.circle(x, y, legend="sin(x)") 17 | p2.line(x, y, legend="sin(x)") 18 | 19 | p2.line(x, 2*y, legend="2*sin(x)", 20 | line_dash=[4, 4], line_color="orange", line_width=2) 21 | 22 | p2.square(x, 3*y, legend="3*sin(x)", fill_color=None, line_color="green") 23 | p2.line(x, 3*y, legend="3*sin(x)", line_color="green") 24 | output_notebook() 25 | show(p2)# open a browser -------------------------------------------------------------------------------- /bokeh_example_2.py: -------------------------------------------------------------------------------- 1 | from bokeh.plotting import figure, output_file, show, ColumnDataSource 2 | from bokeh.models import HoverTool 3 | from bokeh.io import output_notebook 4 | 5 | source = ColumnDataSource( 6 | data=dict( 7 | x=[1, 2, 3, 4, 5], 8 | y=[2, 5, 8, 2, 7], 9 | desc=['A', 'b', 'C', 'd', 'E'], 10 | imgs = [ 11 | 'http://bokeh.pydata.org/static/snake.jpg', 12 | 'http://bokeh.pydata.org/static/snake2.png', 13 | 'http://bokeh.pydata.org/static/snake3D.png', 14 | 'http://bokeh.pydata.org/static/snake4_TheRevenge.png', 15 | 'http://bokeh.pydata.org/static/snakebite.jpg' 16 | ] 17 | ) 18 | ) 19 | 20 | hover = HoverTool( 21 | tooltips=""" 22 |
23 |
24 | @imgs 29 |
30 |
31 | @desc 32 | [$index] 33 |
34 |
35 | Location 36 | ($x, $y) 37 |
38 |
39 | """ 40 | ) 41 | 42 | p = figure(plot_width=400, plot_height=400, tools=[hover], 43 | title="Mouse over the dots") 44 | 45 | p.circle('x', 'y', size=20, source=source) 46 | output_notebook() 47 | show(p) -------------------------------------------------------------------------------- /bokeh_example_3.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from six.moves import zip 3 | 4 | from bokeh.plotting import figure, show, output_file 5 | from bokeh.io import output_notebook 6 | N = 4000 7 | 8 | x = np.random.random(size=N) * 100 9 | y = np.random.random(size=N) * 100 10 | radii = np.random.random(size=N) * 1.5 11 | colors = ["#%02x%02x%02x" % (r, g, 150) for r, g in zip(np.floor(50+2*x), np.floor(30+2*y))] 12 | 13 | TOOLS="resize,crosshair,pan,wheel_zoom,box_zoom,reset,tap,previewsave,box_select,poly_select,lasso_select" 14 | 15 | 16 | p = figure(tools=TOOLS) 17 | p.scatter(x, y, radius=radii, fill_color=colors, fill_alpha=0.6, line_color=None) 18 | output_notebook() 19 | show(p) # open a browser -------------------------------------------------------------------------------- /bqplot_example_1.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | symbol = 'Security 1' 4 | price_data = pd.DataFrame(np.cumsum(np.random.randn(150, 2).dot([[0.5, 0.4], [0.4, 1.0]]), axis=0) + 100, 5 | columns=['Security 1', 'Security 2'], index=pd.date_range(start='01-01-2007', periods=150)) 6 | 7 | dates_actual = price_data.index.values 8 | prices = price_data[symbol].values 9 | 10 | from bqplot import * 11 | from bqplot.interacts import * 12 | from traitlets import link 13 | 14 | from IPython.display import display 15 | from ipywidgets import Latex, ToggleButtons, VBox 16 | 17 | 18 | ## call back for selectors 19 | def interval_change_callback(name, value): 20 | db.value = str(value) 21 | 22 | ## call back for selectors 23 | def date_interval_change_callback(name, value): 24 | db_date.value = str(value) 25 | 26 | from datetime import datetime as py_dtime 27 | 28 | dt_x = DateScale(min=np.datetime64(py_dtime(2006, 6, 1))) 29 | 30 | 31 | lc2_y = LinearScale() 32 | 33 | lc2 = Lines(x=dates_actual, y=prices, 34 | scales={'x': dt_x, 'y': lc2_y}) 35 | 36 | x_ax1 = Axis(label="Date", scale = dt_x) 37 | x_ay2 = Axis(label=(symbol + " Price"), scale = lc2_y, orientation="vertical", tick_format="0.2f") 38 | 39 | intsel_date = FastIntervalSelector(scale=dt_x, marks=[lc2]) 40 | db_date = Latex() 41 | db_date.value = str(intsel_date.selected) 42 | display(db_date) 43 | lc2.on_trait_change(date_interval_change_callback, name='selected') 44 | 45 | fig = Figure(marks=[lc2], axes=[x_ax1, x_ay2], interaction=intsel_date) 46 | display(fig) 47 | 48 | intsel_date = BrushIntervalSelector(scale=dt_x, marks=[lc2], color='blue') 49 | lc2.on_trait_change(date_interval_change_callback, name='selected') 50 | fig.interaction = intsel_date -------------------------------------------------------------------------------- /bqplot_example_2.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | from bqplot import pyplot as plt 3 | from bqplot import topo_load 4 | from bqplot.interacts import panzoom 5 | from numpy import * 6 | import pandas as pd 7 | 8 | random.seed(0) 9 | size = 100 10 | y_data = cumsum(random.randn(size) * 100.0) 11 | y_data_2 = cumsum(random.randn(size)) 12 | y_data_3 = cumsum(random.randn(size) * 100.) 13 | 14 | plt.figure(1) 15 | n = 100 16 | x = linspace(0.0, 10.0, n) 17 | plt.plot(x, y_data, axes_options={'y': {'grid_lines': 'dashed'}}) 18 | plt.show() -------------------------------------------------------------------------------- /bqplot_example_3.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import numpy as np 3 | import pandas as pd 4 | from IPython.display import display 5 | from bqplot import * 6 | 7 | price_data = pd.DataFrame(np.cumsum(np.random.randn(150, 2).dot([[1.0, -0.8], [-0.8, 1.0]]), axis=0) + 100, 8 | columns=['Security 1', 'Security 2'], index=pd.date_range(start='01-01-2007', periods=150)) 9 | size = 100 10 | np.random.seed(0) 11 | x_data = range(size) 12 | y_data = np.cumsum(np.random.randn(size) * 100.0) 13 | ord_keys = np.array(['A', 'B', 'C', 'D', 'E', 'F']) 14 | ordinal_data = np.random.randint(5, size=size) 15 | x_sc = LinearScale() 16 | y_sc = LinearScale() 17 | 18 | x_data = x_data[:50] 19 | y_data = y_data[:50] 20 | 21 | def_tt = Tooltip(fields=['x', 'y'], formats=['', '.2f']) 22 | 23 | scatter_chart = Scatter(x=x_data, y=y_data, scales= {'x': x_sc, 'y': y_sc}, default_colors=['dodgerblue'], 24 | tooltip=def_tt) 25 | ax_x = Axis(scale=x_sc) 26 | ax_y = Axis(scale=y_sc, orientation='vertical', tick_format='0.2f') 27 | 28 | fig = Figure(marks=[scatter_chart], axes=[ax_x, ax_y]) 29 | display(fig) -------------------------------------------------------------------------------- /bqplot_example_4.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from IPython.display import display 3 | from ipywidgets import Latex 4 | from bqplot import * 5 | from bqplot.market_map import MarketMap 6 | 7 | data = pd.read_csv('data_files/country_codes.csv', index_col=[0]) 8 | country_codes = data.index.values 9 | country_names = data['Name'] 10 | 11 | gdp_data = pd.read_csv('data_files/gdp_per_capita.csv', index_col=[0], parse_dates=True) 12 | gdp_data.fillna(method='backfill', inplace=True) 13 | gdp_data.fillna(method='ffill', inplace=True) 14 | 15 | col = ColorScale(scheme='Greens') 16 | continents = data['Continent'].values 17 | ax_c = ColorAxis(scale=col, label='GDP per Capita', visible=False) 18 | 19 | data['GDP'] = gdp_data.ix[-1] 20 | 21 | market_map = MarketMap(names=country_codes, groups=continents, # Basic data which needs to set for each map 22 | cols=25, row_groups=3, # Properties for the visualization 23 | ref_data=data, # Data frame used for different properties of the map 24 | tooltip_fields=['Name', 'Continent', 'GDP'], # Columns from data frame to be displayed as tooltip 25 | tooltip_formats=['', '', '.1f'], 26 | scales={'color': col}, axes=[ax_c]) # Axis and scale for color data 27 | 28 | deb_output = Latex() 29 | def selected_index_changed(name, value): 30 | deb_output.value = str(value) 31 | 32 | market_map.on_trait_change(selected_index_changed, name='selected') 33 | 34 | # Creating the figure to be displayed as the tooltip 35 | sc_x = DateScale() 36 | sc_y = LinearScale() 37 | 38 | ax_x = Axis(scale=sc_x, grid_lines='dashed', label='Date') 39 | ax_y = Axis(scale=sc_y, orientation='vertical', grid_lines='dashed', 40 | label='GDP', label_location='end', label_offset='-1em') 41 | 42 | line = Lines(x= gdp_data.index.values, scales={'x': sc_x, 'y': sc_y}, colors=['orange']) 43 | fig_tooltip = Figure(marks=[line], axes=[ax_x, ax_y], min_width=600, min_height=400) 44 | 45 | market_map = MarketMap(names=country_codes, groups=continents, 46 | cols=25, row_groups=3, 47 | color=data['GDP'], scales={'color': col}, axes=[ax_c], 48 | ref_data=data, tooltip_widget=fig_tooltip) 49 | 50 | # Update the tooltip chart 51 | hovered_symbol = '' 52 | def hover_handler(self, content): 53 | global hovered_symbol 54 | symbol = content.get('ref_data', {}).get('Country Code', '') 55 | if(symbol != hovered_symbol): 56 | hovered_symbol = symbol 57 | if(gdp_data.get(hovered_symbol) is not None): 58 | line.y = gdp_data[hovered_symbol].values 59 | fig_tooltip.title = hovered_symbol 60 | 61 | # Custom msg sent when a particular cell is hovered on 62 | market_map.on_hover(hover_handler) 63 | display(market_map) -------------------------------------------------------------------------------- /c2fo_python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pm8k/dataspyre_tutorial/8ae564967337be2f293cbf30f35cc8a5f9cfe852/c2fo_python.png -------------------------------------------------------------------------------- /data_files/country_codes.csv: -------------------------------------------------------------------------------- 1 | Country Code,Continent,Name 2 | ADO,Europe,Andorra 3 | ARE,Asia,United Arab Emirates 4 | AFG,Asia,Afghanistan 5 | ATG,North America,Antigua and Barbuda 6 | ALB,Europe,Albania 7 | ARM,Asia,Armenia 8 | AGO,Africa,Angola 9 | ARG,South America,Argentina 10 | ASM,Australia and Oceania,American Samoa 11 | AUT,Europe,Austria 12 | AUS,Australia and Oceania,Australia 13 | ABW,North America,Aruba 14 | AZE,Asia,Azerbaijan 15 | BIH,Europe,Bosnia and Herzegovina 16 | BRB,North America,Barbados 17 | BGD,Asia,Bangladesh 18 | BEL,Europe,Belgium 19 | BFA,Africa,Burkina Faso 20 | BGR,Europe,Bulgaria 21 | BHR,Asia,Bahrain 22 | BDI,Africa,Burundi 23 | BEN,Africa,Benin 24 | BMU,North America,Bermuda 25 | BRN,Asia,Brunei Darussalam 26 | BOL,South America,Bolivia 27 | BRA,South America,Brazil 28 | BHS,North America,"Bahamas, The" 29 | BTN,Asia,Bhutan 30 | BWA,Africa,Botswana 31 | BLR,Europe,Belarus 32 | BLZ,North America,Belize 33 | CAN,North America,Canada 34 | ZAR,Africa,"Congo, Dem. Rep." 35 | CAF,Africa,Central African Republic 36 | COG,Africa,"Congo, Rep." 37 | CHE,Europe,Switzerland 38 | CIV,Africa,Cote d'Ivoire 39 | CHL,South America,Chile 40 | CMR,Africa,Cameroon 41 | CHN,Asia,China 42 | COL,South America,Colombia 43 | CRI,North America,Costa Rica 44 | CHI,Australia and Oceania,Channel Islands 45 | CUB,North America,Cuba 46 | CPV,Africa,Cabo Verde 47 | CUW,North America,Curacao 48 | CYP,Asia,Cyprus 49 | CZE,Europe,Czech Republic 50 | DEU,Europe,Germany 51 | DJI,Africa,Djibouti 52 | DNK,Europe,Denmark 53 | DMA,North America,Dominica 54 | DOM,North America,Dominican Republic 55 | DZA,Africa,Algeria 56 | ECU,South America,Ecuador 57 | EST,Europe,Estonia 58 | EGY,Africa,"Egypt, Arab Rep." 59 | ERI,Africa,Eritrea 60 | ESP,Europe,Spain 61 | ETH,Africa,Ethiopia 62 | FIN,Europe,Finland 63 | FJI,Australia and Oceania,Fiji 64 | FSM,Australia and Oceania,"Micronesia, Fed. Sts." 65 | FRO,Europe,Faeroe Islands 66 | FRA,Europe,France 67 | GAB,Africa,Gabon 68 | GBR,Europe,United Kingdom 69 | GRD,North America,Grenada 70 | GEO,Asia,Georgia 71 | GHA,Africa,Ghana 72 | GRL,North America,Greenland 73 | GMB,Africa,"Gambia, The" 74 | GIN,Africa,Guinea 75 | GNQ,Africa,Equatorial Guinea 76 | GRC,Europe,Greece 77 | GTM,North America,Guatemala 78 | GUM,Australia and Oceania,Guam 79 | GNB,Africa,Guinea-Bissau 80 | GUY,South America,Guyana 81 | HKG,Asia,"Hong Kong SAR, China" 82 | HND,North America,Honduras 83 | HRV,Europe,Croatia 84 | HTI,North America,Haiti 85 | HUN,Europe,Hungary 86 | IDN,Asia,Indonesia 87 | IRL,Europe,Ireland 88 | ISR,Asia,Israel 89 | IMY,Europe,Isle of Man 90 | IND,Asia,India 91 | IRQ,Asia,Iraq 92 | IRN,Asia,"Iran, Islamic Rep." 93 | ISL,Europe,Iceland 94 | ITA,Europe,Italy 95 | JAM,North America,Jamaica 96 | JOR,Asia,Jordan 97 | JPN,Asia,Japan 98 | KEN,Africa,Kenya 99 | KGZ,Asia,Kyrgyz Republic 100 | KHM,Asia,Cambodia 101 | KIR,Australia and Oceania,Kiribati 102 | COM,Africa,Comoros 103 | KNA,North America,St. Kitts and Nevis 104 | PRK,Asia,"Korea, Dem. Rep." 105 | KOR,Asia,"Korea, Rep." 106 | KWT,Asia,Kuwait 107 | CYM,North America,Cayman Islands 108 | KAZ,Asia,Kazakhstan 109 | LAO,Asia,Lao PDR 110 | LBN,Asia,Lebanon 111 | LCA,North America,St. Lucia 112 | LIE,Europe,Liechtenstein 113 | LKA,Asia,Sri Lanka 114 | LBR,Africa,Liberia 115 | LSO,Africa,Lesotho 116 | LTU,Europe,Lithuania 117 | LUX,Europe,Luxembourg 118 | LVA,Europe,Latvia 119 | LBY,Africa,Libya 120 | MAR,Africa,Morocco 121 | MCO,Europe,Monaco 122 | MDA,Europe,Moldova 123 | MNE,Europe,Montenegro 124 | MAF,North America,St. Martin (French part) 125 | MDG,Africa,Madagascar 126 | MHL,Australia and Oceania,Marshall Islands 127 | MKD,Europe,"Macedonia, FYR" 128 | MLI,Africa,Mali 129 | MMR,Asia,Myanmar 130 | MNG,Asia,Mongolia 131 | MNP,Australia and Oceania,Northern Mariana Islands 132 | MRT,Africa,Mauritania 133 | MLT,Europe,Malta 134 | MUS,Africa,Mauritius 135 | MDV,Asia,Maldives 136 | MWI,Africa,Malawi 137 | MEX,North America,Mexico 138 | MYS,Asia,Malaysia 139 | MOZ,Africa,Mozambique 140 | NAM,Africa,Namibia 141 | NCL,Australia and Oceania,New Caledonia 142 | NER,Africa,Niger 143 | NGA,Africa,Nigeria 144 | NIC,North America,Nicaragua 145 | NLD,Europe,Netherlands 146 | NOR,Europe,Norway 147 | NPL,Asia,Nepal 148 | NZL,Australia and Oceania,New Zealand 149 | OMN,Asia,Oman 150 | PAN,North America,Panama 151 | PER,South America,Peru 152 | PYF,Australia and Oceania,French Polynesia 153 | PNG,Australia and Oceania,Papua New Guinea 154 | PHL,Asia,Philippines 155 | PAK,Asia,Pakistan 156 | POL,Europe,Poland 157 | PRI,North America,Puerto Rico 158 | PRT,Europe,Portugal 159 | PLW,Australia and Oceania,Palau 160 | PRY,South America,Paraguay 161 | QAT,Asia,Qatar 162 | ROM,Europe,Romania 163 | SRB,Europe,Serbia 164 | RUS,Europe,Russian Federation 165 | RWA,Africa,Rwanda 166 | SAU,Asia,Saudi Arabia 167 | SLB,Australia and Oceania,Solomon Islands 168 | SYC,Africa,Seychelles 169 | SDN,Africa,Sudan 170 | SWE,Europe,Sweden 171 | SGP,Asia,Singapore 172 | SVN,Europe,Slovenia 173 | SVK,Europe,Slovak Republic 174 | SLE,Africa,Sierra Leone 175 | SMR,Europe,San Marino 176 | SEN,Africa,Senegal 177 | SOM,Africa,Somalia 178 | SUR,South America,Suriname 179 | SSD,Africa,South Sudan 180 | STP,Africa,Sao Tome and Principe 181 | SLV,North America,El Salvador 182 | SXM,North America,Sint Maarten (Dutch part) 183 | SYR,Asia,Syrian Arab Republic 184 | SWZ,Africa,Swaziland 185 | TCA,North America,Turks and Caicos Islands 186 | TCD,Africa,Chad 187 | TGO,Africa,Togo 188 | THA,Asia,Thailand 189 | TJK,Asia,Tajikistan 190 | TMP,Asia,Timor-Leste 191 | TKM,Asia,Turkmenistan 192 | TUN,Africa,Tunisia 193 | TON,Australia and Oceania,Tonga 194 | TUR,Europe,Turkey 195 | TTO,North America,Trinidad and Tobago 196 | TUV,Australia and Oceania,Tuvalu 197 | TWN,Asia,"Taiwan, China" 198 | TZA,Africa,Tanzania 199 | UKR,Europe,Ukraine 200 | UGA,Africa,Uganda 201 | USA,North America,United States 202 | URY,South America,Uruguay 203 | UZB,Asia,Uzbekistan 204 | VCT,North America,St. Vincent and the Grenadines 205 | VEN,South America,"Venezuela, RB" 206 | VIR,North America,Virgin Islands (U.S.) 207 | VNM,Asia,Vietnam 208 | VUT,Australia and Oceania,Vanuatu 209 | WSM,Australia and Oceania,Samoa 210 | YEM,Asia,"Yemen, Rep." 211 | ZAF,Africa,South Africa 212 | ZMB,Africa,Zambia 213 | ZWE,Africa,Zimbabwe 214 | -------------------------------------------------------------------------------- /data_files/gdp_per_capita.csv: -------------------------------------------------------------------------------- 1 | ,ADO,ARE,AFG,ATG,ALB,ARM,AGO,ARG,ASM,AUT,AUS,ABW,AZE,BIH,BRB,BGD,BEL,BFA,BGR,BHR,BDI,BEN,BMU,BRN,BOL,BRA,BHS,BTN,BWA,BLR,BLZ,CAN,ZAR,CAF,COG,CHE,CIV,CHL,CMR,CHN,COL,CRI,CHI,CUB,CPV,CUW,CYP,CZE,DEU,DJI,DNK,DMA,DOM,DZA,ECU,EST,EGY,ERI,ESP,ETH,FIN,FJI,FSM,FRO,FRA,GAB,GBR,GRD,GEO,GHA,GRL,GMB,GIN,GNQ,GRC,GTM,GUM,GNB,GUY,HKG,HND,HRV,HTI,HUN,IDN,IRL,ISR,IMY,IND,IRQ,IRN,ISL,ITA,JAM,JOR,JPN,KEN,KGZ,KHM,KIR,COM,KNA,PRK,KOR,KWT,CYM,KAZ,LAO,LBN,LCA,LIE,LKA,LBR,LSO,LTU,LUX,LVA,LBY,MAR,MCO,MDA,MNE,MAF,MDG,MHL,MKD,MLI,MMR,MNG,MNP,MRT,MLT,MUS,MDV,MWI,MEX,MYS,MOZ,NAM,NCL,NER,NGA,NIC,NLD,NOR,NPL,NZL,OMN,PAN,PER,PYF,PNG,PHL,PAK,POL,PRI,PRT,PLW,PRY,QAT,ROM,SRB,RUS,RWA,SAU,SLB,SYC,SDN,SWE,SGP,SVN,SVK,SLE,SMR,SEN,SOM,SUR,SSD,STP,SLV,SXM,SYR,SWZ,TCA,TCD,TGO,THA,TJK,TMP,TKM,TUN,TON,TUR,TTO,TUV,TWN,TZA,UKR,UGA,USA,URY,UZB,VCT,VEN,VIR,VNM,VUT,WSM,YEM,ZAF,ZMB,ZWE 2 | 1960-01-01,,,61.3,,,,,,,935.0,1810.0,,,,379.0,86.3,1270.0,68.4,,,70.3,93.0,1900.0,,168.0,208.0,1550.0,,58.0,,305.0,2290.0,220.0,74.6,130.0,1790.0,157.0,551.0,115.0,88.7,252.0,380.0,,,,,,,,,1360.0,,203.0,242.0,224.0,,,,396.0,,1180.0,286.0,,,1340.0,284.0,1380.0,,,183.0,,,,,534.0,252.0,,,304.0,429.0,168.0,,,,,686.0,1370.0,,83.8,231.0,,1410.0,804.0,429.0,,479.0,97.6,,111.0,,,242.0,,156.0,,,,,,,,143.0,170.0,40.6,,2240.0,,,165.0,,,,,132.0,,,,,,,108.0,,,,46.2,338.0,299.0,,,,135.0,92.8,128.0,1070.0,1440.0,53.3,2310.0,80.2,366.0,252.0,,117.0,254.0,81.4,,718.0,360.0,,,,,,,40.6,,,288.0,107.0,1980.0,428.0,,,149.0,,249.0,65.5,323.0,,,,,187.0,100.0,,104.0,76.6,101.0,,,,,,508.0,631.0,,,,,62.3,3010.0,490.0,,161.0,1140.0,756.0,,,,,423.0,227.0,281.0 3 | 1961-01-01,,,61.3,,,,,,,1030.0,1870.0,,,,402.0,94.5,1350.0,71.6,,,71.5,95.6,1960.0,,179.0,203.0,1650.0,,61.3,,316.0,2230.0,197.0,80.5,146.0,1970.0,172.0,600.0,120.0,75.0,276.0,355.0,,,,,,,,,1500.0,,191.0,211.0,211.0,,,,450.0,,1330.0,287.0,,,1450.0,333.0,1450.0,,,190.0,,,,,597.0,253.0,,,323.0,483.0,172.0,,,,,739.0,1600.0,,87.0,245.0,,1420.0,887.0,453.0,,564.0,94.8,,110.0,,,244.0,,91.5,,,,,,,,143.0,161.0,41.2,,2220.0,,,159.0,,,,,134.0,,,,,,,122.0,,,,48.4,354.0,287.0,,,,142.0,96.8,133.0,1160.0,1560.0,54.8,2340.0,80.8,396.0,276.0,,122.0,267.0,86.9,,777.0,383.0,,,,,,,40.7,,,270.0,114.0,2150.0,449.0,,,150.0,,256.0,68.1,330.0,,,,,199.0,120.0,,109.0,79.1,108.0,,,,,,284.0,676.0,,,,,63.0,3070.0,603.0,,170.0,1130.0,754.0,,,,,431.0,215.0,283.0 4 | 1962-01-01,,,59.8,,,,,1150.0,,1090.0,1850.0,,,,417.0,97.0,1440.0,76.5,,,73.8,94.5,2020.0,,191.0,258.0,1750.0,,64.8,,327.0,2260.0,236.0,80.0,156.0,2130.0,173.0,684.0,125.0,70.1,293.0,335.0,,,,,,,,,1680.0,,233.0,169.0,201.0,,,,520.0,,1410.0,292.0,,,1590.0,359.0,1510.0,,,195.0,,,,35.4,631.0,262.0,,,329.0,522.0,181.0,,,,,797.0,1130.0,,91.7,255.0,,1560.0,990.0,463.0,,634.0,101.0,,110.0,,,246.0,,104.0,,,,,,,,140.0,164.0,47.5,,2310.0,,,182.0,,,,,138.0,,,,,,,122.0,,,,49.6,369.0,292.0,,,,151.0,104.0,143.0,1240.0,1670.0,58.1,2450.0,97.2,419.0,304.0,,128.0,157.0,88.4,,855.0,408.0,,,,,,,41.0,,,287.0,120.0,2320.0,472.0,,,154.0,,255.0,70.8,338.0,,,,,227.0,126.0,,115.0,82.0,114.0,,,,,,309.0,704.0,,,,,62.0,3240.0,656.0,,175.0,1210.0,1020.0,,,,,448.0,208.0,279.0 5 | 1963-01-01,,,80.4,,,,,845.0,,1170.0,1960.0,,,,467.0,98.7,1540.0,78.4,,,78.9,99.8,2020.0,,201.0,289.0,1870.0,,67.5,,337.0,2350.0,377.0,81.6,157.0,2290.0,196.0,664.0,127.0,73.4,277.0,345.0,,,,,,,,,1780.0,,257.0,223.0,211.0,,,,609.0,,1520.0,297.0,,,1760.0,300.0,1590.0,,,211.0,,,,41.5,702.0,281.0,,,289.0,577.0,186.0,,,,,852.0,1260.0,,103.0,251.0,,1830.0,1130.0,484.0,,718.0,104.0,,118.0,,,254.0,,142.0,,,,,,,,117.0,167.0,52.4,,2440.0,,,198.0,,,,,138.0,,,,,,,122.0,,,,50.4,398.0,301.0,,,,162.0,107.0,153.0,1330.0,1780.0,49.4,2620.0,101.0,450.0,324.0,,133.0,168.0,92.5,,932.0,433.0,,,,,,,41.3,,,308.0,119.0,2490.0,511.0,,,155.0,,257.0,73.6,349.0,,,,,237.0,145.0,,117.0,87.8,118.0,,,,,,350.0,760.0,,,,,68.9,3370.0,584.0,,163.0,1260.0,1070.0,,,,,485.0,209.0,280.0 6 | 1964-01-01,,,83.8,,,,,1170.0,,1270.0,2130.0,,,,462.0,97.0,1700.0,80.5,,,86.6,104.0,2200.0,,222.0,259.0,1990.0,,71.8,,351.0,2530.0,170.0,87.9,165.0,2500.0,227.0,685.0,134.0,84.6,332.0,354.0,,,,,,,,,2010.0,,271.0,234.0,228.0,,,,675.0,,1710.0,311.0,,,1920.0,412.0,1730.0,,,230.0,,,,48.0,785.0,282.0,,,312.0,649.0,200.0,,,,,965.0,1380.0,,118.0,288.0,,2300.0,1220.0,518.0,,836.0,109.0,,124.0,,,269.0,,120.0,,,,,,,,121.0,179.0,56.7,,2760.0,,,203.0,,,,,143.0,,,,,,,158.0,,,,50.2,457.0,312.0,,,,156.0,113.0,173.0,1540.0,1940.0,48.4,2810.0,102.0,469.0,381.0,,144.0,176.0,102.0,,1010.0,469.0,,,,,,,41.1,,,332.0,119.0,2760.0,485.0,,,163.0,,265.0,76.5,374.0,,,,,256.0,170.0,,121.0,99.9,126.0,,,,,,369.0,788.0,,,,,76.0,3570.0,741.0,,173.0,1040.0,1300.0,,,,,519.0,237.0,284.0 7 | 1965-01-01,,,103.0,,,,,1270.0,,1370.0,2280.0,,,,487.0,103.0,1840.0,81.7,,,51.6,110.0,2280.0,1110.0,242.0,258.0,2140.0,,76.8,,378.0,2740.0,233.0,91.3,171.0,2620.0,218.0,700.0,136.0,97.5,312.0,375.0,,,,,,,,,2240.0,,228.0,246.0,458.0,,159.0,,775.0,,1880.0,317.0,,,2050.0,426.0,1850.0,,,266.0,,,,240.0,889.0,281.0,,,333.0,677.0,216.0,,,,,1020.0,1430.0,,122.0,,246.0,2720.0,1300.0,552.0,532.0,920.0,105.0,,134.0,,,276.0,,105.0,4350.0,,,,,,,152.0,183.0,58.8,,2780.0,,,208.0,,,,,144.0,,,,,,,174.0,,,,57.7,481.0,333.0,,,1760.0,176.0,117.0,274.0,1710.0,2160.0,70.4,2150.0,101.0,500.0,438.0,1890.0,159.0,187.0,114.0,,1110.0,521.0,,184.0,,,,,46.0,,,328.0,121.0,3010.0,516.0,,,155.0,,262.0,79.4,417.0,,,271.0,,273.0,179.0,,126.0,110.0,138.0,,,,214.0,,385.0,807.0,,,,,110.0,3830.0,701.0,,176.0,1060.0,1510.0,,,,,555.0,296.0,297.0 8 | 1966-01-01,,,140.0,,,,,1270.0,,1490.0,2340.0,,,,524.0,109.0,1960.0,82.5,,,52.5,113.0,2630.0,1240.0,259.0,312.0,2320.0,,83.9,,406.0,3010.0,254.0,93.8,185.0,2780.0,233.0,793.0,139.0,103.0,285.0,397.0,,,,,,,,,2440.0,,245.0,232.0,453.0,,162.0,,890.0,,2010.0,316.0,,,2190.0,454.0,1960.0,,,269.0,,108.0,,251.0,982.0,286.0,,,348.0,686.0,227.0,,,,,1070.0,1510.0,,91.8,,261.0,3220.0,1400.0,615.0,548.0,1060.0,119.0,,139.0,,,299.0,,129.0,4480.0,,,,,,,153.0,190.0,59.6,,2900.0,,,198.0,,,,,152.0,,,,,,,176.0,,,,63.9,520.0,345.0,,,1760.0,178.0,124.0,286.0,1840.0,2320.0,85.2,2190.0,106.0,529.0,504.0,2230.0,177.0,200.0,122.0,,1210.0,575.0,,188.0,,,,,37.5,,,338.0,120.0,3240.0,567.0,,,159.0,,262.0,81.9,501.0,,,278.0,,241.0,192.0,,128.0,122.0,161.0,,,,220.0,,445.0,787.0,,,,,112.0,4150.0,664.0,,185.0,1070.0,1780.0,,,,,592.0,336.0,281.0 9 | 1967-01-01,,,164.0,,,,,1060.0,,1570.0,2580.0,,,,580.0,119.0,2090.0,84.4,,,55.1,112.0,2980.0,1230.0,276.0,344.0,2560.0,,92.9,,420.0,3170.0,184.0,95.3,194.0,2960.0,236.0,765.0,149.0,95.5,291.0,416.0,,,,,,,,,2640.0,,250.0,250.0,462.0,,165.0,,968.0,,2030.0,333.0,,,2350.0,491.0,2020.0,,,217.0,,112.0,,256.0,1050.0,291.0,,,370.0,723.0,241.0,,,,56.6,1150.0,1430.0,,98.2,,281.0,3130.0,1530.0,636.0,494.0,1230.0,121.0,,144.0,,,353.0,,156.0,4170.0,,,,,,,159.0,198.0,61.0,,2910.0,,,205.0,,,,,158.0,,,50.1,,,,182.0,,,,64.6,550.0,348.0,,,1870.0,164.0,99.2,300.0,1990.0,2510.0,77.5,2190.0,162.0,572.0,497.0,2210.0,196.0,207.0,136.0,,1340.0,647.0,,196.0,,,,,46.7,,173.0,333.0,126.0,3490.0,626.0,,,145.0,,255.0,84.2,565.0,,,284.0,,274.0,182.0,,131.0,125.0,167.0,,,,225.0,,483.0,823.0,,,,,113.0,4340.0,581.0,,180.0,1080.0,2270.0,,,,,646.0,352.0,296.0 10 | 1968-01-01,,,131.0,,,,,1140.0,,1680.0,2720.0,,,,579.0,119.0,2220.0,84.7,,,55.2,117.0,2830.0,1360.0,226.0,371.0,2800.0,,102.0,,387.0,3410.0,207.0,109.0,199.0,3120.0,267.0,767.0,164.0,90.4,292.0,448.0,,,,,,,,,2710.0,,253.0,277.0,454.0,,176.0,,951.0,,1910.0,335.0,,,2540.0,521.0,1900.0,,,203.0,,96.7,,234.0,1130.0,314.0,,,332.0,714.0,253.0,,,,68.9,1120.0,1410.0,,102.0,313.0,312.0,2350.0,1650.0,594.0,413.0,1450.0,129.0,,157.0,,,315.0,,193.0,4160.0,,,,,,,150.0,205.0,62.0,,3180.0,,,214.0,,,,,166.0,,,61.8,,,,194.0,,,,57.2,590.0,353.0,,,2170.0,154.0,97.0,307.0,2190.0,2660.0,69.6,1890.0,278.0,598.0,448.0,2510.0,210.0,225.0,144.0,,1480.0,719.0,,202.0,,,,,48.8,781.0,187.0,314.0,128.0,3680.0,708.0,,,135.0,,260.0,86.6,612.0,,,285.0,,294.0,189.0,,130.0,124.0,175.0,,,,246.0,,527.0,815.0,,,,,117.0,4700.0,574.0,,173.0,1140.0,3180.0,,,,,684.0,401.0,304.0 11 | 1969-01-01,,,131.0,,,,,1320.0,,1830.0,2990.0,,,,650.0,131.0,2460.0,86.5,,,56.1,116.0,3050.0,1300.0,234.0,400.0,3220.0,,115.0,,397.0,3700.0,259.0,105.0,204.0,3340.0,272.0,870.0,175.0,98.9,308.0,481.0,,,,,,,,,3070.0,,280.0,298.0,532.0,,193.0,,1080.0,,2180.0,357.0,,,2730.0,551.0,2030.0,,,234.0,,104.0,,230.0,1280.0,325.0,,,352.0,826.0,255.0,,,,79.1,1290.0,1590.0,,110.0,314.0,340.0,2040.0,1810.0,646.0,487.0,1670.0,134.0,,142.0,,,348.0,,237.0,3990.0,,,,,,,160.0,222.0,65.2,,3660.0,,,234.0,,,,,165.0,,,60.3,,,,179.0,,,,60.4,633.0,381.0,,,2530.0,146.0,121.0,322.0,2450.0,2880.0,69.7,2080.0,343.0,638.0,487.0,2270.0,232.0,242.0,150.0,,1660.0,796.0,,212.0,,,,,51.8,805.0,185.0,314.0,137.0,3970.0,812.0,,,165.0,,240.0,88.7,635.0,,,289.0,,364.0,243.0,,132.0,132.0,187.0,,,,256.0,,573.0,831.0,,,,,128.0,5030.0,717.0,,186.0,1150.0,3610.0,,,,,755.0,475.0,347.0 12 | 1970-01-01,3240.0,,159.0,,,,,1320.0,,2050.0,3300.0,,,,761.0,136.0,2780.0,81.5,,,70.2,115.0,3390.0,1380.0,241.0,441.0,3180.0,,139.0,,436.0,4120.0,244.0,103.0,206.0,,278.0,938.0,171.0,112.0,337.0,540.0,,653.0,,,,,2750.0,,3420.0,,328.0,331.0,475.0,,211.0,,1210.0,,2470.0,422.0,,,2870.0,550.0,2350.0,,,258.0,1500.0,117.0,,228.0,1500.0,352.0,,115.0,372.0,960.0,269.0,,,,84.7,1490.0,1810.0,,114.0,331.0,370.0,2610.0,2100.0,752.0,424.0,2000.0,142.0,,102.0,326.0,,363.0,,292.0,3830.0,,,,,,4240.0,184.0,228.0,66.6,,4480.0,,,247.0,12500.0,,,,169.0,,,62.9,,,,182.0,828.0,,,64.1,671.0,392.0,,,3200.0,147.0,224.0,324.0,2880.0,3310.0,74.9,,354.0,666.0,548.0,2300.0,265.0,187.0,169.0,,1850.0,934.0,,221.0,2760.0,,,,58.6,927.0,,344.0,151.0,4670.0,925.0,,,172.0,,243.0,91.8,664.0,,,303.0,,336.0,252.0,,129.0,120.0,192.0,,,,281.0,,491.0,869.0,,,,,133.0,5250.0,761.0,,204.0,1210.0,3480.0,,,,,811.0,427.0,362.0 13 | 1971-01-01,3500.0,,162.0,,,,,1370.0,,2380.0,3490.0,,,,851.0,129.0,3090.0,84.3,,,72.1,113.0,3870.0,1460.0,253.0,500.0,3300.0,,177.0,,474.0,4580.0,272.0,108.0,234.0,,289.0,1100.0,178.0,117.0,357.0,577.0,,780.0,,,,,3180.0,,3790.0,,358.0,336.0,444.0,,222.0,,1360.0,,2720.0,466.0,,,3180.0,635.0,2650.0,,,274.0,1880.0,121.0,,228.0,1660.0,357.0,,112.0,386.0,1110.0,264.0,,,,84.2,1700.0,1820.0,,121.0,377.0,449.0,3290.0,2300.0,812.0,431.0,2230.0,153.0,,135.0,341.0,,441.0,,317.0,4800.0,,,,,,4830.0,187.0,234.0,72.6,,4620.0,,,267.0,13800.0,,,,177.0,,,74.1,,,,192.0,874.0,,,78.3,717.0,404.0,,,3450.0,153.0,160.0,335.0,3320.0,3740.0,74.8,2770.0,402.0,730.0,595.0,2590.0,287.0,201.0,174.0,,2040.0,1060.0,,239.0,3250.0,,,,57.6,1190.0,301.0,401.0,160.0,5060.0,1070.0,,,162.0,,243.0,95.2,724.0,,,309.0,,392.0,297.0,,135.0,131.0,194.0,,,,324.0,,456.0,938.0,,,,,146.0,5620.0,996.0,,219.0,1300.0,3620.0,,,,,874.0,382.0,405.0 14 | 1972-01-01,4220.0,,137.0,,,,,1400.0,,2920.0,3940.0,,,,967.0,91.5,3850.0,99.3,,,69.6,135.0,4340.0,1910.0,284.0,581.0,3320.0,,223.0,,520.0,5130.0,292.0,121.0,289.0,,322.0,1160.0,201.0,130.0,387.0,648.0,,901.0,,,,,3800.0,,4600.0,,416.0,436.0,500.0,,231.0,,1710.0,,3180.0,583.0,,,3870.0,703.0,3030.0,,,233.0,2200.0,125.0,,238.0,1910.0,367.0,,122.0,388.0,1380.0,282.0,,,,96.7,2080.0,2280.0,,125.0,388.0,542.0,4060.0,2660.0,974.0,483.0,2920.0,174.0,,68.9,414.0,,518.0,,339.0,5130.0,,,,,,5640.0,199.0,246.0,75.3,,5720.0,,,304.0,16700.0,,,,193.0,,,82.6,,,,218.0,976.0,,,84.4,801.0,468.0,,,4030.0,159.0,209.0,344.0,4040.0,4410.0,84.9,3290.0,473.0,780.0,641.0,2750.0,333.0,211.0,149.0,,2250.0,1300.0,,267.0,3910.0,,,,61.9,1520.0,235.0,547.0,168.0,5940.0,1370.0,,,176.0,,285.0,119.0,772.0,,,321.0,,448.0,311.0,,153.0,149.0,209.0,,,,423.0,,560.0,1120.0,,,,,149.0,6110.0,776.0,,298.0,1390.0,4040.0,,,,,897.0,418.0,480.0 15 | 1973-01-01,5340.0,,145.0,,,,,2080.0,,3880.0,4760.0,,,,1170.0,116.0,4920.0,114.0,,,84.9,162.0,5010.0,2930.0,278.0,768.0,3700.0,,319.0,,606.0,5860.0,363.0,140.0,371.0,,417.0,1620.0,240.0,155.0,450.0,782.0,,1090.0,,,,,5030.0,,6070.0,,478.0,547.0,594.0,,248.0,,2250.0,,4180.0,769.0,,,4980.0,1160.0,3430.0,,,264.0,2860.0,153.0,,309.0,2510.0,437.0,,121.0,415.0,1890.0,312.0,,,,140.0,2420.0,2820.0,,146.0,469.0,831.0,5500.0,3200.0,974.0,558.0,3930.0,200.0,,93.9,681.0,,546.0,,426.0,5830.0,,,,,,7350.0,220.0,251.0,110.0,,7760.0,,,367.0,21400.0,,,,231.0,,,94.1,,,,266.0,1140.0,,,89.4,950.0,694.0,,,4220.0,197.0,252.0,415.0,5260.0,5690.0,78.9,4320.0,599.0,868.0,746.0,3520.0,490.0,258.0,98.4,,2430.0,1750.0,,333.0,5590.0,,,,70.9,2250.0,308.0,644.0,202.0,7200.0,1930.0,,,213.0,,318.0,144.0,826.0,,,357.0,,458.0,456.0,,166.0,176.0,270.0,,,,507.0,,688.0,1330.0,,,,,166.0,6740.0,1400.0,,323.0,1640.0,4190.0,,,,,1200.0,525.0,574.0 16 | 1974-01-01,6320.0,,176.0,,,,,2820.0,,4620.0,6470.0,,,,1390.0,176.0,5760.0,124.0,,,95.3,174.0,5850.0,6950.0,451.0,995.0,3420.0,,386.0,,786.0,7030.0,431.0,142.0,388.0,,487.0,1510.0,300.0,158.0,527.0,832.0,,1220.0,,,,,5620.0,,6720.0,,581.0,807.0,979.0,,228.0,,2760.0,,5300.0,988.0,,,5340.0,2430.0,3670.0,,,301.0,3430.0,190.0,,377.0,2840.0,524.0,,130.0,583.0,2170.0,343.0,,,,216.0,2510.0,3720.0,,167.0,1020.0,1390.0,7120.0,3610.0,1200.0,685.0,4280.0,229.0,,77.8,1800.0,,711.0,,589.0,13200.0,,,,,,8440.0,269.0,308.0,134.0,,9340.0,,,442.0,22700.0,,,,261.0,,,88.5,,,,321.0,1250.0,,,107.0,1200.0,840.0,,,4870.0,208.0,402.0,561.0,6330.0,6810.0,96.7,4610.0,1950.0,965.0,915.0,4390.0,537.0,343.0,133.0,,2610.0,2000.0,,438.0,15600.0,,,,73.0,6490.0,454.0,738.0,252.0,7980.0,2360.0,,,235.0,,348.0,128.0,1010.0,,,403.0,,706.0,527.0,,163.0,238.0,332.0,,,,645.0,,930.0,2050.0,,,,,199.0,7240.0,1450.0,,348.0,2360.0,4390.0,,,,,1480.0,607.0,667.0 17 | 1975-01-01,7170.0,27600.0,189.0,,,,,2010.0,,5270.0,6990.0,,,,1640.0,268.0,6730.0,153.0,,,114.0,207.0,6510.0,7270.0,504.0,1140.0,3160.0,,432.0,,886.0,7480.0,447.0,188.0,494.0,,589.0,693.0,356.0,176.0,546.0,956.0,,1380.0,,,976.0,,6210.0,,7950.0,,696.0,924.0,1120.0,,283.0,,3220.0,,6260.0,1190.0,,,6700.0,3330.0,4300.0,,,286.0,4260.0,221.0,,438.0,3160.0,589.0,,140.0,661.0,2250.0,362.0,,,,249.0,2970.0,3570.0,,161.0,1150.0,1490.0,6530.0,4090.0,1420.0,753.0,4580.0,242.0,,,1140.0,,754.0,,646.0,11500.0,,,,,,10500.0,281.0,355.0,130.0,,9070.0,,,506.0,28200.0,,,,301.0,,,134.0,,,,358.0,1560.0,,,116.0,1430.0,803.0,,,6160.0,207.0,437.0,565.0,7210.0,8200.0,122.0,4170.0,2380.0,1050.0,1080.0,5280.0,483.0,361.0,166.0,,2740.0,2130.0,,482.0,15300.0,,,,131.0,6340.0,386.0,802.0,298.0,9970.0,2560.0,,,241.0,,456.0,183.0,1280.0,,,445.0,,903.0,558.0,,211.0,256.0,352.0,,,,772.0,368.0,1140.0,2410.0,,,,,218.0,7820.0,1250.0,,348.0,2470.0,4250.0,,,,,1490.0,492.0,708.0 18 | 1976-01-01,7150.0,30800.0,200.0,,,,,1930.0,,5660.0,7470.0,,,,1770.0,136.0,7270.0,156.0,,,120.0,209.0,7260.0,8510.0,559.0,1380.0,3330.0,,435.0,,717.0,8770.0,410.0,219.0,472.0,,674.0,932.0,387.0,163.0,625.0,1150.0,,1440.0,,,1160.0,,6610.0,,8750.0,,746.0,1020.0,1280.0,,324.0,,3290.0,,6740.0,1180.0,,,6870.0,4550.0,4140.0,,,276.0,4840.0,209.0,,454.0,3400.0,687.0,,142.0,602.0,2850.0,421.0,,,,297.0,2920.0,3530.0,,164.0,1470.0,1880.0,7670.0,4020.0,1460.0,911.0,5110.0,248.0,,,831.0,,682.0,,875.0,11800.0,,,,,,11400.0,262.0,356.0,125.0,,9890.0,,,528.0,28800.0,,,,280.0,,,149.0,,,,383.0,1730.0,780.0,,122.0,1400.0,933.0,,,5960.0,204.0,555.0,637.0,7790.0,8930.0,110.0,4370.0,2760.0,1090.0,996.0,5430.0,523.0,403.0,190.0,,2950.0,2170.0,,536.0,18900.0,,,,142.0,8220.0,414.0,812.0,359.0,10700.0,2650.0,,,206.0,,450.0,190.0,1390.0,,,538.0,,976.0,511.0,,208.0,251.0,392.0,,,,785.0,337.0,1280.0,2440.0,,,,,220.0,8610.0,1290.0,,339.0,2750.0,4580.0,,,,,1400.0,534.0,678.0 19 | 1977-01-01,7750.0,34400.0,227.0,942.0,,,,2110.0,,6790.0,7760.0,,,,2000.0,127.0,8460.0,177.0,,,143.0,219.0,8370.0,9970.0,645.0,1550.0,3620.0,,508.0,,859.0,8880.0,509.0,241.0,465.0,,866.0,1250.0,411.0,183.0,775.0,1420.0,,1470.0,,,1480.0,,7650.0,,9760.0,495.0,845.0,1180.0,1510.0,,348.0,,3630.0,,7070.0,1200.0,,,7540.0,4150.0,4680.0,591.0,,313.0,5710.0,250.0,,472.0,3900.0,842.0,,144.0,590.0,3430.0,505.0,,,,357.0,3420.0,3810.0,,190.0,1590.0,2140.0,10100.0,4590.0,1580.0,1080.0,6230.0,309.0,,,766.0,,680.0,,1110.0,12000.0,,,,,,12400.0,294.0,390.0,160.0,,10900.0,,,595.0,31400.0,,,,294.0,,,164.0,,,,384.0,2040.0,898.0,,142.0,1250.0,1080.0,,,6160.0,241.0,534.0,749.0,9010.0,10300.0,103.0,4950.0,2800.0,1120.0,889.0,5710.0,553.0,450.0,209.0,,3210.0,2270.0,,648.0,19800.0,,,,161.0,9010.0,448.0,1050.0,434.0,11300.0,2880.0,,,234.0,,450.0,105.0,1770.0,,,666.0,,952.0,553.0,,220.0,309.0,445.0,,,,868.0,378.0,1430.0,3020.0,,,,,256.0,9470.0,1440.0,,374.0,3100.0,4970.0,,,,,1530.0,474.0,663.0 20 | 1978-01-01,9130.0,28700.0,250.0,1060.0,,,,2130.0,,8190.0,8240.0,,,,2230.0,170.0,10300.0,226.0,,,156.0,264.0,8880.0,10800.0,734.0,1730.0,4130.0,,639.0,,981.0,9080.0,616.0,283.0,518.0,,1040.0,1420.0,523.0,155.0,904.0,1590.0,,1840.0,,,1930.0,,9450.0,,11800.0,608.0,859.0,1440.0,1590.0,,345.0,,4340.0,,7630.0,1360.0,,,9280.0,3450.0,5980.0,758.0,,354.0,7240.0,303.0,,,4710.0,910.0,,153.0,659.0,3920.0,565.0,,,,391.0,4400.0,3690.0,,209.0,1850.0,2020.0,11400.0,5590.0,1270.0,1290.0,8680.0,352.0,,,872.0,,784.0,,1470.0,12500.0,,,,,,17500.0,193.0,404.0,215.0,,13600.0,,,696.0,38400.0,,,,323.0,,,188.0,,,,376.0,2560.0,1090.0,,162.0,1530.0,1260.0,,,6150.0,322.0,525.0,694.0,11000.0,11500.0,117.0,5940.0,2650.0,1300.0,739.0,7030.0,639.0,506.0,238.0,,3570.0,2460.0,,776.0,21100.0,,,,189.0,9200.0,516.0,1360.0,455.0,12400.0,3430.0,,,317.0,,490.0,107.0,2020.0,,,695.0,,1110.0,600.0,,257.0,320.0,529.0,,,,987.0,455.0,1550.0,3380.0,,,,,205.0,10600.0,1710.0,,472.0,3290.0,5340.0,,,,,1720.0,513.0,640.0 21 | 1979-01-01,11800.0,33700.0,279.0,1310.0,,,,2500.0,,9770.0,9270.0,,,,2700.0,194.0,11900.0,262.0,,,195.0,328.0,9610.0,15000.0,843.0,1890.0,5530.0,,853.0,,1070.0,10000.0,587.0,317.0,687.0,,1160.0,1880.0,670.0,183.0,1060.0,1770.0,,2000.0,,,2560.0,,11200.0,,13700.0,591.0,966.0,1760.0,1840.0,,413.0,,5750.0,,9340.0,1640.0,,,11200.0,4270.0,7800.0,884.0,,381.0,8480.0,354.0,,,5730.0,1010.0,,147.0,685.0,4570.0,639.0,,,,388.0,5420.0,4630.0,,228.0,2850.0,2300.0,12800.0,6970.0,1150.0,1560.0,8950.0,398.0,,,802.0,,918.0,,1860.0,19000.0,,,,,890.0,19800.0,232.0,445.0,228.0,,15800.0,,,817.0,45800.0,,,,407.0,,,241.0,,,,432.0,3200.0,1280.0,,175.0,1960.0,1600.0,,,7560.0,372.0,660.0,496.0,12600.0,13000.0,132.0,6670.0,3420.0,1450.0,920.0,8250.0,733.0,596.0,255.0,,4020.0,2760.0,,1010.0,27400.0,,,,223.0,12100.0,679.0,2000.0,455.0,14700.0,4080.0,,,357.0,,595.0,103.0,2150.0,,,756.0,,1150.0,704.0,,227.0,337.0,590.0,,,,1160.0,484.0,2080.0,4300.0,,,,,176.0,11700.0,2480.0,,547.0,3810.0,6320.0,,1060.0,,,2080.0,592.0,736.0 22 | 1980-01-01,12400.0,43000.0,276.0,1570.0,,,,2740.0,,10800.0,10200.0,,,,3460.0,220.0,12900.0,283.0,2260.0,8540.0,223.0,378.0,11200.0,25500.0,845.0,1930.0,6340.0,329.0,1060.0,,1350.0,11100.0,546.0,350.0,950.0,18800.0,1230.0,2460.0,755.0,193.0,1240.0,2060.0,,2020.0,472.0,,4230.0,,12100.0,,13800.0,785.0,1140.0,2170.0,2260.0,,510.0,,6200.0,,11200.0,1890.0,,,12700.0,5890.0,10000.0,939.0,,412.0,9480.0,399.0,,230.0,5920.0,1130.0,,135.0,776.0,5700.0,706.0,,,,536.0,6370.0,5620.0,,271.0,3910.0,2320.0,15000.0,8430.0,1260.0,1790.0,9310.0,447.0,,,512.0,394.0,1110.0,,1780.0,20900.0,,,,,1130.0,20700.0,273.0,452.0,330.0,,17200.0,,,1060.0,51500.0,,,,462.0,,,265.0,,,,462.0,3950.0,1180.0,275.0,198.0,2760.0,1800.0,290.0,2400.0,8440.0,430.0,871.0,660.0,13600.0,15800.0,135.0,7470.0,5180.0,1910.0,1020.0,8980.0,792.0,685.0,296.0,,4500.0,3370.0,,1280.0,35000.0,,,,244.0,16700.0,732.0,2290.0,398.0,16900.0,5000.0,,,346.0,,629.0,99.1,2170.0,,,767.0,,1460.0,898.0,,229.0,418.0,683.0,,,,1370.0,573.0,1570.0,5750.0,,,,,99.2,12600.0,3490.0,,600.0,4450.0,7500.0,,981.0,,,2920.0,664.0,916.0 23 | 1981-01-01,10400.0,45200.0,268.0,1780.0,,,,2760.0,,9360.0,11800.0,,,,3790.0,239.0,10700.0,254.0,2260.0,9270.0,229.0,338.0,13400.0,21900.0,1070.0,2120.0,6620.0,345.0,1040.0,,1310.0,12300.0,463.0,297.0,1080.0,17100.0,977.0,2870.0,830.0,196.0,1320.0,1090.0,,2040.0,458.0,,4030.0,,10200.0,,12000.0,879.0,1220.0,2210.0,2690.0,,509.0,,5360.0,203.0,10900.0,1900.0,,,11100.0,5190.0,9600.0,970.0,,380.0,8540.0,350.0,,158.0,5400.0,1200.0,,186.0,735.0,5990.0,752.0,,,,621.0,5980.0,5860.0,,275.0,2740.0,2400.0,15300.0,7600.0,1380.0,1930.0,10200.0,406.0,,,524.0,353.0,1320.0,,1970.0,17400.0,,,,,1270.0,19500.0,297.0,431.0,324.0,,14400.0,,,837.0,44400.0,,,,400.0,973.0,,218.0,,1330.0,,474.0,3900.0,1170.0,281.0,193.0,3480.0,1800.0,284.0,2180.0,6820.0,362.0,807.0,740.0,11300.0,15500.0,155.0,7810.0,5950.0,2120.0,1190.0,8190.0,756.0,732.0,340.0,,4920.0,3250.0,,1590.0,34900.0,,,,265.0,17600.0,785.0,2380.0,482.0,15400.0,5670.0,,,342.0,,555.0,112.0,2420.0,,,726.0,,1670.0,920.0,,190.0,342.0,721.0,,,,1290.0,666.0,1580.0,6210.0,,,,,103.0,14000.0,3760.0,,738.0,4860.0,8390.0,,833.0,,,3070.0,664.0,1060.0 24 | 1982-01-01,9610.0,40300.0,,2000.0,,,,2910.0,,9390.0,12800.0,,,,3950.0,213.0,9380.0,245.0,2220.0,9450.0,232.0,322.0,14200.0,20800.0,994.0,2210.0,7170.0,343.0,947.0,,1180.0,12400.0,492.0,310.0,1130.0,17400.0,840.0,2110.0,772.0,202.0,1380.0,1050.0,,2110.0,454.0,,4120.0,,9880.0,,11700.0,959.0,1310.0,2180.0,2400.0,,545.0,,5150.0,208.0,10900.0,1790.0,,,10500.0,4740.0,9150.0,1020.0,,351.0,7810.0,333.0,,177.0,5600.0,1180.0,,195.0,625.0,6130.0,751.0,,,,622.0,6150.0,6100.0,,279.0,2950.0,2890.0,13900.0,7530.0,1500.0,1980.0,9430.0,366.0,,,517.0,321.0,1400.0,,2080.0,14300.0,,,,,1190.0,19700.0,314.0,424.0,238.0,,13100.0,,,816.0,41400.0,,,,382.0,1050.0,,190.0,,1440.0,,462.0,3790.0,1090.0,290.0,180.0,2370.0,1880.0,284.0,2010.0,6210.0,327.0,661.0,714.0,10900.0,15200.0,159.0,7660.0,5860.0,2280.0,1170.0,8000.0,698.0,742.0,359.0,,5120.0,3080.0,,1490.0,27400.0,,,,257.0,13700.0,764.0,2250.0,452.0,13500.0,6000.0,,,389.0,,528.0,123.0,2490.0,,,707.0,,1700.0,841.0,,177.0,282.0,743.0,,,,1210.0,663.0,1400.0,7130.0,,,,,163.0,14400.0,3110.0,,836.0,4800.0,8160.0,,808.0,770.0,,2760.0,621.0,1080.0 25 | 1983-01-01,8020.0,35200.0,,2260.0,,,,3530.0,,9510.0,11500.0,,,,4170.0,197.0,8880.0,218.0,1900.0,9420.0,241.0,271.0,15900.0,18200.0,941.0,1560.0,7700.0,372.0,1060.0,,1210.0,13400.0,386.0,265.0,1070.0,17300.0,729.0,1690.0,756.0,224.0,1340.0,1560.0,,2230.0,436.0,,4090.0,,9830.0,,11800.0,1070.0,1380.0,2270.0,2010.0,,585.0,,4470.0,224.0,10500.0,1640.0,1320.0,,10000.0,4330.0,8690.0,1050.0,,341.0,7990.0,317.0,,163.0,5040.0,1200.0,,188.0,639.0,5600.0,771.0,,,,548.0,5910.0,6680.0,,297.0,2740.0,3360.0,11800.0,7810.0,1620.0,2000.0,10200.0,328.0,,,500.0,324.0,1400.0,,2270.0,13200.0,,,,,1260.0,19600.0,335.0,391.0,253.0,,12900.0,,,729.0,38900.0,,,,371.0,1200.0,,181.0,,1500.0,,472.0,3530.0,1090.0,338.0,182.0,1990.0,2060.0,249.0,2130.0,5540.0,284.0,445.0,780.0,10500.0,14900.0,159.0,7600.0,5830.0,2290.0,906.0,8070.0,734.0,645.0,324.0,,5220.0,2740.0,,1500.0,20900.0,,,,261.0,10900.0,708.0,2210.0,400.0,12400.0,6710.0,,,292.0,,458.0,118.0,2390.0,,,720.0,,1770.0,843.0,,172.0,253.0,798.0,,,,1210.0,649.0,1310.0,6850.0,,,,,163.0,15600.0,1720.0,,913.0,4780.0,8820.0,,886.0,706.0,,2890.0,516.0,947.0 26 | 1984-01-01,7730.0,32700.0,,2600.0,663.0,,,2650.0,,8970.0,12400.0,,,,4520.0,207.0,8490.0,194.0,1940.0,9590.0,213.0,252.0,17500.0,17400.0,1050.0,1570.0,8870.0,371.0,1080.0,,1320.0,13800.0,269.0,250.0,1090.0,16500.0,700.0,1610.0,775.0,249.0,1300.0,1750.0,,2400.0,406.0,,4260.0,,9280.0,,11500.0,1210.0,1620.0,2420.0,1930.0,,623.0,,4480.0,205.0,10800.0,1680.0,,,9430.0,4430.0,8180.0,1120.0,,358.0,7200.0,253.0,,171.0,4870.0,1220.0,,156.0,577.0,6210.0,807.0,,,,551.0,5690.0,6260.0,,282.0,3080.0,3350.0,12100.0,7720.0,1040.0,1950.0,10800.0,327.0,,,474.0,304.0,1660.0,,2470.0,13100.0,,,491.0,,1580.0,18600.0,387.0,392.0,211.0,,12600.0,,,646.0,36400.0,,,,303.0,1230.0,,180.0,,1120.0,,423.0,3330.0,1030.0,618.0,174.0,2300.0,2250.0,255.0,1760.0,5250.0,224.0,349.0,861.0,9810.0,15000.0,164.0,6710.0,6170.0,2340.0,898.0,8090.0,712.0,594.0,340.0,,5730.0,2520.0,,1130.0,19600.0,,,,270.0,9500.0,962.0,2260.0,459.0,12900.0,7160.0,,,311.0,,433.0,129.0,2320.0,,,742.0,,1700.0,727.0,,186.0,229.0,818.0,,,,1170.0,685.0,1250.0,6710.0,,,,,255.0,17100.0,1620.0,,998.0,3320.0,9120.0,,1070.0,686.0,,2790.0,410.0,745.0 27 | 1985-01-01,7780.0,30100.0,,3070.0,663.0,,736.0,2910.0,,9150.0,11400.0,,,,4710.0,236.0,8780.0,201.0,1960.0,8710.0,241.0,244.0,18300.0,15800.0,890.0,1640.0,9890.0,367.0,941.0,,1270.0,14000.0,240.0,330.0,1040.0,16600.0,687.0,1360.0,785.0,293.0,1160.0,1780.0,,2270.0,416.0,,4490.0,,9390.0,804.0,12200.0,1340.0,773.0,2540.0,1910.0,,689.0,,4690.0,233.0,11400.0,1600.0,,,9770.0,4040.0,8650.0,1280.0,,354.0,7760.0,308.0,,199.0,4830.0,1230.0,,158.0,603.0,6540.0,859.0,,,,538.0,6010.0,5700.0,,303.0,3100.0,3590.0,12500.0,7970.0,909.0,1890.0,11500.0,312.0,,,343.0,315.0,1860.0,,2540.0,12400.0,,,644.0,,1500.0,19400.0,377.0,387.0,169.0,,13000.0,,,636.0,37600.0,,,,286.0,1140.0,,177.0,,1140.0,,387.0,3320.0,1060.0,693.0,156.0,2370.0,2020.0,334.0,1410.0,5530.0,215.0,344.0,723.0,9760.0,15800.0,162.0,7600.0,6680.0,2420.0,825.0,8600.0,659.0,566.0,329.0,,6010.0,2710.0,,801.0,16600.0,,,,281.0,7830.0,858.0,2510.0,553.0,13500.0,6780.0,,,239.0,,460.0,144.0,2320.0,,,759.0,,1540.0,512.0,,203.0,234.0,748.0,,,,1160.0,639.0,1370.0,6300.0,,,,,240.0,18300.0,1570.0,,1080.0,3340.0,9260.0,239.0,951.0,597.0,,2140.0,329.0,636.0 28 | 1986-01-01,10400.0,23800.0,,3810.0,719.0,,715.0,3600.0,,13100.0,11400.0,,,,5150.0,226.0,12200.0,257.0,2260.0,7040.0,243.0,303.0,20500.0,10300.0,640.0,1930.0,10300.0,416.0,1140.0,,1340.0,14300.0,262.0,418.0,865.0,23700.0,869.0,1440.0,992.0,280.0,1140.0,1980.0,,2380.0,568.0,,5640.0,,13400.0,,17100.0,1530.0,918.0,2710.0,1670.0,,696.0,,6500.0,234.0,15000.0,1800.0,1280.0,,13600.0,4010.0,10600.0,1440.0,,437.0,11300.0,242.0,369.0,233.0,5680.0,892.0,,140.0,677.0,7440.0,872.0,,,,483.0,8100.0,6910.0,,317.0,2960.0,4020.0,16600.0,11300.0,1180.0,2330.0,16900.0,355.0,,,322.0,436.0,2260.0,,2910.0,9830.0,,,470.0,,1760.0,28300.0,397.0,381.0,194.0,,18900.0,,,815.0,52200.0,,,,317.0,1390.0,,223.0,,1470.0,,442.0,4190.0,1430.0,747.0,154.0,1630.0,1740.0,392.0,1520.0,7630.0,276.0,241.0,760.0,13600.0,18900.0,173.0,9430.0,4690.0,2460.0,743.0,12800.0,702.0,535.0,326.0,,6440.0,3860.0,,903.0,12700.0,,,,304.0,6250.0,756.0,3060.0,689.0,17700.0,6860.0,,,133.0,,631.0,153.0,2340.0,,,744.0,,1210.0,611.0,,204.0,315.0,813.0,,,,1200.0,724.0,1510.0,4050.0,,,,,258.0,19100.0,1940.0,,1220.0,3310.0,9720.0,437.0,892.0,629.0,,2480.0,236.0,676.0 29 | 1987-01-01,12600.0,24000.0,,4510.0,699.0,,697.0,3550.0,,16400.0,11600.0,,,,5650.0,247.0,15200.0,291.0,3170.0,7550.0,222.0,344.0,22400.0,11700.0,687.0,2070.0,11200.0,505.0,1560.0,,1590.0,16200.0,241.0,438.0,1050.0,29500.0,923.0,1670.0,1120.0,250.0,1160.0,2050.0,,2450.0,694.0,,6690.0,,16600.0,767.0,21300.0,1750.0,856.0,2760.0,1480.0,,768.0,,8230.0,242.0,18600.0,1630.0,1300.0,,16300.0,3760.0,13100.0,1680.0,,376.0,14600.0,274.0,381.0,274.0,6590.0,854.0,,183.0,480.0,9060.0,923.0,,,,449.0,9570.0,8120.0,,348.0,3470.0,2490.0,22700.0,14200.0,1400.0,2370.0,20400.0,377.0,,,363.0,513.0,2620.0,,3630.0,11700.0,,,279.0,,1850.0,37900.0,408.0,443.0,243.0,,23400.0,,,881.0,63000.0,,,,243.0,1490.0,,254.0,,1490.0,,488.0,5080.0,1820.0,719.0,145.0,1730.0,1930.0,176.0,1850.0,9270.0,315.0,273.0,993.0,16400.0,22500.0,175.0,12300.0,4820.0,2420.0,987.0,13800.0,813.0,579.0,329.0,,6940.0,4800.0,,964.0,12900.0,1660.0,,,320.0,5900.0,832.0,3650.0,867.0,21500.0,7790.0,,,185.0,,736.0,164.0,2530.0,,,771.0,,998.0,761.0,,215.0,360.0,936.0,,,698.0,1260.0,865.0,1700.0,4010.0,,,,1250.0,398.0,20100.0,2420.0,,1340.0,2480.0,10800.0,594.0,961.0,694.0,,3160.0,313.0,708.0 30 | 1988-01-01,14300.0,22500.0,,5420.0,677.0,,680.0,3980.0,,17500.0,14300.0,,,,5980.0,260.0,16500.0,313.0,2560.0,7960.0,205.0,346.0,24300.0,11100.0,709.0,2290.0,11400.0,549.0,2030.0,,1760.0,18800.0,271.0,453.0,980.0,31700.0,906.0,1930.0,1100.0,282.0,1230.0,2070.0,,2640.0,772.0,,7650.0,,17900.0,755.0,22400.0,2000.0,773.0,2370.0,1350.0,,649.0,,9690.0,243.0,22100.0,1540.0,1360.0,,17700.0,4280.0,16000.0,1880.0,,375.0,16400.0,316.0,431.0,286.0,7630.0,923.0,,169.0,564.0,10600.0,857.0,,,,515.0,10700.0,9880.0,,362.0,3750.0,2180.0,24700.0,15700.0,1620.0,2130.0,24600.0,382.0,,,455.0,528.0,3090.0,,4810.0,10300.0,,,150.0,1240.0,2050.0,41400.0,420.0,478.0,278.0,,26300.0,,,1030.0,68400.0,,,,225.0,1600.0,,253.0,,1530.0,,500.0,5810.0,2050.0,830.0,159.0,2220.0,2050.0,157.0,1920.0,12700.0,312.0,256.0,664.0,17400.0,24200.0,202.0,13800.0,4990.0,2040.0,720.0,14200.0,923.0,644.0,368.0,,7540.0,5620.0,,1010.0,13600.0,1750.0,,,340.0,5840.0,1050.0,4120.0,635.0,24200.0,9320.0,,,270.0,,706.0,167.0,2950.0,,,806.0,,902.0,864.0,,266.0,385.0,1120.0,,,859.0,1280.0,1130.0,1740.0,3730.0,,,219.0,1450.0,399.0,21500.0,2680.0,,1540.0,3110.0,11500.0,402.0,1070.0,824.0,,3400.0,501.0,793.0 31 | 1989-01-01,15200.0,24300.0,,6030.0,723.0,,995.0,2380.0,,17400.0,17800.0,,,,6590.0,266.0,16600.0,305.0,2450.0,8030.0,204.0,311.0,25500.0,12000.0,711.0,2890.0,12200.0,521.0,2300.0,,1980.0,20600.0,267.0,433.0,1030.0,30300.0,833.0,2190.0,951.0,309.0,1210.0,2290.0,,2570.0,773.0,,8040.0,,17700.0,731.0,21800.0,2150.0,942.0,2180.0,1400.0,,718.0,,10700.0,247.0,24000.0,1630.0,1440.0,,17700.0,4540.0,16200.0,2200.0,,369.0,16800.0,322.0,423.0,244.0,7880.0,968.0,,214.0,521.0,12100.0,748.0,,,,578.0,11200.0,9870.0,,354.0,3850.0,2080.0,22700.0,16300.0,1850.0,1380.0,24500.0,365.0,,,425.0,493.0,3510.0,,5860.0,11800.0,,,173.0,1020.0,2290.0,39400.0,415.0,368.0,288.0,,27700.0,,,1030.0,68600.0,,,,223.0,1590.0,,257.0,,1670.0,,498.0,6040.0,2080.0,905.0,175.0,2640.0,2190.0,173.0,1870.0,13100.0,290.0,260.0,250.0,17100.0,24300.0,199.0,13300.0,5380.0,2010.0,1030.0,13600.0,874.0,705.0,372.0,,8060.0,6060.0,,1110.0,14000.0,1790.0,,3430.0,333.0,6090.0,1100.0,4390.0,610.0,25300.0,10700.0,,,234.0,,674.0,174.0,1360.0,,,830.0,,815.0,836.0,,249.0,367.0,1290.0,,,854.0,1270.0,1120.0,2020.0,3560.0,,,184.0,1600.0,312.0,22900.0,2730.0,,1660.0,2190.0,13000.0,97.2,1010.0,759.0,,3620.0,522.0,815.0 32 | 1990-01-01,18900.0,28100.0,,6330.0,639.0,637.0,968.0,4330.0,,21600.0,18200.0,,1240.0,,7800.0,291.0,20700.0,352.0,2380.0,8530.0,202.0,392.0,26800.0,13700.0,716.0,3090.0,12400.0,560.0,2740.0,1700.0,2200.0,21300.0,268.0,495.0,1170.0,38300.0,891.0,2390.0,924.0,316.0,1210.0,2400.0,,2700.0,872.0,,9640.0,3900.0,22200.0,767.0,26900.0,2340.0,976.0,2360.0,1510.0,,766.0,,13800.0,253.0,28400.0,1840.0,1530.0,,21800.0,6290.0,19100.0,2300.0,1620.0,403.0,18300.0,346.0,443.0,300.0,9670.0,860.0,,240.0,547.0,13500.0,622.0,,,,641.0,14000.0,11300.0,,376.0,10300.0,2060.0,25700.0,20800.0,1920.0,1310.0,25100.0,366.0,609.0,,400.0,606.0,3900.0,,6640.0,8950.0,,1650.0,204.0,1050.0,2870.0,49500.0,472.0,183.0,341.0,,34900.0,,6790.0,1160.0,84300.0,972.0,,,267.0,1660.0,2230.0,304.0,,1170.0,,504.0,7190.0,2510.0,996.0,199.0,3050.0,2420.0,185.0,1980.0,14800.0,320.0,322.0,244.0,20900.0,28200.0,200.0,13700.0,6460.0,2140.0,1180.0,16000.0,774.0,715.0,360.0,1700.0,8650.0,7890.0,5100.0,1340.0,15400.0,1650.0,,3490.0,353.0,7210.0,970.0,5270.0,481.0,30200.0,12800.0,,2400.0,161.0,,761.0,145.0,955.0,,,898.0,,989.0,1290.0,,292.0,430.0,1510.0,496.0,,881.0,1510.0,1190.0,2790.0,4150.0,980.0,,172.0,1570.0,245.0,24000.0,2990.0,651.0,1840.0,2380.0,15100.0,98.0,1080.0,772.0,479.0,3180.0,419.0,840.0 33 | 1991-01-01,19500.0,27000.0,,6580.0,349.0,589.0,1070.0,5740.0,,22400.0,18800.0,,1210.0,,7710.0,282.0,21100.0,346.0,1270.0,9060.0,203.0,383.0,27700.0,14000.0,768.0,2680.0,11900.0,467.0,2770.0,1750.0,2320.0,21600.0,,462.0,1110.0,38300.0,837.0,2710.0,1000.0,331.0,1210.0,2270.0,,2280.0,889.0,,9700.0,2870.0,23300.0,755.0,27000.0,2550.0,1320.0,1700.0,1640.0,,644.0,,14800.0,271.0,25500.0,1880.0,1680.0,,21800.0,5560.0,19900.0,2500.0,1310.0,439.0,18300.0,727.0,475.0,287.0,10300.0,1030.0,,247.0,466.0,15500.0,609.0,,479.0,3330.0,705.0,14100.0,12000.0,,310.0,,,27100.0,21900.0,1710.0,1230.0,28500.0,336.0,576.0,,661.0,584.0,4010.0,,7680.0,5510.0,,1510.0,235.0,1620.0,3080.0,51000.0,521.0,168.0,374.0,,37200.0,,7340.0,1220.0,83700.0,835.0,,,223.0,1700.0,2340.0,298.0,,1070.0,,694.0,7690.0,2670.0,1100.0,228.0,3580.0,2630.0,198.0,2050.0,15100.0,291.0,279.0,351.0,21400.0,28600.0,211.0,12200.0,6020.0,2300.0,1520.0,16200.0,889.0,716.0,398.0,2190.0,9060.0,8960.0,5420.0,1600.0,14200.0,1250.0,,3430.0,274.0,7850.0,999.0,5290.0,429.0,31400.0,14500.0,,2680.0,192.0,,725.0,,1090.0,,,979.0,,1010.0,1300.0,,306.0,412.0,1720.0,468.0,,848.0,1570.0,1390.0,2750.0,4360.0,1030.0,,194.0,1490.0,183.0,24400.0,3580.0,659.0,1970.0,2560.0,15900.0,143.0,1250.0,765.0,479.0,3350.0,420.0,805.0 34 | 1992-01-01,20500.0,26900.0,,6680.0,218.0,369.0,514.0,6820.0,,24800.0,18600.0,,676.0,,7480.0,282.0,23500.0,241.0,1210.0,9090.0,184.0,315.0,28700.0,15400.0,792.0,2530.0,11700.0,475.0,2830.0,1670.0,2660.0,20700.0,,463.0,1170.0,39400.0,861.0,3240.0,891.0,365.0,1420.0,2650.0,,2050.0,968.0,,11300.0,3340.0,26300.0,760.0,29500.0,2700.0,1500.0,1740.0,1710.0,,717.0,143.0,16100.0,204.0,22300.0,2060.0,1760.0,,23900.0,5600.0,20500.0,2580.0,757.0,415.0,18800.0,729.0,488.0,337.0,11200.0,1120.0,,213.0,509.0,18000.0,660.0,,305.0,3710.0,752.0,15700.0,12800.0,,324.0,,,27400.0,23200.0,1460.0,1420.0,31000.0,328.0,513.0,,677.0,614.0,4400.0,,8140.0,,,1520.0,251.0,1970.0,3370.0,55300.0,557.0,110.0,434.0,,41200.0,,7600.0,1240.0,91700.0,625.0,,,247.0,1840.0,1160.0,343.0,,587.0,,684.0,8370.0,2970.0,1250.0,184.0,4050.0,3080.0,137.0,2280.0,16300.0,284.0,291.0,413.0,23500.0,30500.0,179.0,11800.0,6340.0,2560.0,1550.0,17300.0,1000.0,815.0,415.0,2410.0,9660.0,10800.0,5190.0,1600.0,15600.0,1100.0,,3100.0,310.0,7900.0,1150.0,6050.0,257.0,32300.0,16100.0,,2910.0,169.0,,751.0,,966.0,,,1080.0,,1000.0,1420.0,,297.0,425.0,1930.0,346.0,,824.0,1830.0,1440.0,2850.0,4470.0,1070.0,,174.0,1420.0,152.0,25500.0,4080.0,604.0,2160.0,2830.0,16800.0,144.0,1260.0,799.0,496.0,3560.0,387.0,615.0 35 | 1993-01-01,16500.0,26200.0,,7040.0,381.0,357.0,464.0,6970.0,,24000.0,17700.0,,530.0,,7820.0,289.0,22400.0,244.0,1280.0,9710.0,156.0,407.0,30900.0,14700.0,786.0,2790.0,11400.0,453.0,2760.0,1590.0,2820.0,19900.0,,409.0,744.0,38000.0,826.0,3420.0,1030.0,376.0,1580.0,2910.0,,2070.0,1290.0,,10500.0,3920.0,25500.0,726.0,27600.0,2810.0,1690.0,1770.0,1750.0,,785.0,140.0,13400.0,165.0,17600.0,2170.0,1910.0,,22500.0,4270.0,18400.0,2550.0,550.0,375.0,16800.0,749.0,460.0,329.0,10400.0,1200.0,,217.0,611.0,20400.0,655.0,,249.0,3850.0,840.0,14600.0,12500.0,,309.0,,1020.0,23800.0,18700.0,2000.0,1440.0,35500.0,223.0,449.0,251.0,653.0,594.0,4740.0,,8870.0,,,1430.0,287.0,2600.0,3430.0,55900.0,586.0,79.9,426.0,,41800.0,,6730.0,1150.0,85400.0,640.0,,,267.0,1990.0,1290.0,314.0,,340.0,,567.0,7430.0,2970.0,1380.0,211.0,5500.0,3400.0,136.0,2060.0,16600.0,188.0,153.0,395.0,22700.0,28000.0,187.0,13100.0,6110.0,2740.0,1480.0,17700.0,1110.0,817.0,428.0,2450.0,10200.0,9540.0,4640.0,1580.0,14500.0,1160.0,,2930.0,325.0,7440.0,1210.0,6520.0,315.0,24100.0,18300.0,,3090.0,193.0,,690.0,,1010.0,,,1240.0,,1010.0,1470.0,,224.0,302.0,2150.0,293.0,,796.0,1700.0,1450.0,3180.0,3680.0,1050.0,,156.0,1260.0,166.0,26500.0,4720.0,597.0,2210.0,2750.0,18700.0,189.0,1180.0,796.0,391.0,3580.0,389.0,585.0 36 | 1994-01-01,16200.0,26600.0,,7510.0,619.0,400.0,346.0,7480.0,,25600.0,18100.0,17300.0,436.0,343.0,8200.0,288.0,24300.0,193.0,1150.0,10100.0,151.0,276.0,31500.0,14200.0,801.0,3500.0,11800.0,529.0,2760.0,1460.0,2870.0,19800.0,143.0,266.0,668.0,41700.0,602.0,3880.0,681.0,472.0,2270.0,3110.0,,2620.0,1040.0,,11600.0,4580.0,27100.0,753.0,30000.0,3020.0,1850.0,1480.0,2050.0,,862.0,158.0,13500.0,126.0,20300.0,2380.0,1910.0,,23600.0,3980.0,19700.0,2630.0,517.0,333.0,18100.0,720.0,450.0,236.0,11100.0,1330.0,,211.0,745.0,22500.0,629.0,,282.0,4150.0,926.0,15900.0,13800.0,,355.0,,1130.0,24300.0,19300.0,2010.0,1540.0,38800.0,268.0,372.0,268.0,746.0,409.0,5230.0,,10300.0,,,1320.0,325.0,3230.0,3560.0,64100.0,655.0,65.5,438.0,,45800.0,,6150.0,1280.0,89400.0,461.0,,,228.0,2140.0,1720.0,201.0,,406.0,,580.0,8150.0,3200.0,1490.0,120.0,5640.0,3690.0,140.0,2260.0,16000.0,177.0,171.0,848.0,24200.0,29300.0,203.0,15300.0,6120.0,2860.0,1860.0,16600.0,1200.0,942.0,420.0,2820.0,10900.0,9980.0,4970.0,1680.0,14900.0,1320.0,,2660.0,132.0,7380.0,1330.0,6580.0,440.0,25700.0,21600.0,,3760.0,231.0,,457.0,,1410.0,,,1420.0,,726.0,1500.0,,175.0,235.0,2470.0,236.0,,625.0,1780.0,2020.0,2270.0,3960.0,1180.0,,160.0,1010.0,199.0,27800.0,5460.0,576.0,2250.0,2610.0,,230.0,1340.0,1310.0,289.0,3650.0,424.0,603.0 37 | 1995-01-01,18500.0,28000.0,,7230.0,761.0,456.0,416.0,7410.0,,30300.0,20400.0,16400.0,397.0,530.0,8600.0,317.0,28500.0,236.0,1550.0,10400.0,161.0,362.0,34000.0,16000.0,879.0,4850.0,12200.0,595.0,2990.0,1370.0,3000.0,20500.0,134.0,341.0,778.0,48500.0,774.0,4940.0,627.0,608.0,2530.0,3370.0,,2780.0,1220.0,,15200.0,5770.0,31700.0,750.0,35400.0,3140.0,2050.0,1420.0,2160.0,3040.0,984.0,170.0,15600.0,134.0,26300.0,2540.0,2070.0,,27000.0,4590.0,21300.0,2760.0,569.0,386.0,21700.0,738.0,471.0,321.0,12900.0,1470.0,,223.0,854.0,23500.0,699.0,4790.0,359.0,4470.0,1040.0,19100.0,17900.0,12700.0,384.0,,1500.0,26900.0,20600.0,2340.0,1600.0,42500.0,330.0,364.0,320.0,754.0,498.0,5380.0,,12400.0,17100.0,,1290.0,362.0,3860.0,3810.0,78800.0,718.0,64.8,490.0,,53200.0,2370.0,5380.0,1370.0,102000.0,477.0,,,235.0,2360.0,2260.0,274.0,,632.0,,606.0,9720.0,3600.0,1630.0,140.0,3600.0,4290.0,141.0,2380.0,18700.0,205.0,263.0,889.0,28800.0,34900.0,214.0,17400.0,6410.0,2870.0,2170.0,18500.0,983.0,1060.0,479.0,3610.0,11600.0,11800.0,5520.0,1890.0,16200.0,1560.0,,2670.0,228.0,7670.0,1450.0,6750.0,462.0,29900.0,24900.0,10700.0,4800.0,222.0,,560.0,,1590.0,,,1650.0,,795.0,1760.0,,207.0,306.0,2850.0,213.0,,593.0,2010.0,2110.0,2900.0,4250.0,1190.0,,181.0,936.0,278.0,28800.0,5980.0,586.0,2460.0,3390.0,,288.0,1390.0,1320.0,284.0,3970.0,431.0,611.0 38 | 1996-01-01,19000.0,29800.0,,7700.0,951.0,503.0,604.0,7720.0,,29700.0,21900.0,16600.0,409.0,799.0,9140.0,379.0,27600.0,249.0,1210.0,10500.0,138.0,382.0,44800.0,16900.0,947.0,5190.0,12700.0,617.0,2990.0,1450.0,3020.0,21100.0,134.0,301.0,908.0,46600.0,830.0,5170.0,680.0,707.0,2610.0,3320.0,,2280.0,1230.0,,15100.0,6470.0,30500.0,731.0,35700.0,3320.0,2230.0,1570.0,2180.0,3350.0,1090.0,200.0,16200.0,145.0,25800.0,2710.0,2020.0,,27000.0,5140.0,22400.0,2920.0,670.0,404.0,21400.0,774.0,478.0,509.0,13700.0,1540.0,,232.0,965.0,24800.0,705.0,5270.0,364.0,4500.0,1150.0,20800.0,19200.0,14000.0,411.0,,1800.0,28000.0,23000.0,2600.0,1600.0,37400.0,427.0,395.0,316.0,876.0,483.0,5660.0,,13300.0,19900.0,30200.0,1350.0,376.0,4460.0,3800.0,80000.0,758.0,72.5,459.0,,52200.0,2440.0,5760.0,1500.0,101000.0,462.0,,,288.0,2160.0,2240.0,284.0,,581.0,,600.0,9850.0,3900.0,1800.0,225.0,4090.0,4740.0,197.0,2310.0,18300.0,209.0,315.0,906.0,28500.0,37300.0,214.0,18800.0,7020.0,3310.0,2220.0,18000.0,1060.0,1160.0,487.0,4070.0,12200.0,12200.0,6110.0,1990.0,17700.0,1560.0,,2640.0,233.0,8370.0,1530.0,6580.0,293.0,32600.0,26300.0,10800.0,5180.0,240.0,,567.0,,1950.0,,,1780.0,,935.0,1630.0,,223.0,334.0,3050.0,178.0,,558.0,2150.0,2280.0,3050.0,4580.0,1330.0,,217.0,873.0,282.0,30100.0,6320.0,601.0,2600.0,3030.0,,337.0,1430.0,1460.0,371.0,3690.0,396.0,722.0 39 | 1997-01-01,18400.0,30200.0,,8030.0,698.0,523.0,598.0,8210.0,,26600.0,23500.0,17900.0,506.0,1040.0,9630.0,386.0,25000.0,230.0,1350.0,10600.0,153.0,357.0,48500.0,16800.0,993.0,5310.0,17300.0,702.0,3030.0,1400.0,2990.0,21700.0,138.0,274.0,807.0,40400.0,779.0,5570.0,669.0,779.0,2810.0,3510.0,,2300.0,1170.0,,14200.0,5980.0,27000.0,731.0,32800.0,3470.0,2370.0,1590.0,2390.0,3610.0,1240.0,193.0,14900.0,142.0,24700.0,2640.0,1910.0,,24400.0,4680.0,24700.0,3020.0,775.0,392.0,19100.0,713.0,456.0,939.0,13300.0,1700.0,,225.0,1020.0,27300.0,797.0,5210.0,410.0,4570.0,1080.0,22500.0,19400.0,16000.0,427.0,,1680.0,28100.0,21800.0,2950.0,1630.0,34300.0,453.0,376.0,302.0,878.0,433.0,6270.0,,12200.0,18600.0,,1450.0,343.0,5090.0,4000.0,72400.0,813.0,125.0,477.0,,46400.0,2850.0,6230.0,1340.0,90900.0,528.0,,,247.0,2060.0,1880.0,262.0,,506.0,,566.0,9680.0,3650.0,1980.0,256.0,4860.0,4590.0,225.0,2330.0,16300.0,187.0,314.0,905.0,26300.0,36600.0,227.0,17500.0,7270.0,3510.0,2290.0,15900.0,993.0,1130.0,467.0,4080.0,12800.0,11600.0,6250.0,1980.0,21300.0,1560.0,3180.0,2740.0,286.0,8660.0,1500.0,7280.0,369.0,29900.0,26400.0,10400.0,5140.0,216.0,,510.0,,2080.0,,,1900.0,,956.0,1710.0,,207.0,333.0,2510.0,155.0,,565.0,2250.0,2200.0,3140.0,4550.0,1370.0,,250.0,991.0,284.0,31600.0,7330.0,623.0,2710.0,3730.0,,361.0,1460.0,1660.0,425.0,3730.0,462.0,708.0 40 | 1998-01-01,19000.0,27500.0,,8360.0,872.0,608.0,491.0,8280.0,,27300.0,21300.0,19100.0,562.0,1130.0,10800.0,392.0,25500.0,256.0,1770.0,10000.0,139.0,375.0,51400.0,12800.0,1040.0,5110.0,18500.0,706.0,2830.0,1510.0,3060.0,20900.0,138.0,277.0,658.0,41500.0,817.0,5270.0,637.0,826.0,2550.0,3760.0,40500.0,2330.0,1230.0,,15000.0,6450.0,27300.0,735.0,33400.0,3680.0,2520.0,1560.0,2320.0,4050.0,1320.0,203.0,15500.0,125.0,26000.0,2070.0,2030.0,24500.0,25100.0,3840.0,26100.0,3360.0,805.0,416.0,20500.0,725.0,424.0,762.0,13400.0,1810.0,,169.0,973.0,25800.0,870.0,5650.0,449.0,4730.0,470.0,24200.0,19300.0,18500.0,425.0,,1610.0,31000.0,22300.0,3420.0,1730.0,31000.0,475.0,345.0,267.0,839.0,429.0,6470.0,,8130.0,15100.0,,1470.0,246.0,5540.0,4300.0,76900.0,841.0,141.0,450.0,,47900.0,3150.0,5440.0,1410.0,93100.0,449.0,,,253.0,2090.0,1770.0,267.0,,477.0,,539.0,10100.0,3590.0,2060.0,164.0,4990.0,3230.0,249.0,2110.0,15400.0,203.0,274.0,939.0,27500.0,34800.0,219.0,14700.0,6490.0,3730.0,2160.0,16500.0,742.0,971.0,453.0,4480.0,14300.0,12200.0,6330.0,1760.0,18600.0,1870.0,2420.0,1830.0,277.0,7560.0,1210.0,7720.0,346.0,30100.0,21800.0,11200.0,5530.0,170.0,,536.0,,2080.0,,,2040.0,,975.0,1530.0,,226.0,344.0,1840.0,220.0,,593.0,2340.0,1950.0,4390.0,4790.0,1370.0,,297.0,835.0,289.0,32900.0,7710.0,623.0,2950.0,3890.0,,361.0,1470.0,1560.0,382.0,3290.0,369.0,523.0 41 | 1999-01-01,19300.0,29200.0,,8570.0,1100.0,597.0,455.0,7760.0,,27100.0,20500.0,19400.0,574.0,1250.0,11300.0,394.0,25400.0,267.0,1660.0,10300.0,123.0,369.0,54200.0,14200.0,996.0,3500.0,20500.0,764.0,3180.0,1210.0,3160.0,22100.0,103.0,280.0,773.0,40600.0,783.0,4780.0,676.0,870.0,2200.0,4110.0,42400.0,2560.0,1360.0,,15200.0,6290.0,26800.0,753.0,33400.0,3830.0,2550.0,1560.0,1600.0,4140.0,1390.0,182.0,15900.0,120.0,26200.0,2410.0,2050.0,24600.0,24800.0,3900.0,26600.0,3740.0,629.0,420.0,20200.0,683.0,402.0,1240.0,13100.0,1670.0,,180.0,938.0,25100.0,880.0,5140.0,493.0,4780.0,680.0,26200.0,19000.0,20700.0,455.0,,1610.0,32300.0,21900.0,3430.0,1740.0,35000.0,423.0,258.0,294.0,868.0,432.0,6790.0,,10400.0,16600.0,,1130.0,275.0,5510.0,4470.0,81500.0,822.0,161.0,436.0,,51700.0,3500.0,7060.0,1390.0,91400.0,321.0,,,244.0,2070.0,1810.0,258.0,,445.0,,535.0,10300.0,3650.0,2200.0,161.0,5660.0,3460.0,255.0,2060.0,14600.0,190.0,299.0,967.0,27800.0,36400.0,222.0,15300.0,7230.0,3830.0,1930.0,16300.0,663.0,1090.0,448.0,4350.0,15200.0,12500.0,6010.0,1600.0,21700.0,1580.0,2440.0,1330.0,231.0,8200.0,1200.0,7750.0,319.0,30600.0,21800.0,11400.0,5640.0,166.0,32100.0,535.0,,1920.0,,,2100.0,,992.0,1480.0,,192.0,332.0,1990.0,178.0,,551.0,2430.0,2000.0,4010.0,5380.0,1460.0,,301.0,636.0,255.0,34600.0,7250.0,702.0,3080.0,4090.0,,374.0,1480.0,1490.0,449.0,3180.0,346.0,554.0 42 | 2000-01-01,21400.0,34500.0,,10100.0,1190.0,621.0,656.0,7700.0,,24500.0,21700.0,20600.0,655.0,1440.0,11700.0,403.0,23200.0,227.0,1630.0,13600.0,130.0,339.0,56300.0,18100.0,989.0,3770.0,21300.0,778.0,3300.0,1270.0,3490.0,24000.0,407.0,251.0,1030.0,37800.0,664.0,5130.0,583.0,955.0,2500.0,4060.0,43300.0,2740.0,1220.0,,14300.0,5990.0,23700.0,763.0,30700.0,4820.0,2770.0,1730.0,1460.0,4070.0,1510.0,179.0,14800.0,125.0,24300.0,2070.0,2170.0,22900.0,22500.0,4140.0,26300.0,5120.0,692.0,265.0,19000.0,637.0,342.0,2020.0,12000.0,1720.0,,291.0,957.0,25800.0,1140.0,4920.0,461.0,4610.0,790.0,26100.0,20900.0,20400.0,457.0,,1540.0,31800.0,20100.0,3480.0,1760.0,37300.0,406.0,280.0,299.0,815.0,382.0,9220.0,,11900.0,19800.0,,1230.0,321.0,5330.0,4980.0,75100.0,855.0,183.0,416.0,,48800.0,4170.0,7390.0,1280.0,82500.0,354.0,1630.0,,246.0,2130.0,1840.0,236.0,,474.0,,478.0,10400.0,3860.0,2290.0,154.0,6580.0,4000.0,236.0,2060.0,12600.0,164.0,378.0,1000.0,26000.0,38100.0,237.0,13600.0,8900.0,3800.0,1960.0,14500.0,655.0,1040.0,514.0,4490.0,16200.0,11500.0,7830.0,1530.0,29900.0,1660.0,870.0,1770.0,207.0,9350.0,1060.0,7580.0,356.0,29300.0,23800.0,10200.0,5400.0,154.0,28700.0,475.0,,1910.0,,550.0,2200.0,,1180.0,1430.0,,167.0,266.0,1970.0,139.0,431.0,645.0,2250.0,1930.0,4220.0,6430.0,1460.0,,308.0,636.0,255.0,36400.0,6870.0,558.0,3670.0,4800.0,,433.0,1470.0,1540.0,550.0,3100.0,356.0,535.0 43 | 2001-01-01,21800.0,33000.0,115.0,9800.0,1340.0,692.0,621.0,7210.0,,24500.0,19500.0,20700.0,704.0,1480.0,11600.0,401.0,23100.0,235.0,1780.0,12800.0,128.0,348.0,58900.0,16500.0,939.0,3160.0,21500.0,820.0,3080.0,1240.0,3560.0,23600.0,154.0,252.0,872.0,38500.0,682.0,4630.0,589.0,1050.0,2420.0,4090.0,41600.0,2840.0,1250.0,,14700.0,6590.0,23700.0,780.0,30800.0,4930.0,2830.0,1700.0,1910.0,4490.0,1450.0,183.0,15400.0,121.0,24900.0,2040.0,2240.0,24500.0,22500.0,4000.0,25900.0,5110.0,734.0,275.0,19300.0,543.0,319.0,2730.0,12400.0,1630.0,,301.0,931.0,25200.0,1190.0,5250.0,412.0,5250.0,757.0,28100.0,20100.0,20800.0,466.0,,1730.0,28600.0,20400.0,3490.0,1820.0,32700.0,404.0,308.0,319.0,749.0,406.0,9960.0,,11300.0,17600.0,,1490.0,323.0,5260.0,4660.0,74400.0,838.0,172.0,377.0,,47600.0,4470.0,6490.0,1290.0,82500.0,408.0,1910.0,,279.0,2210.0,1800.0,249.0,,524.0,,464.0,9970.0,3790.0,3180.0,148.0,6880.0,3880.0,217.0,1840.0,,171.0,350.0,1030.0,26600.0,38500.0,254.0,13900.0,8690.0,3790.0,1960.0,,558.0,962.0,492.0,4980.0,18200.0,11700.0,8280.0,1400.0,28700.0,1830.0,1630.0,2100.0,191.0,8760.0,946.0,7660.0,373.0,27000.0,21600.0,10500.0,5710.0,251.0,29700.0,482.0,,1610.0,,540.0,2310.0,,1260.0,1260.0,,198.0,267.0,1830.0,172.0,519.0,777.0,2290.0,1700.0,3060.0,6940.0,1390.0,,306.0,781.0,233.0,37300.0,6280.0,457.0,3980.0,4940.0,,449.0,1360.0,1560.0,547.0,2710.0,395.0,538.0 44 | 2002-01-01,24000.0,34100.0,186.0,10000.0,1460.0,780.0,840.0,2710.0,,26400.0,20100.0,20400.0,763.0,1710.0,11800.0,399.0,25000.0,261.0,2080.0,13100.0,117.0,379.0,62600.0,16900.0,894.0,2840.0,22500.0,897.0,3010.0,1480.0,3700.0,24000.0,176.0,263.0,920.0,41300.0,740.0,4490.0,648.0,1140.0,2380.0,4110.0,44200.0,3000.0,1350.0,,16000.0,8010.0,25200.0,794.0,33200.0,4840.0,2970.0,1740.0,2190.0,5300.0,1290.0,170.0,17000.0,112.0,26800.0,2260.0,2260.0,26600.0,24300.0,4130.0,28200.0,5290.0,779.0,312.0,20700.0,443.0,326.0,3280.0,13900.0,1770.0,,312.0,962.0,24700.0,1200.0,6050.0,392.0,6630.0,910.0,32400.0,18200.0,24200.0,487.0,,1720.0,31900.0,22200.0,3720.0,1900.0,31200.0,398.0,322.0,337.0,842.0,444.0,10200.0,,12800.0,18600.0,,1660.0,317.0,5450.0,4630.0,79500.0,904.0,175.0,348.0,,52200.0,4990.0,3840.0,1360.0,89000.0,459.0,2110.0,,263.0,2390.0,1940.0,307.0,,572.0,,460.0,10800.0,3960.0,3220.0,223.0,6950.0,4130.0,217.0,1720.0,,184.0,457.0,995.0,28800.0,43100.0,251.0,16900.0,8730.0,3860.0,2040.0,,530.0,1000.0,483.0,5200.0,19000.0,12900.0,8390.0,1140.0,30700.0,2120.0,2150.0,2380.0,187.0,8640.0,786.0,8330.0,407.0,29600.0,22000.0,11800.0,6540.0,276.0,31400.0,513.0,,2250.0,,586.0,2380.0,,1270.0,1130.0,,222.0,288.0,1990.0,191.0,494.0,970.0,2370.0,1830.0,3580.0,7050.0,1620.0,,311.0,879.0,238.0,38200.0,4090.0,383.0,4270.0,3670.0,,477.0,1350.0,1630.0,576.0,2540.0,395.0,502.0 45 | 2003-01-01,31400.0,36900.0,198.0,10400.0,1860.0,925.0,920.0,3410.0,,32100.0,23400.0,20800.0,884.0,2150.0,12100.0,432.0,30700.0,332.0,2700.0,14300.0,108.0,464.0,66100.0,18500.0,896.0,3080.0,22000.0,1010.0,4100.0,1820.0,3830.0,28000.0,175.0,298.0,1040.0,48000.0,905.0,4870.0,791.0,1280.0,2260.0,4200.0,48200.0,3190.0,1740.0,,20100.0,9740.0,30300.0,824.0,40500.0,5000.0,2340.0,2060.0,2440.0,7170.0,1190.0,195.0,21500.0,120.0,32800.0,2830.0,2290.0,30800.0,29700.0,4940.0,32600.0,5770.0,922.0,376.0,25100.0,361.0,374.0,4370.0,18300.0,1820.0,,350.0,984.0,24000.0,1230.0,7810.0,329.0,8370.0,1080.0,40900.0,18800.0,28700.0,565.0,,1980.0,39100.0,27400.0,3590.0,1970.0,33700.0,440.0,381.0,360.0,1030.0,557.0,9720.0,,14200.0,22600.0,,2070.0,360.0,5440.0,4980.0,89900.0,985.0,131.0,510.0,,64400.0,5630.0,4840.0,1660.0,109000.0,548.0,2790.0,,317.0,2430.0,2380.0,389.0,,646.0,,527.0,12800.0,4620.0,3630.0,198.0,6600.0,4430.0,235.0,2490.0,,223.0,510.0,1000.0,35200.0,50100.0,258.0,21900.0,9060.0,3990.0,2180.0,,609.0,1020.0,546.0,5690.0,19800.0,15800.0,8150.0,1160.0,35600.0,2760.0,2830.0,2980.0,202.0,9390.0,745.0,8520.0,472.0,37000.0,23600.0,14900.0,8710.0,291.0,39100.0,643.0,,2610.0,,687.0,2500.0,,1260.0,1700.0,,294.0,318.0,2210.0,238.0,485.0,1290.0,2790.0,2090.0,4600.0,8750.0,1900.0,,326.0,1050.0,236.0,39700.0,3620.0,396.0,4450.0,3240.0,,531.0,1580.0,1910.0,617.0,3800.0,450.0,452.0 46 | 2004-01-01,36900.0,40400.0,220.0,11000.0,2470.0,1180.0,1230.0,4780.0,,36700.0,30400.0,22600.0,1050.0,2580.0,12900.0,461.0,35500.0,371.0,3330.0,16000.0,122.0,511.0,70400.0,21800.0,955.0,3640.0,22000.0,1110.0,4830.0,2380.0,3990.0,31800.0,196.0,326.0,1350.0,53300.0,966.0,6220.0,893.0,1500.0,2750.0,4380.0,55800.0,3390.0,1950.0,,23600.0,11700.0,34100.0,870.0,46500.0,5330.0,2410.0,2550.0,2700.0,8850.0,1120.0,238.0,24900.0,137.0,37600.0,3330.0,2250.0,34500.0,33900.0,5760.0,38300.0,5840.0,1190.0,426.0,28900.0,416.0,391.0,7530.0,21700.0,1940.0,,382.0,1040.0,24900.0,1300.0,9370.0,387.0,10200.0,1160.0,47400.0,19700.0,34600.0,650.0,1370.0,2350.0,47000.0,31200.0,3860.0,2160.0,36400.0,462.0,433.0,406.0,1150.0,629.0,10300.0,,15900.0,27100.0,,2870.0,415.0,5440.0,5420.0,100000.0,1060.0,147.0,646.0,6710.0,74700.0,6750.0,6010.0,1880.0,123000.0,721.0,3380.0,,246.0,2520.0,2720.0,421.0,,798.0,,600.0,14100.0,5230.0,4110.0,209.0,7040.0,4920.0,279.0,3300.0,,240.0,646.0,1080.0,39700.0,57600.0,292.0,25500.0,10100.0,4290.0,2430.0,,660.0,1080.0,631.0,6640.0,21000.0,18000.0,8870.0,1390.0,44100.0,3530.0,3330.0,4100.0,226.0,10900.0,819.0,10200.0,557.0,42400.0,27400.0,17300.0,10700.0,290.0,45000.0,732.0,,3010.0,,734.0,2610.0,,1420.0,2210.0,,457.0,359.0,2480.0,312.0,482.0,1460.0,3140.0,2350.0,5870.0,9990.0,2230.0,,350.0,1370.0,286.0,41900.0,4120.0,465.0,4810.0,4280.0,,607.0,1790.0,2350.0,707.0,4890.0,557.0,457.0 47 | 2005-01-01,40000.0,43500.0,252.0,12100.0,2780.0,1630.0,1710.0,5770.0,,38200.0,34000.0,23300.0,1580.0,2810.0,14200.0,485.0,36900.0,407.0,3790.0,18200.0,144.0,533.0,75900.0,25900.0,1020.0,4790.0,23400.0,1260.0,5290.0,3130.0,4100.0,36000.0,221.0,341.0,1720.0,54800.0,982.0,7610.0,915.0,1740.0,3390.0,4620.0,57200.0,3780.0,2030.0,,24700.0,13300.0,34700.0,912.0,48800.0,5250.0,3580.0,3040.0,3010.0,10300.0,1250.0,226.0,26500.0,163.0,39000.0,3660.0,2350.0,35200.0,34900.0,6860.0,39900.0,6750.0,1470.0,502.0,29900.0,434.0,307.0,13600.0,22300.0,2150.0,,413.0,1080.0,26600.0,1400.0,10200.0,465.0,11100.0,1270.0,50600.0,20400.0,37000.0,740.0,1820.0,2740.0,56600.0,32000.0,4250.0,2330.0,35800.0,524.0,477.0,471.0,1170.0,633.0,11100.0,,18700.0,35200.0,,3770.0,472.0,5340.0,5660.0,105000.0,1240.0,166.0,711.0,7860.0,79600.0,7630.0,8460.0,1950.0,127000.0,831.0,3670.0,,276.0,2650.0,2990.0,444.0,,999.0,,694.0,14800.0,5120.0,3760.0,213.0,7820.0,5550.0,313.0,3580.0,,258.0,804.0,1160.0,41200.0,66800.0,321.0,27800.0,12300.0,4590.0,2700.0,,798.0,1200.0,693.0,7980.0,22000.0,18800.0,9720.0,1480.0,54200.0,4650.0,3530.0,5320.0,274.0,13300.0,882.0,11100.0,669.0,43100.0,29900.0,18200.0,11700.0,318.0,46200.0,773.0,,3590.0,,797.0,2810.0,,1590.0,2340.0,,664.0,382.0,2690.0,340.0,500.0,1710.0,3220.0,2560.0,7130.0,12300.0,2250.0,,449.0,1830.0,314.0,44300.0,5220.0,547.0,5060.0,5440.0,,699.0,1890.0,2590.0,832.0,5440.0,726.0,453.0 48 | 2006-01-01,43200.0,45600.0,275.0,13600.0,3050.0,2130.0,2440.0,6750.0,,40400.0,36100.0,24000.0,2470.0,3240.0,15700.0,496.0,38900.0,423.0,4370.0,19500.0,158.0,557.0,83900.0,30600.0,1200.0,5890.0,23700.0,1350.0,5320.0,3850.0,4360.0,40200.0,257.0,365.0,2120.0,57300.0,1010.0,9370.0,965.0,2080.0,3710.0,5130.0,62300.0,4670.0,2300.0,,26500.0,15200.0,36400.0,976.0,52000.0,5630.0,3770.0,3390.0,3340.0,12600.0,1470.0,241.0,28500.0,195.0,41100.0,3750.0,2390.0,39900.0,36500.0,7190.0,42400.0,6760.0,1760.0,930.0,30600.0,442.0,299.0,13000.0,24600.0,2330.0,,407.0,1910.0,28200.0,1540.0,11400.0,507.0,11300.0,1600.0,53900.0,21600.0,41300.0,830.0,2320.0,3420.0,56300.0,33400.0,4500.0,2720.0,34100.0,703.0,543.0,537.0,1140.0,659.0,12800.0,,20900.0,42000.0,64100.0,5290.0,586.0,5340.0,6320.0,114000.0,1420.0,178.0,736.0,9240.0,88400.0,9750.0,9670.0,2130.0,136000.0,951.0,4380.0,,293.0,2760.0,3280.0,497.0,,1330.0,,939.0,15700.0,5460.0,4870.0,234.0,8620.0,6180.0,329.0,3890.0,,267.0,1010.0,1230.0,44000.0,74100.0,353.0,26600.0,14600.0,5000.0,3130.0,,885.0,1400.0,853.0,9000.0,22900.0,19800.0,9720.0,1770.0,62900.0,5790.0,4130.0,6920.0,322.0,14900.0,950.0,12000.0,879.0,46300.0,33600.0,19700.0,13100.0,357.0,48800.0,808.0,,5200.0,,851.0,3040.0,,1770.0,2640.0,,717.0,387.0,3140.0,407.0,463.0,2140.0,3390.0,2830.0,7740.0,14100.0,2350.0,,480.0,2300.0,335.0,46400.0,5880.0,643.0,5610.0,6750.0,,797.0,2050.0,2790.0,924.0,5660.0,1080.0,428.0 49 | 2007-01-01,49300.0,44500.0,374.0,15300.0,3600.0,3080.0,3410.0,8380.0,,46600.0,41000.0,25900.0,3850.0,3990.0,16500.0,544.0,44400.0,476.0,5780.0,21000.0,163.0,633.0,90800.0,32100.0,1360.0,7350.0,24300.0,1760.0,5710.0,4740.0,4510.0,44300.0,286.0,413.0,2230.0,63200.0,1130.0,10400.0,1070.0,2670.0,4660.0,5900.0,73600.0,5190.0,3130.0,,30900.0,18300.0,41800.0,1060.0,58500.0,6060.0,4540.0,3850.0,3570.0,16600.0,1760.0,253.0,32700.0,245.0,48300.0,4080.0,2430.0,46000.0,41600.0,8590.0,48300.0,7320.0,2320.0,1100.0,37500.0,522.0,411.0,15900.0,28500.0,2560.0,,469.0,2260.0,30600.0,1710.0,13500.0,619.0,13800.0,1870.0,61200.0,24600.0,49700.0,1070.0,3090.0,4280.0,68800.0,37700.0,4810.0,3020.0,34000.0,847.0,722.0,628.0,1320.0,731.0,13600.0,,23100.0,44900.0,,6770.0,702.0,5940.0,6720.0,130000.0,1610.0,210.0,817.0,12300.0,103000.0,14100.0,11700.0,2420.0,171000.0,1230.0,5960.0,,379.0,2880.0,3980.0,561.0,,1630.0,,1010.0,18400.0,6290.0,5660.0,266.0,9190.0,7220.0,411.0,4200.0,,302.0,1130.0,1330.0,50900.0,85100.0,398.0,32400.0,16400.0,6050.0,3610.0,,991.0,1680.0,930.0,11200.0,23700.0,22800.0,9730.0,2250.0,69200.0,8170.0,5460.0,9100.0,380.0,16100.0,1050.0,12200.0,1090.0,53300.0,39200.0,23800.0,16000.0,399.0,55600.0,948.0,,5750.0,,883.0,3280.0,,2070.0,2690.0,,808.0,432.0,3740.0,523.0,550.0,2610.0,3810.0,2930.0,9310.0,16500.0,2770.0,,538.0,3070.0,400.0,48100.0,7010.0,830.0,6270.0,8330.0,,919.0,2390.0,3130.0,1210.0,6150.0,1160.0,415.0 50 | 2008-01-01,50000.0,46400.0,377.0,15800.0,4370.0,3920.0,4600.0,10200.0,,51400.0,49700.0,27500.0,5570.0,4850.0,16600.0,619.0,48600.0,571.0,7120.0,23000.0,187.0,739.0,93600.0,37100.0,1700.0,8840.0,23700.0,1820.0,5660.0,6380.0,4660.0,46400.0,327.0,474.0,3060.0,72100.0,1330.0,10700.0,1190.0,3440.0,5400.0,6580.0,,5380.0,3690.0,,35000.0,22600.0,45600.0,1230.0,64200.0,6610.0,4870.0,4790.0,4260.0,18100.0,2160.0,256.0,35600.0,328.0,53400.0,4180.0,2500.0,48700.0,45400.0,10500.0,45200.0,7950.0,2920.0,1230.0,30900.0,612.0,438.0,23500.0,31700.0,2870.0,,570.0,2480.0,31500.0,1880.0,15900.0,679.0,15600.0,2180.0,61000.0,29300.0,,1040.0,4470.0,4900.0,55400.0,40700.0,5130.0,3800.0,37900.0,926.0,966.0,743.0,1420.0,806.0,14400.0,,20500.0,54500.0,,8510.0,887.0,6890.0,6780.0,143000.0,2010.0,231.0,827.0,15000.0,112000.0,16400.0,14800.0,2830.0,194000.0,1700.0,7330.0,,472.0,2920.0,4720.0,665.0,,2140.0,,1180.0,20900.0,7750.0,6750.0,302.0,9580.0,8450.0,485.0,4010.0,,367.0,1380.0,1500.0,56600.0,96900.0,478.0,31000.0,23500.0,7000.0,4250.0,,1220.0,1930.0,1020.0,13900.0,24900.0,24800.0,9840.0,2970.0,84800.0,9950.0,6700.0,11600.0,469.0,19700.0,1210.0,11100.0,1260.0,55700.0,39700.0,27500.0,18600.0,453.0,62200.0,1090.0,,6860.0,1710.0,1090.0,3480.0,,,2620.0,,938.0,528.0,4120.0,709.0,672.0,3920.0,4340.0,3300.0,10400.0,21200.0,3090.0,,666.0,3890.0,448.0,48400.0,9070.0,1020.0,6370.0,11200.0,,1160.0,2700.0,3380.0,1400.0,5810.0,1440.0,345.0 51 | 2009-01-01,46400.0,32900.0,451.0,14000.0,4110.0,2910.0,3990.0,9460.0,,47700.0,42700.0,24600.0,4950.0,4480.0,16500.0,685.0,45000.0,554.0,6740.0,19300.0,195.0,713.0,88500.0,27200.0,1740.0,8600.0,22100.0,1800.0,5260.0,5180.0,4440.0,40800.0,302.0,465.0,2400.0,69700.0,1310.0,10100.0,1160.0,3800.0,5100.0,6390.0,,5500.0,3520.0,,31700.0,19700.0,41700.0,1460.0,57900.0,7030.0,4840.0,3770.0,4240.0,14700.0,2460.0,334.0,32300.0,382.0,47100.0,3370.0,2670.0,45500.0,41600.0,8000.0,37100.0,7390.0,2440.0,1100.0,22500.0,553.0,435.0,13800.0,29500.0,2700.0,,532.0,2590.0,30700.0,1950.0,14100.0,674.0,12900.0,2270.0,51500.0,27600.0,,1150.0,3700.0,4930.0,40300.0,37000.0,4520.0,4030.0,39300.0,930.0,871.0,735.0,1320.0,787.0,13700.0,,18300.0,37200.0,,7170.0,931.0,8270.0,6720.0,126000.0,2060.0,302.0,860.0,11800.0,101000.0,12200.0,10600.0,2860.0,153000.0,1530.0,6700.0,,417.0,2910.0,4480.0,661.0,,1720.0,,1040.0,19600.0,7080.0,6780.0,345.0,7690.0,7280.0,459.0,4140.0,,353.0,1090.0,1460.0,51900.0,80000.0,484.0,28000.0,18200.0,7170.0,4190.0,,1210.0,1830.0,989.0,11400.0,25800.0,23100.0,9180.0,2510.0,62500.0,8070.0,5820.0,8560.0,504.0,16000.0,1160.0,9710.0,1200.0,46200.0,38600.0,24600.0,16500.0,435.0,,1020.0,,7450.0,1280.0,1130.0,3340.0,,,2680.0,,814.0,515.0,3980.0,669.0,780.0,4060.0,4160.0,3100.0,8630.0,14500.0,2760.0,,674.0,2550.0,517.0,47000.0,9420.0,1180.0,6180.0,11500.0,,1230.0,2640.0,3170.0,1280.0,5910.0,1200.0,633.0 52 | 2010-01-01,43000.0,33900.0,561.0,13000.0,4090.0,3120.0,4220.0,11500.0,,46600.0,51800.0,24300.0,5840.0,4380.0,15900.0,763.0,44400.0,578.0,6580.0,20500.0,220.0,690.0,88200.0,30900.0,1930.0,11300.0,21900.0,2210.0,6490.0,5820.0,4530.0,47500.0,330.0,457.0,2920.0,74300.0,1310.0,12700.0,1150.0,4510.0,6180.0,7770.0,,5700.0,3410.0,,30400.0,19800.0,41700.0,1350.0,57600.0,6930.0,5300.0,4350.0,4640.0,14600.0,2800.0,369.0,30700.0,344.0,46200.0,3650.0,2840.0,46400.0,40700.0,9300.0,38400.0,7370.0,2610.0,1330.0,,566.0,435.0,16600.0,26900.0,2880.0,,534.0,2870.0,32600.0,2080.0,13500.0,669.0,13000.0,3140.0,47900.0,30600.0,,1420.0,4470.0,5670.0,41700.0,35900.0,4920.0,4370.0,42900.0,978.0,880.0,783.0,1540.0,777.0,13200.0,,22200.0,38600.0,,9070.0,1120.0,8760.0,7010.0,141000.0,2400.0,327.0,1090.0,12000.0,103000.0,11400.0,12400.0,2820.0,145000.0,1630.0,6640.0,,414.0,3130.0,4470.0,674.0,,2650.0,,1200.0,19700.0,7770.0,7160.0,360.0,8920.0,8750.0,422.0,5170.0,,360.0,2310.0,1500.0,50300.0,87600.0,596.0,33400.0,20900.0,7830.0,5080.0,,1420.0,2140.0,1020.0,12500.0,26400.0,22500.0,9000.0,3100.0,71500.0,8140.0,5410.0,10700.0,526.0,19300.0,1280.0,10800.0,1440.0,52100.0,46600.0,23400.0,16500.0,448.0,,999.0,,8320.0,1580.0,1130.0,3440.0,,,2960.0,,909.0,503.0,4800.0,740.0,876.0,4390.0,4210.0,3550.0,10100.0,15500.0,3240.0,,712.0,2970.0,553.0,48400.0,11900.0,1380.0,6230.0,13600.0,,1330.0,2970.0,3530.0,1360.0,7390.0,1530.0,723.0 53 | 2011-01-01,44000.0,38900.0,616.0,12800.0,4440.0,3420.0,5160.0,13700.0,,51100.0,62100.0,25400.0,7190.0,4770.0,15500.0,842.0,47800.0,670.0,7590.0,22500.0,247.0,745.0,86000.0,41100.0,2320.0,13300.0,21500.0,2500.0,7890.0,6310.0,4700.0,52100.0,373.0,495.0,3410.0,88000.0,1310.0,14500.0,1260.0,5570.0,7120.0,8700.0,,6120.0,3800.0,,31800.0,21700.0,45900.0,1460.0,61300.0,7120.0,5720.0,5270.0,5200.0,17200.0,2970.0,440.0,32000.0,357.0,50800.0,4200.0,3000.0,49800.0,43800.0,11200.0,41000.0,7410.0,3220.0,1590.0,,521.0,454.0,21900.0,26000.0,3240.0,,679.0,3260.0,35100.0,2280.0,14500.0,749.0,14000.0,3660.0,51900.0,33300.0,,1500.0,5850.0,7640.0,46000.0,38400.0,5350.0,4670.0,46200.0,998.0,1120.0,878.0,1740.0,837.0,13700.0,,24200.0,49300.0,,11400.0,1270.0,9140.0,7190.0,158000.0,2840.0,377.0,1240.0,14400.0,114000.0,13700.0,5690.0,3040.0,163000.0,1970.0,7250.0,,456.0,3290.0,4990.0,739.0,,3780.0,,1380.0,22300.0,8980.0,7410.0,364.0,9810.0,10100.0,537.0,5600.0,,388.0,2510.0,1650.0,53500.0,101000.0,696.0,37900.0,22500.0,8900.0,5760.0,,1840.0,2360.0,1210.0,13800.0,27200.0,23200.0,9770.0,3820.0,88900.0,9060.0,6420.0,13300.0,575.0,24100.0,1650.0,12200.0,1620.0,59600.0,53100.0,25000.0,18100.0,500.0,,1080.0,,8350.0,1720.0,1360.0,3700.0,,,3140.0,,1010.0,580.0,5190.0,835.0,1000.0,5720.0,4310.0,4220.0,10600.0,17700.0,3990.0,,746.0,3570.0,531.0,49800.0,14200.0,1540.0,6190.0,10700.0,,1540.0,3280.0,4070.0,1330.0,8080.0,1740.0,820.0 54 | 2012-01-01,40200.0,40400.0,689.0,13500.0,4260.0,3350.0,5540.0,14800.0,,48300.0,67500.0,,7390.0,4410.0,15200.0,862.0,44800.0,678.0,7200.0,23300.0,251.0,751.0,85500.0,41100.0,2580.0,12100.0,22100.0,2460.0,7380.0,6720.0,4860.0,52700.0,418.0,479.0,3150.0,83300.0,1360.0,15200.0,1220.0,6260.0,7750.0,9430.0,,6490.0,3540.0,,28900.0,19700.0,43900.0,1570.0,57600.0,7180.0,5880.0,5310.0,5660.0,17100.0,3260.0,504.0,29000.0,472.0,47400.0,4400.0,3150.0,47600.0,40900.0,10800.0,41100.0,7580.0,3530.0,1650.0,,509.0,495.0,22400.0,22500.0,3340.0,,576.0,3580.0,36700.0,2330.0,13200.0,776.0,12800.0,3720.0,48400.0,32500.0,,1480.0,6690.0,7300.0,44400.0,34900.0,5460.0,4900.0,46700.0,1170.0,1180.0,945.0,1740.0,796.0,13700.0,,24500.0,53500.0,,12100.0,1410.0,9760.0,7200.0,150000.0,2920.0,414.0,1160.0,14300.0,106000.0,14000.0,13300.0,2900.0,,2050.0,6520.0,,445.0,3510.0,4630.0,696.0,1410.0,4400.0,,1280.0,21200.0,9110.0,7490.0,267.0,9820.0,10400.0,593.0,5760.0,,405.0,2730.0,1750.0,49100.0,102000.0,686.0,39600.0,23000.0,9980.0,6430.0,,2150.0,2590.0,1250.0,13000.0,27800.0,20600.0,10400.0,3680.0,92600.0,8450.0,5660.0,14100.0,630.0,25900.0,1870.0,12800.0,1690.0,57100.0,54600.0,22500.0,17200.0,634.0,,1020.0,,9380.0,957.0,1400.0,3780.0,,,3050.0,,994.0,589.0,5480.0,953.0,1110.0,6800.0,4200.0,4360.0,10700.0,17400.0,4040.0,,836.0,3860.0,653.0,51500.0,15100.0,1720.0,6350.0,12700.0,,1760.0,3160.0,4260.0,1340.0,7590.0,1770.0,909.0 55 | 2013-01-01,41000.0,43000.0,665.0,13300.0,4460.0,3500.0,5780.0,15000.0,,50500.0,67500.0,,7810.0,4660.0,15000.0,958.0,46900.0,716.0,7500.0,24700.0,267.0,805.0,85700.0,38600.0,2870.0,11900.0,22300.0,2360.0,7410.0,7720.0,4890.0,52300.0,445.0,335.0,3170.0,84700.0,1540.0,15700.0,1330.0,6990.0,7870.0,10100.0,,6850.0,3680.0,,27900.0,19900.0,46300.0,1670.0,59800.0,7180.0,5880.0,5360.0,6000.0,18900.0,3310.0,544.0,29900.0,505.0,49300.0,4380.0,3050.0,52800.0,42600.0,10300.0,41800.0,7890.0,3600.0,1880.0,,482.0,531.0,20600.0,22000.0,3480.0,,555.0,3740.0,38400.0,2280.0,13600.0,819.0,13500.0,3640.0,50500.0,36100.0,,1490.0,6960.0,6380.0,47500.0,35500.0,5290.0,5200.0,38600.0,1240.0,1280.0,1010.0,1650.0,842.0,14300.0,,26000.0,52200.0,,13600.0,1650.0,9930.0,7330.0,,3280.0,453.0,1040.0,15700.0,111000.0,15400.0,10600.0,3090.0,,2240.0,7110.0,,463.0,3630.0,5110.0,726.0,1100.0,4420.0,,1300.0,22800.0,9480.0,7840.0,237.0,10300.0,10500.0,598.0,5610.0,,431.0,2970.0,1780.0,50800.0,103000.0,692.0,42400.0,21500.0,11000.0,6660.0,,2110.0,2770.0,1280.0,13800.0,28700.0,21500.0,10900.0,4250.0,93700.0,9490.0,6350.0,14500.0,639.0,25800.0,1890.0,15700.0,1750.0,60400.0,56000.0,23300.0,18100.0,809.0,,1050.0,,9830.0,1040.0,1610.0,3830.0,,,2830.0,,1010.0,636.0,5780.0,1040.0,1240.0,7830.0,4320.0,4110.0,11000.0,18200.0,3880.0,,927.0,4030.0,657.0,53000.0,16900.0,1880.0,6570.0,12200.0,,1910.0,3170.0,4180.0,1470.0,6890.0,1840.0,953.0 56 | 2014-01-01,,42500.0,666.0,14000.0,4620.0,3650.0,5940.0,12900.0,,51100.0,61900.0,,7880.0,4800.0,15200.0,1100.0,47500.0,720.0,7710.0,25200.0,295.0,825.0,,40800.0,3150.0,11600.0,22200.0,2380.0,7760.0,8040.0,,50300.0,475.0,379.0,3100.0,,1650.0,14500.0,1430.0,7590.0,7720.0,10000.0,,,3720.0,,27200.0,19600.0,47600.0,1780.0,60600.0,7430.0,6080.0,5360.0,6290.0,19700.0,3440.0,590.0,30300.0,568.0,49500.0,4540.0,,,42700.0,10100.0,45600.0,8300.0,3670.0,1460.0,,423.0,550.0,18400.0,21700.0,3700.0,,586.0,4020.0,40200.0,2350.0,13500.0,833.0,13900.0,3510.0,53300.0,37000.0,,1630.0,6430.0,5290.0,52100.0,35000.0,,5420.0,36200.0,1340.0,1270.0,1080.0,1600.0,861.0,15200.0,,28000.0,,,12300.0,1710.0,10100.0,7440.0,,3630.0,461.0,995.0,16400.0,,16000.0,6580.0,3140.0,,2230.0,7370.0,,449.0,,5370.0,766.0,1200.0,4170.0,,1270.0,,10000.0,8620.0,253.0,10400.0,10800.0,619.0,5720.0,,441.0,3180.0,1910.0,51600.0,97400.0,698.0,,20800.0,11800.0,6590.0,,,2840.0,1330.0,14400.0,,22100.0,11900.0,4480.0,93400.0,10000.0,6150.0,12700.0,652.0,25400.0,2020.0,15400.0,1900.0,58900.0,56300.0,24000.0,18400.0,788.0,,1070.0,,,1110.0,1690.0,3950.0,,,2680.0,,1050.0,646.0,5560.0,1100.0,1280.0,9030.0,,4110.0,10500.0,,,,998.0,3080.0,677.0,54600.0,16800.0,2040.0,6660.0,16500.0,,2050.0,,4170.0,,6480.0,1800.0,936.0 57 | -------------------------------------------------------------------------------- /input_output_control_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pm8k/dataspyre_tutorial/8ae564967337be2f293cbf30f35cc8a5f9cfe852/input_output_control_large.png -------------------------------------------------------------------------------- /public/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pm8k/dataspyre_tutorial/8ae564967337be2f293cbf30f35cc8a5f9cfe852/public/.DS_Store -------------------------------------------------------------------------------- /pygal_example_1.py: -------------------------------------------------------------------------------- 1 | %matplotlib inline 2 | from IPython.display import SVG, HTML 3 | html_pygal = """ 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | {pygal_render} 14 |
15 | 16 | 17 | """ 18 | 19 | import pygal 20 | line_chart = pygal.Line() 21 | line_chart.title = 'Browser usage evolution (in %)' 22 | line_chart.x_labels = map(str, range(2002, 2013)) 23 | line_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1]) 24 | line_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3]) 25 | line_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1]) 26 | line_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5]) 27 | HTML(html_pygal.format(pygal_render=line_chart.render())) -------------------------------------------------------------------------------- /pygal_example_2.py: -------------------------------------------------------------------------------- 1 | %matplotlib inline 2 | from IPython.display import SVG, HTML 3 | html_pygal = """ 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | {pygal_render} 14 |
15 | 16 | 17 | """ 18 | 19 | import pygal 20 | stackedline_chart = pygal.StackedLine(fill=True) 21 | stackedline_chart.title = 'Browser usage evolution (in %)' 22 | stackedline_chart.x_labels = map(str, range(2002, 2013)) 23 | stackedline_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1]) 24 | stackedline_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3]) 25 | stackedline_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1]) 26 | stackedline_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5]) 27 | HTML(html_pygal.format(pygal_render=stackedline_chart.render())) -------------------------------------------------------------------------------- /pygal_example_3.py: -------------------------------------------------------------------------------- 1 | %matplotlib inline 2 | from IPython.display import SVG, HTML 3 | html_pygal = """ 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | {pygal_render} 14 |
15 | 16 | 17 | """ 18 | import pygal 19 | from math import cos 20 | xy_chart = pygal.XY() 21 | xy_chart.title = 'XY Cosinus' 22 | xy_chart.add('x = cos(y)', [(cos(x / 10.), x / 10.) for x in range(-50, 50, 5)]) 23 | xy_chart.add('y = cos(x)', [(x / 10., cos(x / 10.)) for x in range(-50, 50, 5)]) 24 | xy_chart.add('x = 1', [(1, -5), (1, 5)]) 25 | xy_chart.add('x = -1', [(-1, -5), (-1, 5)]) 26 | xy_chart.add('y = 1', [(-5, 1), (5, 1)]) 27 | xy_chart.add('y = -1', [(-5, -1), (5, -1)]) 28 | HTML(html_pygal.format(pygal_render=xy_chart.render())) -------------------------------------------------------------------------------- /resized_chemistry-cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pm8k/dataspyre_tutorial/8ae564967337be2f293cbf30f35cc8a5f9cfe852/resized_chemistry-cat.jpg -------------------------------------------------------------------------------- /sample_script_10.py: -------------------------------------------------------------------------------- 1 | from spyre import server 2 | 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | import pandas as pd 6 | import pygal 7 | import cherrypy 8 | import os 9 | 10 | class SimpleSineApp(server.App): 11 | title = "Simple Sine App" 12 | inputs = [{ "type":"text", 13 | "key":"freq", 14 | "value":5, 15 | "label":"frequency", 16 | "action_id":"sine_wave_plot"}] 17 | tabs=["Plot","Data"] 18 | outputs = [{"type" : "html", 19 | "id" : "initiate_directs", 20 | "on_page_load" : True }, 21 | {"type":"html", 22 | "id":"wave_plot", 23 | "tab":"Plot", 24 | "control_id":"sine_wave_plot"}, 25 | {"type":"table", 26 | "id":"wave_data", 27 | "tab":"Data", 28 | "control_id":"sine_wave_plot"}] 29 | 30 | controls = [{"type":"HIDDEN", 31 | "id":"sine_wave_plot"}] 32 | 33 | def initiate_directs(self,params): 34 | root=self.getRoot() 35 | current_dir=os.path.dirname(os.path.abspath("__file__")) 36 | config_public={ 37 | '/':{ 38 | 'tools.staticdir.root' : current_dir, 39 | }, 40 | '/static': { 41 | 'tools.staticdir.on': True, 42 | 'tools.staticdir.dir': 'public', 43 | 'tools.staticdir.content_types':{'.min.js':"text/javascript",'svg':"image/svg+xml"} 44 | } 45 | } 46 | cherrypy.tree.mount(root, "/", config=config_public) 47 | def wave_plot(self, params): 48 | #self.initiate_directs(params) 49 | f = float(params['freq']) 50 | df=self.getData(params) 51 | line_chart = pygal.Line(height=400,width=600,show_minor_x_labels=False,x_label_rotation=45) 52 | line_chart.title = 'Sine Wave in Pygal' 53 | line_chart.x_labels = ["{0:.2f}".format(a) for a in df.x.tolist()] 54 | line_chart.add('Sin(y)',df.y.tolist()) 55 | line_chart.add('Sin(2y)',df.y2.tolist()) 56 | 57 | line_chart.x_labels_major=line_chart.x_labels[::30] 58 | line_chart.render_to_file('public/pygalspyre.svg') 59 | html="""
""" 60 | 61 | return html 62 | 63 | def getData(self,params): 64 | f=float(params['freq']) 65 | x = pd.Series(np.arange(0,2*np.pi,np.pi/150)) 66 | y = pd.Series(np.sin(f*x)) 67 | y2= pd.Series(np.sin(f*x*2)) 68 | df=pd.concat([x,y,y2],axis=1) 69 | df.columns=['x','y','y2'] 70 | return df 71 | 72 | if __name__ == '__main__': 73 | app = SimpleSineApp() 74 | app.launch() -------------------------------------------------------------------------------- /spyre_script_1.py: -------------------------------------------------------------------------------- 1 | ##################### 2 | from spyre import server 3 | 4 | class SimpleApp(server.App): 5 | title = "Simple App" 6 | inputs = [{ "type":"text", 7 | "key":"words", 8 | "label": "write here", 9 | "value":"hello world"}] 10 | outputs = [{"type":"html", 11 | "id":"some_html", 12 | "control_id":"button1"}] 13 | controls = [{"type":"button", 14 | "label":"press to update", 15 | "id":"button1"}] 16 | def getHTML(self, params): 17 | words = params['words'] 18 | return "Here are some words: %s"%words 19 | 20 | app = SimpleApp() 21 | app.launch() -------------------------------------------------------------------------------- /spyre_script_10.py: -------------------------------------------------------------------------------- 1 | from spyre import server 2 | 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | import pandas as pd 6 | import pygal 7 | import cherrypy 8 | import os 9 | 10 | class SimpleSineApp(server.App): 11 | title = "Simple Sine App" 12 | inputs = [{ "type":"text", 13 | "key":"freq", 14 | "value":5, 15 | "label":"frequency", 16 | "action_id":"sine_wave_plot"}] 17 | tabs=["Plot","Data"] 18 | outputs = [{"type" : "html", 19 | "id" : "initiate_directs", 20 | "on_page_load" : True }, 21 | {"type":"html", 22 | "id":"wave_plot", 23 | "tab":"Plot", 24 | "control_id":"sine_wave_plot"}, 25 | {"type":"table", 26 | "id":"wave_data", 27 | "tab":"Data", 28 | "control_id":"sine_wave_plot"}] 29 | 30 | controls = [{"type":"HIDDEN", 31 | "id":"sine_wave_plot"}] 32 | 33 | def initiate_directs(self,params): 34 | root=self.getRoot() 35 | current_dir=os.path.dirname(os.path.abspath("__file__")) 36 | config_public={ 37 | '/':{ 38 | 'tools.staticdir.root' : current_dir, 39 | }, 40 | '/static': { 41 | 'tools.staticdir.on': True, 42 | 'tools.staticdir.dir': 'public', 43 | 'tools.staticdir.content_types':{'.min.js':"text/javascript",'svg':"image/svg+xml"} 44 | } 45 | } 46 | cherrypy.tree.mount(root, "/", config=config_public) 47 | def wave_plot(self, params): 48 | #self.initiate_directs(params) 49 | f = float(params['freq']) 50 | df=self.getData(params) 51 | line_chart = pygal.Line(height=400,width=600,show_minor_x_labels=False,x_label_rotation=45) 52 | line_chart.title = 'Sine Wave in Pygal' 53 | line_chart.x_labels = ["{0:.2f}".format(a) for a in df.x.tolist()] 54 | line_chart.add('Sin(y)',df.y.tolist()) 55 | line_chart.add('Sin(2y)',df.y2.tolist()) 56 | 57 | line_chart.x_labels_major=line_chart.x_labels[::30] 58 | line_chart.render_to_file('public/pygalspyre'+str(f)+'.svg') 59 | html="""
""" 60 | 61 | return html 62 | 63 | def getData(self,params): 64 | f=float(params['freq']) 65 | x = pd.Series(np.arange(0,2*np.pi,np.pi/150)) 66 | y = pd.Series(np.sin(f*x)) 67 | y2= pd.Series(np.sin(f*x*2)) 68 | df=pd.concat([x,y,y2],axis=1) 69 | df.columns=['x','y','y2'] 70 | return df 71 | 72 | if __name__ == '__main__': 73 | app = SimpleSineApp() 74 | app.launch() -------------------------------------------------------------------------------- /spyre_script_2.py: -------------------------------------------------------------------------------- 1 | from spyre import server 2 | 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | 6 | class SimpleSineApp(server.App): 7 | title = "Simple Sine App" 8 | inputs = [{ "type":"slider", 9 | "key":"freq", 10 | "value":5, "max":10, 11 | "action_id":"sine_wave_plot"}] 12 | 13 | outputs = [{"type":"plot", 14 | "id":"sine_wave_plot"}] 15 | 16 | def getPlot(self, params): 17 | f = float(params['freq']) 18 | x = np.arange(0,2*np.pi,np.pi/150) 19 | y = np.sin(f*x) 20 | fig = plt.figure() 21 | splt1 = fig.add_subplot(1,1,1) 22 | splt1.plot(x,y) 23 | return fig 24 | 25 | if __name__ == '__main__': 26 | app = SimpleSineApp() 27 | app.launch() -------------------------------------------------------------------------------- /spyre_script_3.py: -------------------------------------------------------------------------------- 1 | #Display this Code 2 | ##################### 3 | from spyre import server 4 | 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | 8 | class SimpleSineApp(server.App): 9 | title = "Simple Sine App" 10 | inputs = [{ "type":"text", 11 | "key":"freq", 12 | "value":5, 13 | "label":"frequency", 14 | "action_id":"sine_wave_plot"}] 15 | outputs = [{"type":"plot", 16 | "id":"sine_wave_plot"}] 17 | controls = [{"type":"HIDDEN", 18 | "id":"sine_wave_plot"}] 19 | def getPlot(self, params): 20 | f = float(params['freq']) 21 | x = np.arange(0,2*np.pi,np.pi/150) 22 | y = np.sin(f*x) 23 | fig = plt.figure() 24 | splt1 = fig.add_subplot(1,1,1) 25 | splt1.plot(x,y) 26 | return fig 27 | 28 | if __name__ == '__main__': 29 | app = SimpleSineApp() 30 | app.launch() -------------------------------------------------------------------------------- /spyre_script_4.py: -------------------------------------------------------------------------------- 1 | ##################### 2 | #Display this Code 3 | ##################### 4 | from spyre import server 5 | 6 | import matplotlib.pyplot as plt 7 | import numpy as np 8 | import pandas as pd 9 | 10 | class SimpleSineApp(server.App): 11 | title = "Simple Sine App" 12 | inputs = [{ "type":"text", 13 | "key":"freq", 14 | "value":5, 15 | "label":"frequency", 16 | "action_id":"sine_wave_plot"}] 17 | tabs=["Plot","Data"] 18 | outputs = [{"type":"plot", 19 | "id":"wave_plot", 20 | "tab":"Plot", 21 | "control_id":"sine_wave_plot"}, 22 | {"type":"table", 23 | "id":"wave_data", 24 | "tab":"Data", 25 | "control_id":"sine_wave_plot"}] 26 | controls = [{"type":"HIDDEN", 27 | "id":"sine_wave_plot"}] 28 | def getPlot(self, params): 29 | f = float(params['freq']) 30 | df=self.getData(params) 31 | fig = plt.figure() 32 | splt1 = fig.add_subplot(1,1,1) 33 | splt1.plot(df.x,df.y) 34 | return fig 35 | def getData(self,params): 36 | f=float(params['freq']) 37 | x = pd.Series(np.arange(0,2*np.pi,np.pi/150)) 38 | y = pd.Series(np.sin(f*x)) 39 | df=pd.concat([x,y],axis=1) 40 | df.columns=['x','y'] 41 | return df 42 | 43 | if __name__ == '__main__': 44 | app = SimpleSineApp() 45 | app.launch() 46 | ##################### -------------------------------------------------------------------------------- /spyre_script_5.py: -------------------------------------------------------------------------------- 1 | ##################### 2 | #Display this Code 3 | ##################### 4 | from spyre import server 5 | 6 | import matplotlib.pyplot as plt 7 | import numpy as np 8 | import pandas as pd 9 | 10 | class SimpleSineApp(server.App): 11 | title = "Simple Sine App" 12 | inputs = [{ "type":"text", 13 | "key":"freq", 14 | "value":5, 15 | "label":"frequency", 16 | "action_id":"sine_wave_plot"}] 17 | tabs=["Plot1","Plot2","Data"] 18 | outputs = [{"type":"plot", 19 | "id":"wave_plot", 20 | "tab":"Plot1", 21 | "control_id":"sine_wave_plot"}, 22 | {"type":"plot", 23 | "id":"wave_plot2", 24 | "tab":"Plot2", 25 | "control_id":"sine_wave_plot"}, 26 | {"type":"table", 27 | "id":"wave_data", 28 | "tab":"Data", 29 | "control_id":"sine_wave_plot"}] 30 | controls = [{"type":"HIDDEN", 31 | "id":"sine_wave_plot"}] 32 | def wave_plot(self, params): 33 | f = float(params['freq']) 34 | df=self.wave_data(params) 35 | fig = plt.figure() 36 | splt1 = fig.add_subplot(1,1,1) 37 | splt1.plot(df.x,df.y1) 38 | return fig 39 | def wave_plot2(self, params): 40 | f = float(params['freq']) 41 | df=self.wave_data(params) 42 | fig = plt.figure() 43 | splt1 = fig.add_subplot(1,1,1) 44 | splt1.plot(df.x,df.y2) 45 | return fig 46 | def wave_data(self,params): 47 | f=float(params['freq']) 48 | x = pd.Series(np.arange(0,2*np.pi,np.pi/150)) 49 | y1 = pd.Series(np.sin(f*x)) 50 | y2 = pd.Series(np.sin(2*f*x)) 51 | df=pd.concat([x,y1,y2],axis=1) 52 | df.columns=['x','y1','y2'] 53 | return df 54 | 55 | if __name__ == '__main__': 56 | app = SimpleSineApp() 57 | app.launch() 58 | ##################### -------------------------------------------------------------------------------- /spyre_script_6.py: -------------------------------------------------------------------------------- 1 | #########CODE########## 2 | from spyre import server 3 | 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | import pandas as pd 7 | 8 | class SimpleSineApp(server.App): 9 | title = "Simple Sine App" 10 | inputs = [{ "type":"text", 11 | "key":"freq", 12 | "value":5, 13 | "label":"frequency", 14 | "action_id":"sine_wave_plot"}, 15 | { "type":"radiobuttons", 16 | "key":"func_type", 17 | "label":"func_type", 18 | "action_id":"sine_wave_plot", 19 | "options":[ 20 | {"label":"Sine","value":"sin","checked":True}, 21 | {"label":"Cosine","value":"cos"}]}, 22 | { "type":"dropdown", 23 | "key":"datatoplot", 24 | "options":[ 25 | {"label":"x","value":"y1"}, 26 | {"label":"2x","value":"y2"}], 27 | "label":"Data to Plot", 28 | "action_id":"sine_wave_plot"}, 29 | { "type":"slider", 30 | "key":"x_slider", 31 | "value":100, 32 | "min":1, 33 | "max":200, 34 | "label":"x_axis", 35 | "action_id":"sine_wave_plot"}, 36 | { "type":"checkboxgroup", 37 | "key":"checkboxes", 38 | "options":[ 39 | {"label":"show x gridlines","value":"showx","checked":True}, 40 | {"label":"show y gridlines","value":"showy"} 41 | ], 42 | "label":"Plot Options", 43 | "action_id":"sine_wave_plot"}] 44 | tabs=["Plot","Data"] 45 | outputs = [{"type":"plot", 46 | "id":"wave_plot", 47 | "tab":"Plot", 48 | "control_id":"sine_wave_plot"}, 49 | {"type":"table", 50 | "id":"wave_data", 51 | "tab":"Data", 52 | "control_id":"sine_wave_plot"}] 53 | controls = [{"type":"HIDDEN", 54 | "id":"sine_wave_plot"}] 55 | def getPlot(self, params): 56 | f = float(params['freq']) 57 | data = params['datatoplot'] 58 | checkboxlist=params['checkboxes'] 59 | df=self.getData(params) 60 | fig = plt.figure() 61 | splt1 = fig.add_subplot(1,1,1) 62 | splt1.plot(df.x,df[data]) 63 | if 'showx' in checkboxlist: 64 | splt1.xaxis.grid(True) 65 | if 'showy' in checkboxlist: 66 | splt1.yaxis.grid(True) 67 | return fig 68 | def getData(self,params): 69 | f=float(params['freq']) 70 | index=int(params['x_slider']) 71 | functouse=params['func_type'] 72 | funcdict={"sin":np.sin,"cos":np.cos} 73 | func=funcdict[functouse] 74 | x = pd.Series(np.arange(0,2*np.pi,np.pi/150)) 75 | y1 = pd.Series(func(f*x)) 76 | y2 = pd.Series(func(2*f*x)) 77 | df=pd.concat([x,y1,y2],axis=1) 78 | df.columns=['x','y1','y2'] 79 | return df[:index] 80 | 81 | if __name__ == '__main__': 82 | app = SimpleSineApp() 83 | app.launch() 84 | ######################### -------------------------------------------------------------------------------- /spyre_script_7.py: -------------------------------------------------------------------------------- 1 | ##################### 2 | #Display this Code 3 | ##################### 4 | from spyre import server 5 | 6 | import matplotlib.pyplot as plt 7 | import numpy as np 8 | import pandas as pd 9 | 10 | class SimpleSineApp(server.App): 11 | title = "Simple Sine App" 12 | inputs = [{ "type":"slider", 13 | "key":"x_slider", 14 | "value":200, 15 | "min":1, 16 | "max":200, 17 | "label":"x_axis", 18 | "action_id":"sine_wave_plot"},{ "type":"text", 19 | "key":"freq", 20 | "value":5, 21 | "label":"frequency", 22 | "action_id":"sine_wave_data"}] 23 | tabs=["Plot","Data"] 24 | outputs = [{"type":"plot", 25 | "id":"wave_plot", 26 | "tab":"Plot", 27 | "control_id":"sine_wave_data"}, 28 | {"type":"table", 29 | "id":"wave_data", 30 | "tab":"Data", 31 | "control_id":"sine_wave_plot"}] 32 | controls = [{"type":"HIDDEN", 33 | "id":"sine_wave_plot"}, 34 | {"type":"HIDDEN","id":"sine_wave_data"}] 35 | def getPlot(self, params): 36 | f = float(params['freq']) 37 | index=int(params['x_slider']) 38 | df=self.getData(params) 39 | fig = plt.figure() 40 | splt1 = fig.add_subplot(1,1,1) 41 | splt1.plot(df.x,df.y) 42 | return fig 43 | def getData(self,params): 44 | f=float(params['freq']) 45 | index=int(params['x_slider']) 46 | x = pd.Series(np.arange(0,2*np.pi,np.pi/150)) 47 | y = pd.Series(np.sin(f*x)) 48 | df=pd.concat([x,y],axis=1) 49 | df.columns=['x','y'] 50 | return df[:index] 51 | 52 | if __name__ == '__main__': 53 | app = SimpleSineApp() 54 | app.launch() 55 | ##################### -------------------------------------------------------------------------------- /spyre_script_8.py: -------------------------------------------------------------------------------- 1 | ##################### 2 | #Display this Code 3 | ##################### 4 | from spyre import server 5 | 6 | import matplotlib.pyplot as plt 7 | import numpy as np 8 | import pandas as pd 9 | import os 10 | import cherrypy 11 | class SimpleSineApp(server.App): 12 | title = "Simple Sine App" 13 | inputs = [{ "type":"text", 14 | "key":"freq", 15 | "value":5, 16 | "label":"frequency", 17 | "action_id":"sine_wave_plot"}] 18 | outputs = [{"type" : "html", 19 | "id" : "initiate_directs", 20 | "on_page_load" : True }, 21 | {"type":"html", 22 | "id":"wave_plot_and_data", 23 | "control_id":"sine_wave_plot"}] 24 | controls = [{"type":"HIDDEN", 25 | "id":"sine_wave_plot"}] 26 | def initiate_directs(self,params): 27 | root=self.getRoot() 28 | current_dir=os.path.dirname(os.path.abspath("__file__")) 29 | config_public={ 30 | '/':{ 31 | 'tools.staticdir.root' : current_dir, 32 | }, 33 | '/static': { 34 | 'tools.staticdir.on': True, 35 | 'tools.staticdir.dir': 'public', 36 | 'tools.staticdir.content_types':{'.min.js':"text/javascript",'svg':"image/svg+xml"} 37 | } 38 | } 39 | cherrypy.tree.mount(root, "/", config=config_public) 40 | def wave_plot_and_data(self, params): 41 | f = float(params['freq']) 42 | df=self.getplotData(params) 43 | fig = plt.figure() 44 | splt1 = fig.add_subplot(1,1,1) 45 | splt1.plot(df.x,df.y) 46 | fig.savefig('public/ourfig'+str(f)+'.png') 47 | dfhtml=df[:20].to_html(index=False) 48 | html='
' 49 | finalhtml=html+"
"+dfhtml 50 | return finalhtml 51 | def getplotData(self,params): 52 | f=float(params['freq']) 53 | x = pd.Series(np.arange(0,2*np.pi,np.pi/150)) 54 | y = pd.Series(np.sin(f*x)) 55 | df=pd.concat([x,y],axis=1) 56 | df.columns=['x','y'] 57 | return df 58 | 59 | if __name__ == '__main__': 60 | app = SimpleSineApp() 61 | app.launch() 62 | ##################### -------------------------------------------------------------------------------- /spyre_script_9.py: -------------------------------------------------------------------------------- 1 | from spyre import server 2 | 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | import pandas as pd 6 | 7 | from bokeh.charts import Donut 8 | from bokeh.resources import INLINE 9 | from bokeh.resources import CDN 10 | from bokeh.embed import components 11 | from bokeh.plotting import figure, show, output_file, vplot 12 | 13 | class SimpleSineApp(server.App): 14 | title = "Simple Sine App" 15 | inputs = [{ "type":"text", 16 | "key":"freq", 17 | "value":5, 18 | "label":"frequency", 19 | "action_id":"sine_wave_plot"}] 20 | tabs=["Plot","Data"] 21 | outputs = [{"type":"html", 22 | "id":"wave_plot", 23 | "tab":"Plot", 24 | "control_id":"sine_wave_plot"}, 25 | {"type":"table", 26 | "id":"wave_data", 27 | "tab":"Data", 28 | "control_id":"sine_wave_plot"}] 29 | controls = [{"type":"HIDDEN", 30 | "id":"sine_wave_plot"}] 31 | def getHTML(self, params): 32 | f = float(params['freq']) 33 | df=self.getData(params) 34 | 35 | TOOLS = "pan,wheel_zoom,box_zoom,reset,save,box_select" 36 | 37 | p2 = figure(title="Another Sine Example", tools=TOOLS) 38 | 39 | p2.circle(df.x, df.y, legend="sin(x)") 40 | p2.line(df.x, df.y, legend="sin(x)") 41 | 42 | 43 | script, div = components(p2, CDN) 44 | html = "%s\n%s"%(script, div) 45 | return html 46 | 47 | return fig 48 | def getData(self,params): 49 | f=float(params['freq']) 50 | x = pd.Series(np.arange(0,2*np.pi,np.pi/150)) 51 | y = pd.Series(np.sin(f*x)) 52 | df=pd.concat([x,y],axis=1) 53 | df.columns=['x','y'] 54 | return df 55 | def getCustomJS(self): 56 | return INLINE.js_raw[0] 57 | 58 | def getCustomCSS(self): 59 | return INLINE.css_raw[0] 60 | if __name__ == '__main__': 61 | app = SimpleSineApp() 62 | app.launch() -------------------------------------------------------------------------------- /thats-cool-i8t8sz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pm8k/dataspyre_tutorial/8ae564967337be2f293cbf30f35cc8a5f9cfe852/thats-cool-i8t8sz.jpg --------------------------------------------------------------------------------