├── README.md
├── notebooks
├── README.md
├── EX-1.1-Something-You-Should-Not-Do.ipynb
├── iris.csv
├── iris_with_names.csv
├── EX-4-Pivot-Using-SQL-And-Pandas.ipynb
├── EX-1.0-Getting-to-Know-the-Clickhouse-driver-Client.ipynb
├── EX-3-Sql-Magic-Functions.ipynb
├── EX-5-Airline-OnTime-Data.ipynb
└── EX-2-ClickHouse-SQL-Alchemy.ipynb
├── LICENSE
└── .gitignore
/README.md:
--------------------------------------------------------------------------------
1 | # ClickHouse Python Samples
2 |
3 | This project contains Python samples for ClickHouse. For now the samples
4 | consist of Jupyter Notebook files in the notebooks directory.
5 |
--------------------------------------------------------------------------------
/notebooks/README.md:
--------------------------------------------------------------------------------
1 | # Juypter Notebooks for ClickHouse
2 |
3 | This directory contains sample notebooks showing how to connect Python
4 | to ClickHouse.
5 |
6 | Notebook code has been tested on Ubuntu using Anaconda and Python 3.7.
7 | They should work from Python 3.5 onwards.
8 |
9 | To get started you'll need to add the following packages using conda:
10 | ```
11 | conda install -c conda-forge clickhouse-driver
12 | conda install -c conda-forge clickhouse-sqlalchemy
13 | ```
14 |
15 | Examples use sample data from the iris dataset.
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Altinity
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 | .pytest_cache/
49 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | local_settings.py
57 | db.sqlite3
58 |
59 | # Flask stuff:
60 | instance/
61 | .webassets-cache
62 |
63 | # Scrapy stuff:
64 | .scrapy
65 |
66 | # Sphinx documentation
67 | docs/_build/
68 |
69 | # PyBuilder
70 | target/
71 |
72 | # Jupyter Notebook
73 | .ipynb_checkpoints
74 |
75 | # pyenv
76 | .python-version
77 |
78 | # celery beat schedule file
79 | celerybeat-schedule
80 |
81 | # SageMath parsed files
82 | *.sage.py
83 |
84 | # Environments
85 | .env
86 | .venv
87 | env/
88 | venv/
89 | ENV/
90 | env.bak/
91 | venv.bak/
92 |
93 | # Spyder project settings
94 | .spyderproject
95 | .spyproject
96 |
97 | # Rope project settings
98 | .ropeproject
99 |
100 | # mkdocs documentation
101 | /site
102 |
103 | # mypy
104 | .mypy_cache/
105 |
--------------------------------------------------------------------------------
/notebooks/EX-1.1-Something-You-Should-Not-Do.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Something You Should Not Do\n",
8 | "\n",
9 | "This notebook has samples that were included in the [Altinity blog article that introduces the clickhouse-driver client library](https://www.altinity.com/blog/clickhouse-and-python-getting-to-know-the-clickhouse-driver-client).\n",
10 | "\n",
11 | "_WARNING_: The final example hangs. It must be cancelled manually. "
12 | ]
13 | },
14 | {
15 | "cell_type": "markdown",
16 | "metadata": {},
17 | "source": [
18 | "Load the clickhouse driver and connect to a local server. "
19 | ]
20 | },
21 | {
22 | "cell_type": "code",
23 | "execution_count": null,
24 | "metadata": {},
25 | "outputs": [],
26 | "source": [
27 | "from clickhouse_driver import Client\n",
28 | "client = Client('localhost')"
29 | ]
30 | },
31 | {
32 | "cell_type": "markdown",
33 | "metadata": {},
34 | "source": [
35 | "Create the iris table, dropping any previously existing table of the same name. "
36 | ]
37 | },
38 | {
39 | "cell_type": "code",
40 | "execution_count": null,
41 | "metadata": {},
42 | "outputs": [],
43 | "source": [
44 | "client.execute('DROP TABLE IF EXISTS iris')\n",
45 | "client.execute('CREATE TABLE iris ('\n",
46 | " 'sepal_length Float64, sepal_width Float64, '\n",
47 | " 'petal_length Float64, petal_width Float64, '\n",
48 | " 'species String) ENGINE = MergeTree '\n",
49 | " ' PARTITION BY species ORDER BY (species)')"
50 | ]
51 | },
52 | {
53 | "cell_type": "markdown",
54 | "metadata": {},
55 | "source": [
56 | "If you try to insert values using a single string INSERT command that works with clickhouse-client the results will be disappointing. This command will hang. Once you see it hang, press the STOP button in your Jupyter environment. "
57 | ]
58 | },
59 | {
60 | "cell_type": "code",
61 | "execution_count": null,
62 | "metadata": {},
63 | "outputs": [],
64 | "source": [
65 | "# Don’t do this.\n",
66 | "try:\n",
67 | " client.execute(\n",
68 | " \"INSERT INTO iris (sepal_length, sepal_width, petal_length, petal_width, species) \" \n",
69 | " \"VALUES (5.1, 3.7, 1.5, 0.4, 'Iris-setosa'), (4.6, 3.6, 1.0, 0.2, 'Iris-setosa')\"\n",
70 | " )\n",
71 | "except:\n",
72 | " print(\"The command failed as expected\")"
73 | ]
74 | },
75 | {
76 | "cell_type": "markdown",
77 | "metadata": {},
78 | "source": [
79 | "You have to put insert data in a separate array. Python cannot translate this the way clickhouse-client does. (It creates the array transparently.)"
80 | ]
81 | },
82 | {
83 | "cell_type": "code",
84 | "execution_count": null,
85 | "metadata": {},
86 | "outputs": [],
87 | "source": []
88 | }
89 | ],
90 | "metadata": {
91 | "kernelspec": {
92 | "display_name": "Python 3",
93 | "language": "python",
94 | "name": "python3"
95 | },
96 | "language_info": {
97 | "codemirror_mode": {
98 | "name": "ipython",
99 | "version": 3
100 | },
101 | "file_extension": ".py",
102 | "mimetype": "text/x-python",
103 | "name": "python",
104 | "nbconvert_exporter": "python",
105 | "pygments_lexer": "ipython3",
106 | "version": "3.7.1"
107 | }
108 | },
109 | "nbformat": 4,
110 | "nbformat_minor": 2
111 | }
112 |
--------------------------------------------------------------------------------
/notebooks/iris.csv:
--------------------------------------------------------------------------------
1 | 5.1,3.5,1.4,0.2,Iris-setosa
2 | 4.9,3.0,1.4,0.2,Iris-setosa
3 | 4.7,3.2,1.3,0.2,Iris-setosa
4 | 4.6,3.1,1.5,0.2,Iris-setosa
5 | 5.0,3.6,1.4,0.2,Iris-setosa
6 | 5.4,3.9,1.7,0.4,Iris-setosa
7 | 4.6,3.4,1.4,0.3,Iris-setosa
8 | 5.0,3.4,1.5,0.2,Iris-setosa
9 | 4.4,2.9,1.4,0.2,Iris-setosa
10 | 4.9,3.1,1.5,0.1,Iris-setosa
11 | 5.4,3.7,1.5,0.2,Iris-setosa
12 | 4.8,3.4,1.6,0.2,Iris-setosa
13 | 4.8,3.0,1.4,0.1,Iris-setosa
14 | 4.3,3.0,1.1,0.1,Iris-setosa
15 | 5.8,4.0,1.2,0.2,Iris-setosa
16 | 5.7,4.4,1.5,0.4,Iris-setosa
17 | 5.4,3.9,1.3,0.4,Iris-setosa
18 | 5.1,3.5,1.4,0.3,Iris-setosa
19 | 5.7,3.8,1.7,0.3,Iris-setosa
20 | 5.1,3.8,1.5,0.3,Iris-setosa
21 | 5.4,3.4,1.7,0.2,Iris-setosa
22 | 5.1,3.7,1.5,0.4,Iris-setosa
23 | 4.6,3.6,1.0,0.2,Iris-setosa
24 | 5.1,3.3,1.7,0.5,Iris-setosa
25 | 4.8,3.4,1.9,0.2,Iris-setosa
26 | 5.0,3.0,1.6,0.2,Iris-setosa
27 | 5.0,3.4,1.6,0.4,Iris-setosa
28 | 5.2,3.5,1.5,0.2,Iris-setosa
29 | 5.2,3.4,1.4,0.2,Iris-setosa
30 | 4.7,3.2,1.6,0.2,Iris-setosa
31 | 4.8,3.1,1.6,0.2,Iris-setosa
32 | 5.4,3.4,1.5,0.4,Iris-setosa
33 | 5.2,4.1,1.5,0.1,Iris-setosa
34 | 5.5,4.2,1.4,0.2,Iris-setosa
35 | 4.9,3.1,1.5,0.2,Iris-setosa
36 | 5.0,3.2,1.2,0.2,Iris-setosa
37 | 5.5,3.5,1.3,0.2,Iris-setosa
38 | 4.9,3.6,1.4,0.1,Iris-setosa
39 | 4.4,3.0,1.3,0.2,Iris-setosa
40 | 5.1,3.4,1.5,0.2,Iris-setosa
41 | 5.0,3.5,1.3,0.3,Iris-setosa
42 | 4.5,2.3,1.3,0.3,Iris-setosa
43 | 4.4,3.2,1.3,0.2,Iris-setosa
44 | 5.0,3.5,1.6,0.6,Iris-setosa
45 | 5.1,3.8,1.9,0.4,Iris-setosa
46 | 4.8,3.0,1.4,0.3,Iris-setosa
47 | 5.1,3.8,1.6,0.2,Iris-setosa
48 | 4.6,3.2,1.4,0.2,Iris-setosa
49 | 5.3,3.7,1.5,0.2,Iris-setosa
50 | 5.0,3.3,1.4,0.2,Iris-setosa
51 | 7.0,3.2,4.7,1.4,Iris-versicolor
52 | 6.4,3.2,4.5,1.5,Iris-versicolor
53 | 6.9,3.1,4.9,1.5,Iris-versicolor
54 | 5.5,2.3,4.0,1.3,Iris-versicolor
55 | 6.5,2.8,4.6,1.5,Iris-versicolor
56 | 5.7,2.8,4.5,1.3,Iris-versicolor
57 | 6.3,3.3,4.7,1.6,Iris-versicolor
58 | 4.9,2.4,3.3,1.0,Iris-versicolor
59 | 6.6,2.9,4.6,1.3,Iris-versicolor
60 | 5.2,2.7,3.9,1.4,Iris-versicolor
61 | 5.0,2.0,3.5,1.0,Iris-versicolor
62 | 5.9,3.0,4.2,1.5,Iris-versicolor
63 | 6.0,2.2,4.0,1.0,Iris-versicolor
64 | 6.1,2.9,4.7,1.4,Iris-versicolor
65 | 5.6,2.9,3.6,1.3,Iris-versicolor
66 | 6.7,3.1,4.4,1.4,Iris-versicolor
67 | 5.6,3.0,4.5,1.5,Iris-versicolor
68 | 5.8,2.7,4.1,1.0,Iris-versicolor
69 | 6.2,2.2,4.5,1.5,Iris-versicolor
70 | 5.6,2.5,3.9,1.1,Iris-versicolor
71 | 5.9,3.2,4.8,1.8,Iris-versicolor
72 | 6.1,2.8,4.0,1.3,Iris-versicolor
73 | 6.3,2.5,4.9,1.5,Iris-versicolor
74 | 6.1,2.8,4.7,1.2,Iris-versicolor
75 | 6.4,2.9,4.3,1.3,Iris-versicolor
76 | 6.6,3.0,4.4,1.4,Iris-versicolor
77 | 6.8,2.8,4.8,1.4,Iris-versicolor
78 | 6.7,3.0,5.0,1.7,Iris-versicolor
79 | 6.0,2.9,4.5,1.5,Iris-versicolor
80 | 5.7,2.6,3.5,1.0,Iris-versicolor
81 | 5.5,2.4,3.8,1.1,Iris-versicolor
82 | 5.5,2.4,3.7,1.0,Iris-versicolor
83 | 5.8,2.7,3.9,1.2,Iris-versicolor
84 | 6.0,2.7,5.1,1.6,Iris-versicolor
85 | 5.4,3.0,4.5,1.5,Iris-versicolor
86 | 6.0,3.4,4.5,1.6,Iris-versicolor
87 | 6.7,3.1,4.7,1.5,Iris-versicolor
88 | 6.3,2.3,4.4,1.3,Iris-versicolor
89 | 5.6,3.0,4.1,1.3,Iris-versicolor
90 | 5.5,2.5,4.0,1.3,Iris-versicolor
91 | 5.5,2.6,4.4,1.2,Iris-versicolor
92 | 6.1,3.0,4.6,1.4,Iris-versicolor
93 | 5.8,2.6,4.0,1.2,Iris-versicolor
94 | 5.0,2.3,3.3,1.0,Iris-versicolor
95 | 5.6,2.7,4.2,1.3,Iris-versicolor
96 | 5.7,3.0,4.2,1.2,Iris-versicolor
97 | 5.7,2.9,4.2,1.3,Iris-versicolor
98 | 6.2,2.9,4.3,1.3,Iris-versicolor
99 | 5.1,2.5,3.0,1.1,Iris-versicolor
100 | 5.7,2.8,4.1,1.3,Iris-versicolor
101 | 6.3,3.3,6.0,2.5,Iris-virginica
102 | 5.8,2.7,5.1,1.9,Iris-virginica
103 | 7.1,3.0,5.9,2.1,Iris-virginica
104 | 6.3,2.9,5.6,1.8,Iris-virginica
105 | 6.5,3.0,5.8,2.2,Iris-virginica
106 | 7.6,3.0,6.6,2.1,Iris-virginica
107 | 4.9,2.5,4.5,1.7,Iris-virginica
108 | 7.3,2.9,6.3,1.8,Iris-virginica
109 | 6.7,2.5,5.8,1.8,Iris-virginica
110 | 7.2,3.6,6.1,2.5,Iris-virginica
111 | 6.5,3.2,5.1,2.0,Iris-virginica
112 | 6.4,2.7,5.3,1.9,Iris-virginica
113 | 6.8,3.0,5.5,2.1,Iris-virginica
114 | 5.7,2.5,5.0,2.0,Iris-virginica
115 | 5.8,2.8,5.1,2.4,Iris-virginica
116 | 6.4,3.2,5.3,2.3,Iris-virginica
117 | 6.5,3.0,5.5,1.8,Iris-virginica
118 | 7.7,3.8,6.7,2.2,Iris-virginica
119 | 7.7,2.6,6.9,2.3,Iris-virginica
120 | 6.0,2.2,5.0,1.5,Iris-virginica
121 | 6.9,3.2,5.7,2.3,Iris-virginica
122 | 5.6,2.8,4.9,2.0,Iris-virginica
123 | 7.7,2.8,6.7,2.0,Iris-virginica
124 | 6.3,2.7,4.9,1.8,Iris-virginica
125 | 6.7,3.3,5.7,2.1,Iris-virginica
126 | 7.2,3.2,6.0,1.8,Iris-virginica
127 | 6.2,2.8,4.8,1.8,Iris-virginica
128 | 6.1,3.0,4.9,1.8,Iris-virginica
129 | 6.4,2.8,5.6,2.1,Iris-virginica
130 | 7.2,3.0,5.8,1.6,Iris-virginica
131 | 7.4,2.8,6.1,1.9,Iris-virginica
132 | 7.9,3.8,6.4,2.0,Iris-virginica
133 | 6.4,2.8,5.6,2.2,Iris-virginica
134 | 6.3,2.8,5.1,1.5,Iris-virginica
135 | 6.1,2.6,5.6,1.4,Iris-virginica
136 | 7.7,3.0,6.1,2.3,Iris-virginica
137 | 6.3,3.4,5.6,2.4,Iris-virginica
138 | 6.4,3.1,5.5,1.8,Iris-virginica
139 | 6.0,3.0,4.8,1.8,Iris-virginica
140 | 6.9,3.1,5.4,2.1,Iris-virginica
141 | 6.7,3.1,5.6,2.4,Iris-virginica
142 | 6.9,3.1,5.1,2.3,Iris-virginica
143 | 5.8,2.7,5.1,1.9,Iris-virginica
144 | 6.8,3.2,5.9,2.3,Iris-virginica
145 | 6.7,3.3,5.7,2.5,Iris-virginica
146 | 6.7,3.0,5.2,2.3,Iris-virginica
147 | 6.3,2.5,5.0,1.9,Iris-virginica
148 | 6.5,3.0,5.2,2.0,Iris-virginica
149 | 6.2,3.4,5.4,2.3,Iris-virginica
150 | 5.9,3.0,5.1,1.8,Iris-virginica
151 |
--------------------------------------------------------------------------------
/notebooks/iris_with_names.csv:
--------------------------------------------------------------------------------
1 | sepal_length,sepal_width,petal_length,petal_width,species
2 | 5.1,3.5,1.4,0.2,Iris-setosa
3 | 4.9,3.0,1.4,0.2,Iris-setosa
4 | 4.7,3.2,1.3,0.2,Iris-setosa
5 | 4.6,3.1,1.5,0.2,Iris-setosa
6 | 5.0,3.6,1.4,0.2,Iris-setosa
7 | 5.4,3.9,1.7,0.4,Iris-setosa
8 | 4.6,3.4,1.4,0.3,Iris-setosa
9 | 5.0,3.4,1.5,0.2,Iris-setosa
10 | 4.4,2.9,1.4,0.2,Iris-setosa
11 | 4.9,3.1,1.5,0.1,Iris-setosa
12 | 5.4,3.7,1.5,0.2,Iris-setosa
13 | 4.8,3.4,1.6,0.2,Iris-setosa
14 | 4.8,3.0,1.4,0.1,Iris-setosa
15 | 4.3,3.0,1.1,0.1,Iris-setosa
16 | 5.8,4.0,1.2,0.2,Iris-setosa
17 | 5.7,4.4,1.5,0.4,Iris-setosa
18 | 5.4,3.9,1.3,0.4,Iris-setosa
19 | 5.1,3.5,1.4,0.3,Iris-setosa
20 | 5.7,3.8,1.7,0.3,Iris-setosa
21 | 5.1,3.8,1.5,0.3,Iris-setosa
22 | 5.4,3.4,1.7,0.2,Iris-setosa
23 | 5.1,3.7,1.5,0.4,Iris-setosa
24 | 4.6,3.6,1.0,0.2,Iris-setosa
25 | 5.1,3.3,1.7,0.5,Iris-setosa
26 | 4.8,3.4,1.9,0.2,Iris-setosa
27 | 5.0,3.0,1.6,0.2,Iris-setosa
28 | 5.0,3.4,1.6,0.4,Iris-setosa
29 | 5.2,3.5,1.5,0.2,Iris-setosa
30 | 5.2,3.4,1.4,0.2,Iris-setosa
31 | 4.7,3.2,1.6,0.2,Iris-setosa
32 | 4.8,3.1,1.6,0.2,Iris-setosa
33 | 5.4,3.4,1.5,0.4,Iris-setosa
34 | 5.2,4.1,1.5,0.1,Iris-setosa
35 | 5.5,4.2,1.4,0.2,Iris-setosa
36 | 4.9,3.1,1.5,0.2,Iris-setosa
37 | 5.0,3.2,1.2,0.2,Iris-setosa
38 | 5.5,3.5,1.3,0.2,Iris-setosa
39 | 4.9,3.6,1.4,0.1,Iris-setosa
40 | 4.4,3.0,1.3,0.2,Iris-setosa
41 | 5.1,3.4,1.5,0.2,Iris-setosa
42 | 5.0,3.5,1.3,0.3,Iris-setosa
43 | 4.5,2.3,1.3,0.3,Iris-setosa
44 | 4.4,3.2,1.3,0.2,Iris-setosa
45 | 5.0,3.5,1.6,0.6,Iris-setosa
46 | 5.1,3.8,1.9,0.4,Iris-setosa
47 | 4.8,3.0,1.4,0.3,Iris-setosa
48 | 5.1,3.8,1.6,0.2,Iris-setosa
49 | 4.6,3.2,1.4,0.2,Iris-setosa
50 | 5.3,3.7,1.5,0.2,Iris-setosa
51 | 5.0,3.3,1.4,0.2,Iris-setosa
52 | 7.0,3.2,4.7,1.4,Iris-versicolor
53 | 6.4,3.2,4.5,1.5,Iris-versicolor
54 | 6.9,3.1,4.9,1.5,Iris-versicolor
55 | 5.5,2.3,4.0,1.3,Iris-versicolor
56 | 6.5,2.8,4.6,1.5,Iris-versicolor
57 | 5.7,2.8,4.5,1.3,Iris-versicolor
58 | 6.3,3.3,4.7,1.6,Iris-versicolor
59 | 4.9,2.4,3.3,1.0,Iris-versicolor
60 | 6.6,2.9,4.6,1.3,Iris-versicolor
61 | 5.2,2.7,3.9,1.4,Iris-versicolor
62 | 5.0,2.0,3.5,1.0,Iris-versicolor
63 | 5.9,3.0,4.2,1.5,Iris-versicolor
64 | 6.0,2.2,4.0,1.0,Iris-versicolor
65 | 6.1,2.9,4.7,1.4,Iris-versicolor
66 | 5.6,2.9,3.6,1.3,Iris-versicolor
67 | 6.7,3.1,4.4,1.4,Iris-versicolor
68 | 5.6,3.0,4.5,1.5,Iris-versicolor
69 | 5.8,2.7,4.1,1.0,Iris-versicolor
70 | 6.2,2.2,4.5,1.5,Iris-versicolor
71 | 5.6,2.5,3.9,1.1,Iris-versicolor
72 | 5.9,3.2,4.8,1.8,Iris-versicolor
73 | 6.1,2.8,4.0,1.3,Iris-versicolor
74 | 6.3,2.5,4.9,1.5,Iris-versicolor
75 | 6.1,2.8,4.7,1.2,Iris-versicolor
76 | 6.4,2.9,4.3,1.3,Iris-versicolor
77 | 6.6,3.0,4.4,1.4,Iris-versicolor
78 | 6.8,2.8,4.8,1.4,Iris-versicolor
79 | 6.7,3.0,5.0,1.7,Iris-versicolor
80 | 6.0,2.9,4.5,1.5,Iris-versicolor
81 | 5.7,2.6,3.5,1.0,Iris-versicolor
82 | 5.5,2.4,3.8,1.1,Iris-versicolor
83 | 5.5,2.4,3.7,1.0,Iris-versicolor
84 | 5.8,2.7,3.9,1.2,Iris-versicolor
85 | 6.0,2.7,5.1,1.6,Iris-versicolor
86 | 5.4,3.0,4.5,1.5,Iris-versicolor
87 | 6.0,3.4,4.5,1.6,Iris-versicolor
88 | 6.7,3.1,4.7,1.5,Iris-versicolor
89 | 6.3,2.3,4.4,1.3,Iris-versicolor
90 | 5.6,3.0,4.1,1.3,Iris-versicolor
91 | 5.5,2.5,4.0,1.3,Iris-versicolor
92 | 5.5,2.6,4.4,1.2,Iris-versicolor
93 | 6.1,3.0,4.6,1.4,Iris-versicolor
94 | 5.8,2.6,4.0,1.2,Iris-versicolor
95 | 5.0,2.3,3.3,1.0,Iris-versicolor
96 | 5.6,2.7,4.2,1.3,Iris-versicolor
97 | 5.7,3.0,4.2,1.2,Iris-versicolor
98 | 5.7,2.9,4.2,1.3,Iris-versicolor
99 | 6.2,2.9,4.3,1.3,Iris-versicolor
100 | 5.1,2.5,3.0,1.1,Iris-versicolor
101 | 5.7,2.8,4.1,1.3,Iris-versicolor
102 | 6.3,3.3,6.0,2.5,Iris-virginica
103 | 5.8,2.7,5.1,1.9,Iris-virginica
104 | 7.1,3.0,5.9,2.1,Iris-virginica
105 | 6.3,2.9,5.6,1.8,Iris-virginica
106 | 6.5,3.0,5.8,2.2,Iris-virginica
107 | 7.6,3.0,6.6,2.1,Iris-virginica
108 | 4.9,2.5,4.5,1.7,Iris-virginica
109 | 7.3,2.9,6.3,1.8,Iris-virginica
110 | 6.7,2.5,5.8,1.8,Iris-virginica
111 | 7.2,3.6,6.1,2.5,Iris-virginica
112 | 6.5,3.2,5.1,2.0,Iris-virginica
113 | 6.4,2.7,5.3,1.9,Iris-virginica
114 | 6.8,3.0,5.5,2.1,Iris-virginica
115 | 5.7,2.5,5.0,2.0,Iris-virginica
116 | 5.8,2.8,5.1,2.4,Iris-virginica
117 | 6.4,3.2,5.3,2.3,Iris-virginica
118 | 6.5,3.0,5.5,1.8,Iris-virginica
119 | 7.7,3.8,6.7,2.2,Iris-virginica
120 | 7.7,2.6,6.9,2.3,Iris-virginica
121 | 6.0,2.2,5.0,1.5,Iris-virginica
122 | 6.9,3.2,5.7,2.3,Iris-virginica
123 | 5.6,2.8,4.9,2.0,Iris-virginica
124 | 7.7,2.8,6.7,2.0,Iris-virginica
125 | 6.3,2.7,4.9,1.8,Iris-virginica
126 | 6.7,3.3,5.7,2.1,Iris-virginica
127 | 7.2,3.2,6.0,1.8,Iris-virginica
128 | 6.2,2.8,4.8,1.8,Iris-virginica
129 | 6.1,3.0,4.9,1.8,Iris-virginica
130 | 6.4,2.8,5.6,2.1,Iris-virginica
131 | 7.2,3.0,5.8,1.6,Iris-virginica
132 | 7.4,2.8,6.1,1.9,Iris-virginica
133 | 7.9,3.8,6.4,2.0,Iris-virginica
134 | 6.4,2.8,5.6,2.2,Iris-virginica
135 | 6.3,2.8,5.1,1.5,Iris-virginica
136 | 6.1,2.6,5.6,1.4,Iris-virginica
137 | 7.7,3.0,6.1,2.3,Iris-virginica
138 | 6.3,3.4,5.6,2.4,Iris-virginica
139 | 6.4,3.1,5.5,1.8,Iris-virginica
140 | 6.0,3.0,4.8,1.8,Iris-virginica
141 | 6.9,3.1,5.4,2.1,Iris-virginica
142 | 6.7,3.1,5.6,2.4,Iris-virginica
143 | 6.9,3.1,5.1,2.3,Iris-virginica
144 | 5.8,2.7,5.1,1.9,Iris-virginica
145 | 6.8,3.2,5.9,2.3,Iris-virginica
146 | 6.7,3.3,5.7,2.5,Iris-virginica
147 | 6.7,3.0,5.2,2.3,Iris-virginica
148 | 6.3,2.5,5.0,1.9,Iris-virginica
149 | 6.5,3.0,5.2,2.0,Iris-virginica
150 | 6.2,3.4,5.4,2.3,Iris-virginica
151 | 5.9,3.0,5.1,1.8,Iris-virginica
152 |
--------------------------------------------------------------------------------
/notebooks/EX-4-Pivot-Using-SQL-And-Pandas.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Pivoting SQL results in Panda\n",
8 | "\n",
9 | "This notebook shows how to pivot array data using SQL ARRAY JOIN and pandas DataFrame.pivot(). This problem appeared as a [question on Stack Overflow](https://stackoverflow.com/questions/54811905/return-clickhouse-array-as-column). "
10 | ]
11 | },
12 | {
13 | "cell_type": "markdown",
14 | "metadata": {},
15 | "source": [
16 | "First create some test data. We'll use clickhouse-driver for this so we can see the SQL. "
17 | ]
18 | },
19 | {
20 | "cell_type": "code",
21 | "execution_count": 1,
22 | "metadata": {},
23 | "outputs": [],
24 | "source": [
25 | "from clickhouse_driver import Client\n",
26 | "client = Client('localhost')\n",
27 | "client.execute('CREATE TABLE IF NOT EXISTS f '\n",
28 | " '(f1 String, f2 Array(Int32), f3 Array(String)) '\n",
29 | " 'ENGINE = Memory')\n",
30 | "client.execute('TRUNCATE TABLE f')\n",
31 | "client.execute(\n",
32 | " 'INSERT INTO f (f1, f2, f3) VALUES', [\n",
33 | " ('a', [1,2,3], ['x', 'y', 'z']),\n",
34 | " ('b', [4,5,6], ['x', 'y', 'z']),\n",
35 | " ]\n",
36 | ")"
37 | ]
38 | },
39 | {
40 | "cell_type": "markdown",
41 | "metadata": {},
42 | "source": [
43 | "Now load SQLAlchemy. "
44 | ]
45 | },
46 | {
47 | "cell_type": "code",
48 | "execution_count": 2,
49 | "metadata": {
50 | "scrolled": true
51 | },
52 | "outputs": [],
53 | "source": [
54 | "from sqlalchemy import create_engine\n",
55 | "%load_ext sql"
56 | ]
57 | },
58 | {
59 | "cell_type": "markdown",
60 | "metadata": {},
61 | "source": [
62 | "Connect to ClickHouse, which is assumed to be on localhost with default user. "
63 | ]
64 | },
65 | {
66 | "cell_type": "code",
67 | "execution_count": 3,
68 | "metadata": {},
69 | "outputs": [
70 | {
71 | "data": {
72 | "text/plain": [
73 | "'Connected: default@default'"
74 | ]
75 | },
76 | "execution_count": 3,
77 | "metadata": {},
78 | "output_type": "execute_result"
79 | }
80 | ],
81 | "source": [
82 | "%sql clickhouse://default:@localhost/default"
83 | ]
84 | },
85 | {
86 | "cell_type": "markdown",
87 | "metadata": {},
88 | "source": [
89 | "Use SQL query with ARRAY JOIN to flip matching array indexes in f2, f3 to row values with f1. "
90 | ]
91 | },
92 | {
93 | "cell_type": "code",
94 | "execution_count": 13,
95 | "metadata": {},
96 | "outputs": [
97 | {
98 | "name": "stdout",
99 | "output_type": "stream",
100 | "text": [
101 | " * clickhouse://default:***@localhost/default\n",
102 | "Done.\n"
103 | ]
104 | },
105 | {
106 | "data": {
107 | "text/html": [
108 | "
\n",
109 | "\n",
122 | "
\n",
123 | " \n",
124 | " \n",
125 | " | \n",
126 | " f1 | \n",
127 | " f2 | \n",
128 | " f3 | \n",
129 | "
\n",
130 | " \n",
131 | " \n",
132 | " \n",
133 | " | 0 | \n",
134 | " a | \n",
135 | " 1 | \n",
136 | " x | \n",
137 | "
\n",
138 | " \n",
139 | " | 1 | \n",
140 | " a | \n",
141 | " 2 | \n",
142 | " y | \n",
143 | "
\n",
144 | " \n",
145 | " | 2 | \n",
146 | " a | \n",
147 | " 3 | \n",
148 | " z | \n",
149 | "
\n",
150 | " \n",
151 | " | 3 | \n",
152 | " b | \n",
153 | " 4 | \n",
154 | " x | \n",
155 | "
\n",
156 | " \n",
157 | " | 4 | \n",
158 | " b | \n",
159 | " 5 | \n",
160 | " y | \n",
161 | "
\n",
162 | " \n",
163 | " | 5 | \n",
164 | " b | \n",
165 | " 6 | \n",
166 | " z | \n",
167 | "
\n",
168 | " \n",
169 | " | 6 | \n",
170 | " c | \n",
171 | " 7 | \n",
172 | " y | \n",
173 | "
\n",
174 | " \n",
175 | " | 7 | \n",
176 | " c | \n",
177 | " 8 | \n",
178 | " z | \n",
179 | "
\n",
180 | " \n",
181 | " | 8 | \n",
182 | " c | \n",
183 | " 9 | \n",
184 | " aa | \n",
185 | "
\n",
186 | " \n",
187 | " | 9 | \n",
188 | " c | \n",
189 | " 10 | \n",
190 | " bb | \n",
191 | "
\n",
192 | " \n",
193 | " | 10 | \n",
194 | " c | \n",
195 | " 7 | \n",
196 | " y | \n",
197 | "
\n",
198 | " \n",
199 | " | 11 | \n",
200 | " c | \n",
201 | " 8 | \n",
202 | " z | \n",
203 | "
\n",
204 | " \n",
205 | " | 12 | \n",
206 | " c | \n",
207 | " 9 | \n",
208 | " aa | \n",
209 | "
\n",
210 | " \n",
211 | " | 13 | \n",
212 | " c | \n",
213 | " 10 | \n",
214 | " bb | \n",
215 | "
\n",
216 | " \n",
217 | "
\n",
218 | "
"
219 | ],
220 | "text/plain": [
221 | " f1 f2 f3\n",
222 | "0 a 1 x\n",
223 | "1 a 2 y\n",
224 | "2 a 3 z\n",
225 | "3 b 4 x\n",
226 | "4 b 5 y\n",
227 | "5 b 6 z\n",
228 | "6 c 7 y\n",
229 | "7 c 8 z\n",
230 | "8 c 9 aa\n",
231 | "9 c 10 bb\n",
232 | "10 c 7 y\n",
233 | "11 c 8 z\n",
234 | "12 c 9 aa\n",
235 | "13 c 10 bb"
236 | ]
237 | },
238 | "execution_count": 13,
239 | "metadata": {},
240 | "output_type": "execute_result"
241 | }
242 | ],
243 | "source": [
244 | "result = %sql SELECT * FROM f ARRAY JOIN f2, f3\n",
245 | "df = result.DataFrame()\n",
246 | "df"
247 | ]
248 | },
249 | {
250 | "cell_type": "markdown",
251 | "metadata": {},
252 | "source": [
253 | "Now we can pivot f2 and f3 into a new data frame that has the f3 array entries as columns. "
254 | ]
255 | },
256 | {
257 | "cell_type": "code",
258 | "execution_count": 15,
259 | "metadata": {},
260 | "outputs": [
261 | {
262 | "name": "stdout",
263 | "output_type": "stream",
264 | "text": [
265 | "f3 aa bb x y z\n",
266 | "f1 \n",
267 | "a NaN NaN 1.0 2.0 3.0\n",
268 | "b NaN NaN 4.0 5.0 6.0\n",
269 | "c 9.0 10.0 NaN 7.0 8.0\n"
270 | ]
271 | }
272 | ],
273 | "source": [
274 | "dfp = df.pivot_table(columns='f3', values='f2', index='f1')\n",
275 | "print(dfp)"
276 | ]
277 | },
278 | {
279 | "cell_type": "markdown",
280 | "metadata": {},
281 | "source": [
282 | "This approach works if we add additional data with new property names in the f3 array. Try adding a row to the table and then rerun the cells that select and pivot data. "
283 | ]
284 | },
285 | {
286 | "cell_type": "code",
287 | "execution_count": 12,
288 | "metadata": {
289 | "scrolled": false
290 | },
291 | "outputs": [],
292 | "source": [
293 | "client.execute(\n",
294 | " 'INSERT INTO f (f1, f2, f3) VALUES', [\n",
295 | " ('c', [7,8,9,10], ['y', 'z', 'aa', 'bb']),\n",
296 | " ]\n",
297 | ")"
298 | ]
299 | },
300 | {
301 | "cell_type": "markdown",
302 | "metadata": {},
303 | "source": [
304 | "If you try this again the duplicate rows will be ignored. "
305 | ]
306 | }
307 | ],
308 | "metadata": {
309 | "kernelspec": {
310 | "display_name": "Python 3",
311 | "language": "python",
312 | "name": "python3"
313 | },
314 | "language_info": {
315 | "codemirror_mode": {
316 | "name": "ipython",
317 | "version": 3
318 | },
319 | "file_extension": ".py",
320 | "mimetype": "text/x-python",
321 | "name": "python",
322 | "nbconvert_exporter": "python",
323 | "pygments_lexer": "ipython3",
324 | "version": "3.7.1"
325 | },
326 | "widgets": {
327 | "application/vnd.jupyter.widget-state+json": {
328 | "state": {},
329 | "version_major": 1,
330 | "version_minor": 0
331 | }
332 | }
333 | },
334 | "nbformat": 4,
335 | "nbformat_minor": 2
336 | }
337 |
--------------------------------------------------------------------------------
/notebooks/EX-1.0-Getting-to-Know-the-Clickhouse-driver-Client.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Getting to know the ClickHouse-driver Client\n",
8 | "\n",
9 | "This notebook has samples that were included in the [Altinity blog article that introduces the clickhouse-driver client library](https://www.altinity.com/blog/clickhouse-and-python-getting-to-know-the-clickhouse-driver-client).\n",
10 | "\n",
11 | "_WARNING_: If you run the whole notebook it will hang. You must run the samples one by one as one of them is designed to hang and must be cancelled manually. "
12 | ]
13 | },
14 | {
15 | "cell_type": "markdown",
16 | "metadata": {},
17 | "source": [
18 | "It's easy to load the clickhouse driver. The `Client` class is the main client interface. "
19 | ]
20 | },
21 | {
22 | "cell_type": "code",
23 | "execution_count": null,
24 | "metadata": {},
25 | "outputs": [],
26 | "source": [
27 | "from clickhouse_driver import Client"
28 | ]
29 | },
30 | {
31 | "cell_type": "markdown",
32 | "metadata": {},
33 | "source": [
34 | "If you are running against an unencrypted local server setting up a connection is as simple as the following. Instantiating a client does not actually connect to ClickHouse. It just sets up the data structure used to connect later on when your code does something. "
35 | ]
36 | },
37 | {
38 | "cell_type": "code",
39 | "execution_count": null,
40 | "metadata": {},
41 | "outputs": [],
42 | "source": [
43 | "client = Client('localhost')"
44 | ]
45 | },
46 | {
47 | "cell_type": "markdown",
48 | "metadata": {},
49 | "source": [
50 | "Servers with sensitive data should be encrypted with a user/password and encrypted communications. The following command shows how to connect to a server with self-signed certificate using an explicit database name. "
51 | ]
52 | },
53 | {
54 | "cell_type": "code",
55 | "execution_count": null,
56 | "metadata": {},
57 | "outputs": [],
58 | "source": [
59 | "client = Client('localhost', \n",
60 | " user='python', \n",
61 | " password='secret', \n",
62 | " secure=True, \n",
63 | " verify=False, \n",
64 | " database='default',\n",
65 | " compression=True)"
66 | ]
67 | },
68 | {
69 | "cell_type": "markdown",
70 | "metadata": {},
71 | "source": [
72 | "The Python driver uses the Client.execute() method to issue select commands. Results are returned as a list of tuples. Let's send a very simple query and take apart the results to see values and types. \n",
73 | "\n",
74 | "*NOTE*: If you get an error about an unknown timezone, ensure your server has the timezone set properly. "
75 | ]
76 | },
77 | {
78 | "cell_type": "code",
79 | "execution_count": null,
80 | "metadata": {
81 | "scrolled": false
82 | },
83 | "outputs": [],
84 | "source": [
85 | "result = client.execute('SELECT now(), version()')\n",
86 | "print(\"RESULT: {0}: {1}\".format(type(result), result))\n",
87 | "for t in result:\n",
88 | " print(\" ROW: {0}: {1}\".format(type(t), t))\n",
89 | " for v in t:\n",
90 | " print(\" COLUMN: {0}: {1}\".format(type(v), v))"
91 | ]
92 | },
93 | {
94 | "cell_type": "markdown",
95 | "metadata": {},
96 | "source": [
97 | "Create the iris table, dropping any previously existing table of the same name. The print statements show that result sets from DDL are empty. "
98 | ]
99 | },
100 | {
101 | "cell_type": "code",
102 | "execution_count": null,
103 | "metadata": {},
104 | "outputs": [],
105 | "source": [
106 | "r1 = client.execute('DROP TABLE IF EXISTS iris')\n",
107 | "print(r1)\n",
108 | "r2 = client.execute('CREATE TABLE iris ('\n",
109 | " 'sepal_length Float64, sepal_width Float64, '\n",
110 | " 'petal_length Float64, petal_width Float64, '\n",
111 | " 'species String) ENGINE = MergeTree '\n",
112 | " ' PARTITION BY species ORDER BY (species)')\n",
113 | "print(r2)"
114 | ]
115 | },
116 | {
117 | "cell_type": "markdown",
118 | "metadata": {},
119 | "source": [
120 | "Add some data to the table. Note that the values are given in a separate array of tuples. "
121 | ]
122 | },
123 | {
124 | "cell_type": "code",
125 | "execution_count": null,
126 | "metadata": {},
127 | "outputs": [],
128 | "source": [
129 | "client.execute(\n",
130 | " 'INSERT INTO iris (sepal_length, sepal_width, petal_length, petal_width, species) VALUES',\n",
131 | " [(5.1, 3.7, 1.5, 0.4, 'Iris-setosa'), (4.6, 3.6, 1.0, 0.2, 'Iris-setosa')]\n",
132 | ")\n",
133 | "print(client.execute(\"SELECT * FROM iris\"))"
134 | ]
135 | },
136 | {
137 | "cell_type": "markdown",
138 | "metadata": {},
139 | "source": [
140 | "Here is an example of how to insert CSV. We read the values line by line using csv.DictReader() running inside the generator function row_reader(). This results in a tuple for each line. Note that *you must* assign types or your values will not convert. The csv module converts everything to a string. "
141 | ]
142 | },
143 | {
144 | "cell_type": "code",
145 | "execution_count": null,
146 | "metadata": {
147 | "scrolled": true
148 | },
149 | "outputs": [],
150 | "source": [
151 | "client.execute(\"TRUNCATE TABLE iris\")\n",
152 | "\n",
153 | "import datetime\n",
154 | "import csv\n",
155 | "\n",
156 | "# Create a generator to fetch parsed rows. CSV must have variable names in header row.\n",
157 | "def row_reader():\n",
158 | " with open('iris_with_names.csv') as iris_csv:\n",
159 | " # Use DictReader to get values as a dictionary with column names.\n",
160 | " for line in csv.DictReader(iris_csv):\n",
161 | " yield {\n",
162 | " 'sepal_length': float(line['sepal_length']), \n",
163 | " 'sepal_width': float(line['sepal_width']), \n",
164 | " 'petal_length': float(line['petal_length']), \n",
165 | " 'petal_width': float(line['petal_width']), \n",
166 | " 'species': str(line['species']), \n",
167 | " }\n",
168 | "\n",
169 | "# Use a generator expression to load values as a list of dictionaries. \n",
170 | "client.execute(\"INSERT INTO iris VALUES\", (line for line in row_reader()))\n",
171 | "client.execute(\"SELECT count(*) FROM iris\")"
172 | ]
173 | },
174 | {
175 | "cell_type": "markdown",
176 | "metadata": {},
177 | "source": [
178 | "That was painful. We dislike pain. A better approach to non-toy CSV files is to use Pandas, which has a very good method for reading CSV that automatically coerces types. This is much simpler! "
179 | ]
180 | },
181 | {
182 | "cell_type": "code",
183 | "execution_count": null,
184 | "metadata": {},
185 | "outputs": [],
186 | "source": [
187 | "client.execute(\"TRUNCATE TABLE iris\")\n",
188 | "\n",
189 | "import pandas as pd\n",
190 | "df = pd.read_csv('iris_with_names.csv')\n",
191 | "\n",
192 | "client.execute(\"INSERT INTO iris VALUES\", [tuple(x) for x in df.values])\n",
193 | "client.execute(\"SELECT count(*) FROM iris\")"
194 | ]
195 | },
196 | {
197 | "cell_type": "markdown",
198 | "metadata": {},
199 | "source": [
200 | "The next few queries show examples of select statements. "
201 | ]
202 | },
203 | {
204 | "cell_type": "code",
205 | "execution_count": null,
206 | "metadata": {},
207 | "outputs": [],
208 | "source": [
209 | "result = client.execute('SELECT COUNT(*), species FROM iris '\n",
210 | " 'WHERE petal_length > 3.4 '\n",
211 | " 'GROUP BY species ORDER BY species')\n",
212 | "print(result)"
213 | ]
214 | },
215 | {
216 | "cell_type": "code",
217 | "execution_count": null,
218 | "metadata": {},
219 | "outputs": [],
220 | "source": [
221 | "result = client.execute('SELECT COUNT(*), species FROM iris '\n",
222 | " 'WHERE petal_length > %(max_len)s '\n",
223 | " 'GROUP BY species ORDER BY species', \n",
224 | " {'max_len': 3.4})\n",
225 | "print(result)"
226 | ]
227 | },
228 | {
229 | "cell_type": "markdown",
230 | "metadata": {},
231 | "source": [
232 | "Show how to get the column names for results. Note that we also get the column types, which is convenient for conversions. "
233 | ]
234 | },
235 | {
236 | "cell_type": "code",
237 | "execution_count": null,
238 | "metadata": {},
239 | "outputs": [],
240 | "source": [
241 | "result, columns = client.execute('SELECT COUNT(*), species FROM iris '\n",
242 | " 'WHERE petal_length > %(max_len)s '\n",
243 | " 'GROUP BY species ORDER BY species', \n",
244 | " {'max_len': 3.4},\n",
245 | " with_column_types=True)\n",
246 | "print(result)\n",
247 | "print(columns)"
248 | ]
249 | },
250 | {
251 | "cell_type": "markdown",
252 | "metadata": {},
253 | "source": [
254 | "This final example shows how to put a result set into a pandas data frame. We'll use the column names so that the DataFrame has correct labels."
255 | ]
256 | },
257 | {
258 | "cell_type": "code",
259 | "execution_count": null,
260 | "metadata": {
261 | "scrolled": true
262 | },
263 | "outputs": [],
264 | "source": [
265 | "import pandas\n",
266 | "result, columns = client.execute('SELECT * FROM iris WHERE species = %(species)s LIMIT 5', \n",
267 | " {'species': \"Iris-setosa\"}, with_column_types=True)\n",
268 | "df = pandas.DataFrame(result, columns=[tuple[0] for tuple in columns])\n",
269 | "df.tail()"
270 | ]
271 | },
272 | {
273 | "cell_type": "markdown",
274 | "metadata": {},
275 | "source": [
276 | "Since we're using pandas and may like to put this data into graphs, etc., we need to ensure the data types are correct. Let's describe the data set to ensure that the columns with numbers really appear as numbers. The following should show metrics for length and width values but nothing for species, which is a string. "
277 | ]
278 | },
279 | {
280 | "cell_type": "code",
281 | "execution_count": null,
282 | "metadata": {},
283 | "outputs": [],
284 | "source": [
285 | "df.describe()"
286 | ]
287 | },
288 | {
289 | "cell_type": "code",
290 | "execution_count": null,
291 | "metadata": {},
292 | "outputs": [],
293 | "source": []
294 | }
295 | ],
296 | "metadata": {
297 | "kernelspec": {
298 | "display_name": "Python 3",
299 | "language": "python",
300 | "name": "python3"
301 | },
302 | "language_info": {
303 | "codemirror_mode": {
304 | "name": "ipython",
305 | "version": 3
306 | },
307 | "file_extension": ".py",
308 | "mimetype": "text/x-python",
309 | "name": "python",
310 | "nbconvert_exporter": "python",
311 | "pygments_lexer": "ipython3",
312 | "version": "3.7.1"
313 | }
314 | },
315 | "nbformat": 4,
316 | "nbformat_minor": 2
317 | }
318 |
--------------------------------------------------------------------------------
/notebooks/EX-3-Sql-Magic-Functions.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Using Sql Magic Function with ClickHouse\n",
8 | "\n",
9 | "This notebook goes from nothing to a nice graph in three steps. We'll extract data using the %sql magic function. You'll need to have created the iris table for this to work. Run the EX-1-Getting-to-Know-the-Clickhouse-driver-Client.ipynb notebook to load data into the iris table if you have not already done so. "
10 | ]
11 | },
12 | {
13 | "cell_type": "markdown",
14 | "metadata": {},
15 | "source": [
16 | "First import SQLAlchemy and activate the %sql function. This just needs to be done once. "
17 | ]
18 | },
19 | {
20 | "cell_type": "code",
21 | "execution_count": 1,
22 | "metadata": {
23 | "scrolled": true
24 | },
25 | "outputs": [],
26 | "source": [
27 | "from sqlalchemy import create_engine\n",
28 | "%load_ext sql"
29 | ]
30 | },
31 | {
32 | "cell_type": "markdown",
33 | "metadata": {},
34 | "source": [
35 | "Connect to a local server using native protocol, select data from the iris table, and pop it into a data frame. You should see 150 rows in the data frame. "
36 | ]
37 | },
38 | {
39 | "cell_type": "code",
40 | "execution_count": 2,
41 | "metadata": {
42 | "scrolled": true
43 | },
44 | "outputs": [
45 | {
46 | "name": "stdout",
47 | "output_type": "stream",
48 | "text": [
49 | " * clickhouse://default:***@localhost/default\n",
50 | "Done.\n"
51 | ]
52 | },
53 | {
54 | "data": {
55 | "text/html": [
56 | "\n",
57 | "\n",
70 | "
\n",
71 | " \n",
72 | " \n",
73 | " | \n",
74 | " sepal_length | \n",
75 | " sepal_width | \n",
76 | " petal_length | \n",
77 | " petal_width | \n",
78 | " species | \n",
79 | "
\n",
80 | " \n",
81 | " \n",
82 | " \n",
83 | " | 145 | \n",
84 | " 5.7 | \n",
85 | " 3.0 | \n",
86 | " 4.2 | \n",
87 | " 1.2 | \n",
88 | " Iris-versicolor | \n",
89 | "
\n",
90 | " \n",
91 | " | 146 | \n",
92 | " 5.7 | \n",
93 | " 2.9 | \n",
94 | " 4.2 | \n",
95 | " 1.3 | \n",
96 | " Iris-versicolor | \n",
97 | "
\n",
98 | " \n",
99 | " | 147 | \n",
100 | " 6.2 | \n",
101 | " 2.9 | \n",
102 | " 4.3 | \n",
103 | " 1.3 | \n",
104 | " Iris-versicolor | \n",
105 | "
\n",
106 | " \n",
107 | " | 148 | \n",
108 | " 5.1 | \n",
109 | " 2.5 | \n",
110 | " 3.0 | \n",
111 | " 1.1 | \n",
112 | " Iris-versicolor | \n",
113 | "
\n",
114 | " \n",
115 | " | 149 | \n",
116 | " 5.7 | \n",
117 | " 2.8 | \n",
118 | " 4.1 | \n",
119 | " 1.3 | \n",
120 | " Iris-versicolor | \n",
121 | "
\n",
122 | " \n",
123 | "
\n",
124 | "
"
125 | ],
126 | "text/plain": [
127 | " sepal_length sepal_width petal_length petal_width species\n",
128 | "145 5.7 3.0 4.2 1.2 Iris-versicolor\n",
129 | "146 5.7 2.9 4.2 1.3 Iris-versicolor\n",
130 | "147 6.2 2.9 4.3 1.3 Iris-versicolor\n",
131 | "148 5.1 2.5 3.0 1.1 Iris-versicolor\n",
132 | "149 5.7 2.8 4.1 1.3 Iris-versicolor"
133 | ]
134 | },
135 | "execution_count": 2,
136 | "metadata": {},
137 | "output_type": "execute_result"
138 | }
139 | ],
140 | "source": [
141 | "%sql clickhouse://default:@localhost/default\n",
142 | "result = %sql SELECT * FROM iris\n",
143 | "df = result.DataFrame()\n",
144 | "df.tail()"
145 | ]
146 | },
147 | {
148 | "cell_type": "markdown",
149 | "metadata": {},
150 | "source": [
151 | "Everybody likes a nice picture. Let's make a scatter graph that shows data with different markers for each species of iris. We'll use standard pandas tricks to find the species names and query for each one of the. \n",
152 | "\n",
153 | "Pro tip: For large datasets you could get unique names using SQL. We'll just cheat and use the pandas unique() method on the data frame."
154 | ]
155 | },
156 | {
157 | "cell_type": "code",
158 | "execution_count": 5,
159 | "metadata": {},
160 | "outputs": [
161 | {
162 | "data": {
163 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXwAAAEKCAYAAAARnO4WAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAAIABJREFUeJzt3XmYFOX16PHvYRgFFEU2jYOCel2iLMMewbBIBHdBAVGjEhVcrnFJooLGXRQ1Jmb5XRE14BYFRdCfC5KwiKKCM6yCSxQFgRhHkFEZ0Jmec/+o7pnunl6q6erq7unzeZ5+Zqq6uup0oWeqT5/3LVFVjDHGNH5Nsh2AMcYYf1jCN8aYAmEJ3xhjCoQlfGOMKRCW8I0xpkBYwjfGmAJhCd8YYwqEJXxjjCkQlvCNMaZANM12AOHatm2rnTp1ynYYxhiTN8rLy79W1XZuts2phN+pUyfKysqyHYYxxuQNEdngdlsr6RhjTIGwhG+MMQUiYwlfRI4UkZVhj29F5JpMHc8YY0xiGavhq+pHQCmAiBQBm4HZqe6nurqaTZs2sWvXLo8jNOlo1qwZHTp0oLi4ONuhGGNc8utL2yHAp6rq+suFkE2bNtGyZUs6deqEiGQgNJMqVWXr1q1s2rSJQw45JNvhGGNc8quGPwZ4JtYTIjJeRMpEpKyioqLB87t27aJNmzaW7HOIiNCmTRv71GVMnsn4Fb6I7AGcDkyM9byqTgWmAvTq1Svm7bcs2ece+zcxhW7Ois3c//pHbNm+kwNbNee6YUcyvHtJtsNKyI+SzknAclX9rw/HMsaYjJuzYjMTX1jDzuoAAJu372TiC2sAcjrp+1HSOYc45Zx8sffee8d9rl+/fmnv/6WXXmLy5Mkpv87NsS+55BLWrVu3O2EZY+K4//WP6pJ9yM7qAPe//lGWInIno1f4ItICOAG4NJPHyYZAIEBRURFvv/122vs6/fTTOf300xusr6mpoWnT+P9Ebo796KOPphWbMaahLdt3prQ+V2T0Cl9Vq1S1japWZvI44eas2Ez/yQs4ZMIr9J+8gDkrNnu270WLFjF48GDOPfdcunTpAtRf/f/nP/9hwIABlJaW0rlzZ958880Gr+/bty9r166tWx40aBDl5eVMnz6dK6+8EoCxY8fym9/8hsGDB3PDDTdQUVHBCSecQI8ePbj00kvp2LEjX3/9dcSxFy1axKBBgxg5ciRHHXUU5513Hqpad4zQdBVz586lR48edOvWjSFDhgCwbNky+vXrR/fu3enXrx8ffZTbVyjG5IIDWzVPaX2uaFQjbUN1tc3bd6LU19W8TPrLli1j0qRJDcok//jHPxg2bBgrV65k1apVlJaWNnjtmDFjmDlzJuD8gdiyZQs9e/ZssN3HH3/Mv/71Lx544AFuv/12jj/+eJYvX86IESPYuHFjzLhWrFjBgw8+yLp161i/fj1LliyJeL6iooJx48Yxa9YsVq1axXPPPQfAUUcdxeLFi1mxYgV33HEHN954426dF2MKyXXDjqR5cVHEuubFRVw37MgsReROo0r4ftTV+vTpE7P3vHfv3kybNo3bbruNNWvW0LJlywbbjB49ui7Rzpw5k1GjRsU8xqhRoygqcv5jeuuttxgzZgwAJ554Ivvtt1/cuDp06ECTJk0oLS3l888/j3j+3XffZcCAAXWxt27dGoDKykpGjRpF586dufbaayM+gRhjYhvevYQeB+8bsa7Hwfvm9Be20MgSvh91tb322ivm+gEDBrB48WJKSko4//zzeeKJJ5g9ezalpaWUlpZSVlZGSUkJbdq0YfXq1cyYMaMukSc6Rqg0k8yee+5Z93tRURE1NTURz6tqzFbKm2++mcGDB/P+++/zv//7v9Zbb4wLv5+zhiWfbotYt+TTbfx+zposReROo0r42ayrbdiwgfbt2zNu3DguvvjiuhLMypUrWblyJb169QKcss59991HZWVl3fcAiRx33HF1ZaB58+bxzTff7FZ8xx57LG+88QafffYZANu2Of+xVlZWUlLiXJVMnz59t/ZtTKF5ZukXKa3PFY0q4WezrrZo0SJKS0vp3r07s2bN4uqrr4653ciRI3n22WcZPXq0q/3eeuutzJs3jx49evDaa6/xk5/8JGa5KJl27doxdepUzjzzTLp168bZZ58NwPXXX8/EiRPp378/gUAgyV6MMQCBOJ+8463PFeK2ZOCHXr16afQNUD744AN++tOfut5HPo5+S+SHH36gqKiIpk2b8s4773D55ZezcuXKbIcFpP5vY0y+SJZHDpv4aszkXiTCp/ec7GeoiEi5qvZys21O3fHKC8O7l+R1go+2ceNGRo8eTW1tLXvssQePPPJItkMyplFzM4r2nL4H8dS7DTvmzul7kH+B7oZGl/Abm8MPP5wVK1ZkOwxjCkaibr9Qwr9ruPP92zNLvyCgSpEI5/Q9qG59rrKEb4wxYdx2+901vEvOJ/hojepLW2OMSVe+jqJ1wxK+McaEyddRtG5YSccYY8KE6vSZ7vbLRkehJXwX9t57b77//vuYz/Xr18+TGTNjufvuu21uG2OyINPdftmaT7/xlXSie2MzNM4gNEgpU8kenIRvjGl8sjWffuNK+AvvgbkT65O8qrO88B5Pdp/u9Mhr166lT58+lJaW0rVrV/79738D8NRTT9Wtv/TSSwkEAkyYMIGdO3dSWlrKeeedB8Af//hHOnfuTOfOnXnwwQcB2LFjB6eccgrdunWjc+fOzJgxA4A77riD3r1707lzZ8aPH+96Th5jTOZlaz79xlPSUYVdlbD0IWf5xGDyX/oQ9L3ced6D+7AuW7aM999/v8GMmaHpkW+66SYCgQBVVVUNXjtlyhSuvvpqzjvvPH788UcCgQAffPABM2bMYMmSJRQXF3PFFVfw9NNPM3nyZP72t7/VjaotLy9n2rRpLF26FFWlb9++DBw4kPXr13PggQfyyiuvAM7cOABXXnklt9xyCwDnn38+L7/8Mqeddlra79+YbGsMo+kPbNWczTGSe6Y7gRpPwhdxkjw4ST6U+Pte7qz36KbbiaZHvuiii6iurmb48OEx58M/9thjmTRpEps2beLMM8/k8MMPZ/78+ZSXl9O7d28Adu7cSfv27Ru89q233mLEiBF1M2meeeaZvPnmm5x44on87ne/44YbbuDUU0/l5z//OQALFy7kvvvuo6qqim3btnHMMcdYwjd5L1/vJRvtumFHRrwP8KcTqHGVdMKTfoiHyR7Smx753HPP5aWXXqJ58+YMGzaMBQsWoKpceOGFdbNqfvTRR9x2220N9h+vJHPEEUdQXl5Oly5dmDhxInfccQe7du3iiiuu4Pnnn2fNmjWMGzfOpj02jUK+3ks22vDuJdxzZhdKWjVHgJJWzbnnzC7WpZOSUM0+3NyJnif9WDZs2EBJSQnjxo1jx44dLF++nAcffJARI0bUbbN+/XoOPfRQrrrqKtavX8/q1asZOnQoZ5xxBtdeey3t27dn27ZtfPfdd3Ts2JHi4mKqq6spLi5mwIABjB07lgkTJqCqzJ49myeffJItW7bQunVrfvnLX7L33nszffr0uuTetm1bvv/+e55//nlGjhyZ0fdvjB/y9V6ysWRj3q/Gk/BDyT5Usw+v4UPGk/6iRYu4//77KS4uZu+99+aJJ55osM2MGTN46qmnKC4u5oADDuCWW26hdevW3HXXXQwdOpTa2lqKi4v5n//5Hzp27Mj48ePp2rUrPXr04Omnn2bs2LH06dMHgEsuuYTu3bvz+uuvc91119GkSROKi4t56KGHaNWqFePGjaNLly506tSprlxkTL7LVu27sWhc0yMvvMf54jaU3EN/BJrtC4MnJn+9SYlNj2z8Fl3DB6f27Uc5JFcV7vTIgydGduOEavoZLucYY7yTqAvH7ShYPzp58rFbqHElfGiY3C3ZG5M33HThJKt9+9HJk6/dQo2rS8cYk9e86MLxo5MnX7uFMprwRaSViDwvIh+KyAcicmwmj2eMyW9edOH40cmTr91CmS7p/BmYq6ojRWQPoEWGj2dMTsrHem82eNGF40cnT752C2XsCl9E9gEGAI8BqOqPqro9U8czJleF6r2bt+9Eqa/3zlmxOduh5ZzBR7VLaX0sfsxnn69z5meypHMoUAFME5EVIvKoiMQepprjQhOkxdKvXz8fI4nt5JNPZvv21P+W3nbbbfzhD3/IQEQmXL7We7Nh4YcVKa2PxY9RrNkaKZuuTJZ0mgI9gF+r6lIR+TMwAbg5fCMRGQ+MBzj44IMzGI63AoEARUVFGZ0eOVxNTQ1Nm8b+53r11VezHoOJL1/qvbnQyujVufJjFGs2RsqmK5NX+JuATaq6NLj8PM4fgAiqOlVVe6lqr3bt3H9sS6SiqoKTZp3E1zu/9mR/IelOj9y3b1/Wrl1btzxo0CDKy8vZsWMHF110Eb1796Z79+68+OKLAEyfPp1Ro0Zx2mmnMXTo0LjH6NSpE19/7bzXJ554gq5du9KtWzfOP/98wJn2YciQIXTt2pUhQ4awcePGBrGtXLmSn/3sZ3Tt2pURI0bwzTff1MV44403MnDgQP785z97dSoLSj7cI9WPspObY+TDucpnGUv4qvol8IWIhIpaQ4B1mTpeuCmrp7D5+81MWTXF830vW7aMSZMmsW5d5FsJTY+8cuVKVq1aFXO2zDFjxjBz5kzA+QOxZcsWevbsyaRJkzj++ON57733WLhwIddddx07duwA4J133uHxxx9nwYIFSY+xdu1aJk2axIIFC1i1alVdgr7yyiu54IILWL16Needdx5XXXVVg9guuOAC7r33XlavXk2XLl24/fbb657bvn07b7zxBr/97W/TO3kFKh/qvbnSypgP5yqfZboP/9fA0yKyGigFMn4Lp4qqCl785EUUZc4nczy/yk80PfK0adO47bbbWLNmDS1btmywzejRo3nuuecAmDlzJqNGjQJg3rx5TJ48mdLSUgYNGsSuXbvqrsJPOOEEWrdu7eoYCxYsYOTIkbRt2xag7nXvvPMO5557LuDMjf/WW29FvK6yspLt27czcOBAAC688EIWL15c9/zZZ5+d4lky4byo985ZsZn+kxdwyIRX6D95wW5deSfaR660Mg7vXsJZPUsoCg6YLBLhrJ75VzrJVRlN+Kq6Mliu6aqqw1X1m0weD5yr+1qtBaBWaz2/yk9neuSSkhLatGnD6tWrmTFjBmPGjAGcqY9nzZpVN0Xyxo0b6+aoCT9erGOEU1XExchiN9u4ec/GveHdS1gy4Xg+m3wKSyYcn3KyT7fckmwffpRS3BxjzorNzCrfTCA4x1dAlVnlm62jySONaqRt6Oq+urYagOra6oxc5ceyYcMG2rdvz7hx47j44otZvnw5I0aMqEvivXo5cxuNGTOG++67j8rKyrrvAYYNG8Zf//rXujnvV6xY4foY4YYMGcLMmTPZunUrANu2bQOcTqJnn30WgKeffprjjjsu4nX77rsv++23X913Ak8++WTd1b7JPj9Gn+ZKK6N1NGVWo2q5CL+6Dwld5f/+Z7/P6LHdTI8MMHLkSK6++mpuvrm+Wenmm2/mmmuuoWvXrqgqnTp14uWXX075GMcccww33XQTAwcOpKioiO7duzN9+nT+8pe/cNFFF3H//ffTrl07pk2b1mDfjz/+OJdddhlVVVUceuihMbcx2eHH6FO3k5Klw80x8qWjKV81qumRhzw3hK+qvmqwvn2L9swfNd+TGE09mx7ZH/0nL4g5qrOkVXOWTDjet31A5ls3vYqzkBTs9MiW1E1j5MX9Tzu1iT0VQKc27mv0fswQma17vRaKRlXDN6Yx8qLL5931sfsl4q2PxY/6er6OYM0XeXGF77b7xPgnl0qBmeZFGeP3c9bwzNIvCKhSJMI5fQ/iruFdXD+f7qjOQJx/r3jrY/Grvp6PI1jzRc5f4Tdr1oytW7cWVILJdarK1q1badasWbZDyTgvWiJ/P2cNT727MaLV8Kl3N/L7OWtcPe+FeNdLqVxH2SjY/JfzV/gdOnRg06ZNVFS4nzzJZF6zZs3o0KFDtsPIuERlDLdXoc8s/SLu+ruGd0n6vBeaN21CVXVtzPVuWX09/+V8wi8uLo45stUYP3hRxkhWTnFTbkm3rLQzRrKPXp/sGH60bprMyvmEb0w2eXGjiyKRmEk9NH2AALFSfqja4kV3TLL34fYYVl/Pbzlfwzcmm7wYgXpO34MSrm+xR1HM50PrveiOSfY+bIRrYbArfGMS8KKMEarDx+vCqfoxEPN1ofVelJWSvQ8b4VoYLOEbk0SyMoab+vpdw7vE/QI2WbnFq/unJnofbo9h9+bNb1bSMSYNXrRtJiu35MrEZnZv3vxnCd+YNHhR+042ujRX7tFqdf78ZyUdY9LgVe27bMM2vqzchQJfVu6ibMM237tjkh3D6vz5z67wjUmDF6NP/Rhp6wUbaZv/LOEbkwYv6uuJRtrmErvfbP6zko4xafCibdOPkbZe7MNG2uY/S/jGpCnd+nqykbhejLT1ai57G2mb36ykY0yWJRuJ68c9bU1hsCt8k9fOe+Qdlny6rW65/2GteXrcsXXLbsoYFVUVXPDaBTx58pO0bd42I3EmiiPZSFw/7mnrlg28ym9xE76IvOTi9dtUdax34RjjXnSyB1jy6TbOe+Qdnh53rOsyxpTVU9j8/eaM3ezeTRyJRuK2alHMN1XVMde75cVoXT9ucWgyK1FJ56fAAwkefwR6ZzpAY+KJTvbR692UMSqqKnjxkxdRlDmfzOHrnV97Hme65ZR49/5J5Z5AXnTYWFko/yUq6dykqm8kerGI3J7k+c+B74AAUOP2zurGeMFNGWPK6inUqjMnfK3WZuQqP91ySuXOhlf3idbH4kWHjQ28yn9xr/BVdWayF7vZBhisqqWW7E2q5qzYTP/JCzhkwiv0n7wg5Tlbkg0Uqqiq4IWP51Bd6yTO6tpqZn082/Or/HQHLHk14Gl49xLmXNWFo3r/jRev7ppyGcYGXuW/pF06ItJLRGaLyHIRWS0ia0RktR/BmcLlZqKu/oe1jvna0PpkZYwb5j9AdSCyRFEdCHDD/Ac8fCcw+Kh2Ka2P5uWAp/DvK1JlA6/yn5u2zKeBacBZwGnAqcGfbigwT0TKRWT87oVoCpGbevHT445tkPTDu3SSTQhWVvEW0iTyGNIkwHtfvenpe1n4Yez7McdbH82rydPS/b7Cj0ncTGa5acusUFU3HTux9FfVLSLSHviniHyoqovDNwj+IRgPcPDBB+/mYUw+StTi57ZeHN6CGUuigULffTwx4a0F3cTpRihmafotLTpOoerzy9FAy5RvYJJuYvXi+4rh3Uvof+QeGW9jNZnh5gr/VhF5VETOEZEzQw83O1fVLcGfXwGzgT4xtpmqqr1UtVe7du4+4pr8l6xk40e92M0xvJgDPtQ+uUeb+UjxN+zRdn7Eej+Eru7Dv6/Y3a6kdMpCJrvcJPxfAaXAiTilnFBZJyER2UtEWoZ+B4YC7+9+qKYxSVayyZWbfnjRiqjqXN0XtypHRCluVYYUfZdSW2W6wq/uQ0JX+anwo43VZI6bhN8teAV+oar+Kvi4yMXr9gfeEpFVwDLgFVWdm1a0ptFIVrLxsl5cUVXBSbNOapCchncv4ayeJXVz1hSJcFbPyNKJm9JSsm6iyp3V7NFmPtQVkJQ92s5Pqa0yXYu+WFR3dR9SXVvNwi8WRqyLd65CYpWFTP5wU8N/V0SOVtV1qexYVdcD3XYvLNPYuRn56dVEXfFG0s5ZsZlZ5Zsj5qGfVb6ZXh1b1x03WZxuRp8e0PpHvmtVXvcFsTQJUNyqjNbVp6T93tyaP2q+q+0SjTqOVxa6rNtlVsvPE26u8I8DVorIR9aWabziV4tfohKEm3JNsjjd7OOnP10KDb4eVo4+emka78x7yco1XpWFTPa4SfgnAofj1OBTbcs0Jia/WvwSlSDclGuSxelmHxt2vRez/fPznct26z1lSrJyjduykMldbko6PwHWqup3AMEvYo8GNmQyMNP4ZXpu9WQlCLcTig3vXsJRB3/HmFfGMO3UmRzRuiRi22T7CJVT/JiVM5l4Mbgp17gtC+XC+zSxubnCfwj4Pmx5R3CdMTktWQkilbLShDcnENAA1y++PmJ9KvvIhXbGeDF4Wa7JhfdpYnOT8EW1voFMVWuxefRNHkhWgnBbVvpw64d8WvkpAJ9WfsrH2z6ue87tPnKhnTFRDF6Va3LhfZr4RJM0A4vIC8Ai6q/qr8CZEG2418H06tVLy8rKvN6tMWkZPmd4XcIHOGzfw5gzfE5K+7jz3TuZ/e/ZVNdWU9ykmDMPPzPlUa5uSiWJtvEihmT8OIaJJCLlbiendHOFfxnQD9gMbAL6EpwKwZjGLvzqPiT6Kj8Zr0a5uimVxNvGy5G28fhxDJOepAlfVb9S1TGq2l5V91fVc4NTJRjT6E14c0LM9dG1/ES8qI+7KZUk2saPlkpr28x9cRO+m9ktbQZM76U7B7yfko3K9GIfXhwjmQ+3fkjpE6Uxr9o/+/azmK+JXp8oTi9GuboZ4ZpoGz9aKq1tM/fFreGLyHrgd4leC9yhqsd4FUyh1/CjR22C0/GRq1PQ3vnunTz30XOMPnL0btdpk+3Di2MkE6rRx6rNV1RVcNILJ/FD4Ie6dXsW7cncs+ZG1MgzeS7cxOA2TtP4eFXDf4P6ydJiPU4F/pleqCZcPt0z1ItujGT78KPjI1EHDrgrU2T6XLiJwcopxo1Etzj8lYvHNX4G29jl0z1DvZhEK9k+/JioK7pGH12bd1OmyPS5cBODlVOMG0nbMv1U6CWd/pMXxBy1WdKqOUsmHJ+FiGJLpXyQaGRnon34UaL4cOuHjHp5VIP1s06bxRGtj3C1Dz/ORSqStW7aKNjGx+u2TOOTfLlnaCrlg90d2elHicLvDpxcGOVqo2ALmyX8HJIv9wxNpetkd0d2+lGicNuBk4gf58KtXPhOxOQ2NyNt98S5gXknwqZUUNU7vA6m0Es6jU0hjbpMVipxcy7SLbckO0Yh/XsUEq9LOi8CZwA1OBOnhR7GxFVooy4TlUrcnot0yi3JjlFo/x4mNjcJv4Oqnq2q96nqA6FHxiMzea2Q2gS9uHFIuuWWXPhOxOQ+Nwn/bRHpkvFITKPi1T1UE42CdSvTo3W9uHFIuq2dufCdiMl9iUbarsG5L1tTnDterQd+wBlhq6ra1etgrIZfeJKNUE00CtarY6TDi5ZKGyVr0uFVDT90K8OTgP+D3eLQeCxZGSPZKFgvjpEuL0olVm4xfkk00naDqm4A7gr9Hr7OvxBNY5WsjJFsFKwXx0iXF6USK7cYv7hpy1yuqj3ClouANap6tNfBWEmncCQrY6QyCtaPEazG5CpPSjoiMlFEvgO6isi3wcd3wFc4rZrG7LZkZYxURsH6MYLVmMYgUUnnHlVtCdyvqvsEHy1VtY2qTnR7ABEpEpEVIvKyJxGbRiFZGSOVeegzPYLVmMbCTVvmcyLSI+pxmIi4vZH51cAHacRo8li8tsr5o+Yz+sjRFDcpBqC4STFnH3k280fNB2DVBatiPr/qglUR+5myegqBWmdK6UBtIOLqff6o+ay5cE2DR+gYIW7aNv24EYsxmeYm4f8/4F1gKvBI8PdngY9FZGiiF4pIB+AU4NE04zR5asKbEwhooEEpxouRoaFtarQGgBqt8f1escbkEzcJ/3Ogu6r2UtWeQCnwPvAL4L4kr30QuB6oTbKdaYQStVV6MTI0/Oo+JPoqP5l07xVrTD5xk/CPUtW1oQVVXYfzB2B9oheJyKnAV6panmS78SJSJiJlFRUVroI23sh0mSJRW6UXI0MXfbGo7uo+pEZrUqrRp3uvWGPyiZu2zBnANpwyDsDZQFvgfOAtVe0d53X3BLepAZoB+wAvqOov4x3L2jL9lckRqG7bKtOJId22S7tXrGkMvJ4tcyzwCXANcC3OFAtjgWpgcLwXqepEVe2gqp2AMcCCRMne+CvTZQo3bZVeTBgW0KiSjrov6di9Yk2hSZrwVXVncIbMEao6XFX/oKpVqlqrqt/7EaTxXqbLFG7aKr2YMKymNqqkU+u+pGP3ijWFxk1Jpz9wG9CRyBugHOp1MFbS8YefZYpMjoK1cosx3pd0HgP+CBwH9A57mDzlZ5kik6NgrdxiTGrcJPxKVX1NVb9S1a2hR8YjMxnjV5ki06NgrdxiTGrclHQmA0XACzjz4QOgqsu9DsZKOo3Lne/eyQsfv0CN1tBUmnLWEWfZPVSN8VgqJR030yP0Df4M36ECx6camCkc8UbBXtbtMquvG5MlSRO+qsZtvTQmnkSjYO0q35jsSFrDF5H9ReQxEXktuHy0iFyc+dBMPnM7CtYmJTPGP26+tJ0OvA4cGFz+GGcQljFxPXvKs+xZtGfEuj2L9mTGqTMi1tmkZMb4x03Cb6uqMwlOgKaqNUAg8UtMoXPTMmmTkhnjLzcJf4eItMH5ohYR+RlQmdGoTN5z0zJpk5IZ4y83XTq/AV4CDhORJUA7YGRGozJJxRvBmiuibzISLd5899FdPLn+Po3JJ27m0lkODAT6AZcCx6jq6kwHZhLL99q321Gy+f4+jckliW5ifmboAZwOHAkcAZwWXGeypDHUvt2UfBrD+zQmlyQq6ZyW4DnFGXlrsiBW7TvfetuTlXygcbxPY3JJ0qkV/GRTKyRXKDNEFsr7NCZdXs+WaXJIocwQWSjv0xg/WcLPQYlGnxbKDJGF8j6N8ZObtkzjs/DOlOiadaj2ncn70eYCNzV+Y0xqXHXpxHr4GWQhcdOZYt0rxpjdkaikc1qCx6mZD60wuRl9aiNUjTG7w7p0coibzhTrXjHGhPO8S0dEThGR60XkltAjvRBNLG46U6x7xRizu9zMhz8FOBv4NSDAKKBjhuMqSG46U6x7xRizu9zc03a1qnYN+7k38IKqDvU6mEIv6RhjTKq8LunsDP6sEpEDgWrgkN0NzhhjTHa46cN/WURaAfcDy3Hm0Xk0o1EZY4zxnJsr/PtUdbuqzsKp3R8F3JXsRSLSTESWicgqEVkrIrenG6xxz+4Va4yJ5ibhvxP6RVV/UNXK8HUJ/AAcr6rOZtyrAAATZ0lEQVTdgFLgxODdsowPbB55Y0y0RCNtDxCRnkBzEekuIj2Cj0FAi2Q7Vsf3wcXi4CN3mv4bMRuJa4yJJdEV/jDgD0AH4I/AA8HHtcCNbnYuIkUishL4Cvinqi6Nsc14ESkTkbKKiopU4zcx2EhcY0wsbtoyzwrW73f/IM6XvrOBX6vq+/G2s7bM9NlIXGMKi9dtmUtE5DEReS2486NF5OJUAlLV7cAi4MRUXmdSZyNxjTHxuEn404DXgQODyx8D1yR7kYi0C17ZIyLNgV8AH+5mnMYlG4lrjInHTR9+W1WdKSITAVS1RkQCLl73E+BxESnC+cMyU1VfTiNW44LNI2+MicdNwt8hIm0IdtgEWysrk71IVVcD3dMLzxhjjFfcJPzfAC8Bh4nIEqAdMDKjURljjPFc0oSvqstFZCBwJM5smR+panWSlxljjMkxSRO+iDQDrgCOwynrvCkiU1R1V6aDM8YY4x03JZ0ngO+AvwaXzwGexJkX3xhjTJ5wk/CPDM6HE7JQRFZlKiBjjDGZ4aYPf0X4pGci0hdYkrmQjDHGZIKbK/y+wAUisjG4fDDwgYiswZkjrWvGojPGGOMZNwnfpkMwxphGwE1b5gY/AjHGGJNZbmr4xhhjGgFL+MYYUyAs4RtjTIGwhG+MMQXCEr4xxhQIS/jGGFMgLOEbY0yBsIRvjDEFwhK+McYUCEv4xhhTICzhG2NMgbCEb4wxBcISvjHGFAhL+MYYUyAs4RtjTIHIWMIXkYNEZKGIfCAia0Xk6kwdyxhjTHJu7ni1u2qA36rqchFpCZSLyD9VdV0Gj2mMMSaOjF3hq+p/VHV58PfvgA+AkkwdzxhjTGK+1PBFpBPQHVga47nxIlImImUVFRV+hJNdqomX8+UYxpi8k/GELyJ7A7OAa1T12+jnVXWqqvZS1V7t2rXLdDjZtfAemDuxPgGrOssL78mvYxhj8lJGE76IFOMk+6dV9YVMHivnqcKuSlj6UH1CnjvRWd5V6c1VuB/HMMbkrYx9aSsiAjwGfKCqf8zUcfKGCJwYvMpe+pDzAOh7ubNeJD+OYYzJW5m8wu8PnA8cLyIrg4+TM3i83BeekEO8TsR+HMMYk5cy2aXzlqqKqnZV1dLg49VMHS8vhEos4cLr7flyDGNMXrKRtn4Jr6f3vRxu3e78DK+358MxQmprEy97wbqNjPFUJgdemXAi0GzfyHp6qPTSbF/vavhfroYDusCwu53lYXfDhrec9V6VdaadDD98C+MXQ5MmTrKfOgD23Ad+5dGHuIX3OF80h85V6I9Zs31h8MTkrzfGNGBX+H4aPDGynh5K+l4lMFU4oCt8uQZev9FZfv1GZ/mArt5cIdfWOsn+yzVOkg8l+y/XOOu9uNK3biNjMkI0h/7n6dWrl5aVlWU7jPwWnhxDvO7SCU/yIQd0qb/i94If78OYRkBEylW1l5tt7Qrfa8nqzl7UvgOB+MuhMk64UHnHK02aOMk9nJfJHqzbyJgMsITvpWSjXKedXF8Ggfor5WkpdKv+qTM8cHh9kg8EnOU/dQ7GcLezz3BTBzjrvRKKO/oYXn5xa91GxnjOEr5XktWdA4H0a9+BAFRXQdXW+qT/wOHOcnUVVFfDR68Ga/Zd4JZvnJ9frnHWe5GQw+OOPoZXSd/PbiNjCoh16aRCNbKkEL7sZpTr+MX1yfKO/Zzno2vftbWRpZHw5aIi+O2/65P8na2d9S3aOOuLiuCIk524wo+xf2dnfbz9xlqO916bNHG6cdp3ro97/GKY8nNnvRdlnbqOpsuiOprUu44mYwqQXeG75WZSsmR152S1bzcln8X3wdFnRe7j6LOc9QCr/gHfbol8/tstzvqQZMdx9V6jzk8mcnD0hbxd2BuTFkv4brhtE0xWd05U+3bT7qgKO7ZB2dTIfZRNddbX1MCPO2Dntsjnd25z1gcCyY8TCLgrTf33/cjX//d979syl02JjGHZFGvLNCYNhdWWmagk4+a1r94A7z1cv673pXDyvZEDg0J15xPviVweOgkeGVhf+w4v74SWAR7+uZM8Q/bvDJe+6XwKCK/ZR2vRBn7zMcy7EZY93PD5PpfCScFYa2vh4QHw37C2yv27wKXBTxvJWiLdtmWme76tLdOYpKwtM5Z054mffgp88Xbkui/edtZD/JG0fS931hcVwTcboGkzuGSRkxgvWeQsf7PBWX781NjHDq0vKoIfvgMpinxeguubNnW+nG3eOvL55q2d9aFE+ca90LFf5DYd+znrQ+8lndIUpH++rS3TGM8VRsJPd+RmeBkkXHSHTaKRtLW1sF9HqNkFjw5ylh8d5Czv19Epx+yqjLy6B2d5V2V92aftkaBRffgacNbX1MAeLWOXdPZoWV8W2vlNw08Byx521qumV5oCb0bKWlumMZ4rjC6ddOeJF4GD+jVM+OCsD3999L6ir4rjdem4fR8d+0WWYkJCV+w7/hv7tTv+W58sN7wde5sNbztJe95NsUtTkLg0NXVA/ZV+Ouc7UXkM7ErfmN1UGFf44CSIoZMi1w2d1LDGHC60LAIt9nNq9uF6X+qsd7MPSFwKadLEKf3s3zny+f07O+ubNHGO03w/6D0+Ko7xzvqmTaG4hVPPD9eijbO+qCh4nH2cmn3Ecbo464uKkpem9gy+Prwtc/8ukW2Z6Yz4TVYes2RvzG4pnIQ/7WTnC89wDxzuvhVx4A2xa/gDb6hfTraPZKWQC1+OHXv4eq2FtbMin187y1kPcPVq2Gv/yOf32t9ZHzL2ldg1/LGvOL8nm+St08+d7cOf79jPWV93LtIc8ZvpieaMKUCFkfADAaj40OluadEGbt7m/Kza6qwP1c8TtSImG13qZqRton3U1NS3N4Y/H97+GAhA2WOx30fZY85I26kDoGJd5D4q1kXGOXeiU7MPH8W67OHIP1bxSlN1LZMPR7VMPlxfn6+t9WbEb7wYjDG7pTBq+EVF0PNiKH+s4QjVnhc7pZBkNec994lsPQzVrsPLGOnso2lTd8doexR8/WHD99H2KCgudrePdObld/N9iIgzshcafl8RPeI3Xem0fhpTYAqrDz8QqE+S4FwhF4W1OKrC7a3ql2/dHpk8kk1H4MU+ki0vvAeqtsF7YYOveo+HFq3ryx1u40wnUSZ7n6HjhpI9OFf6XiZ7u0mKMdaHH1NtrdNdEu6RgZGthMnaAKOTVawkmu4+Ei2rws7tkckenOWd2+uPk2yfkF65xM37DN18JVzopixesJukGJOyxpPwE3XHJJvhMRBIf3ZGv2Z4jJeX/apiuHmffpyL8M6dpQ85nzbC2zitrGNMA42jhp/so31ohsd4te14rYjgvg3Qr3vWNmvlzCK5dEr9+r6XOev9SHJu32emz0UolhPviZx+wZK9MXHlfw0/2Rw24Qlgd6cETjWeTH6JqAqvTXAmEgvpcxmcNNnfROfmffpxLmy+HVPgUqnh5/8VfiqjaJPVtr1oA8xkK2H4rJHRf9xC58GvROfmffpxLmw0rjGuZSzhi8jfgVOBr1S1c7Lt0zyYPx/ts90C6EfZKF/YuTAmZRkr6YjIAOB74Am3CX+32zL9+GifSy2A2f7Dk0vsXJgClxNtmaq6GNiWdMP0D5T5jpBcawG0Eaj17FwY41rjqOH70R2TzuyPxhiTAzLapSMinYCXE5V0RGQ8MB7g4IMP7rlhw4bdO5gfH+3djC41xhgf5URJxy1VnaqqvVS1V7t27XZ/R5n+aG835DDG5LmsJ/y84NcoWmOMyaBMtmU+AwwC2orIJuBWVX0sU8fLKGsBNMY0Avk/0tZP1gJojMkxeVXDzyvWAmiMyWOW8I0xpkBYwjfGmAJhCd8YYwqEJXxjjCkQlvCNMaZA5FRbpohUALs5t4Kn2gJfZzsIFyxO7+RDjGBxeq0xxNlRVV1NU5BTCT9XiEiZ277WbLI4vZMPMYLF6bVCi9NKOsYYUyAs4RtjTIGwhB/b1GwH4JLF6Z18iBEsTq8VVJxWwzfGmAJhV/jGGFMgCj7hi0iRiKwQkZdjPDdWRCpEZGXwcUmWYvxcRNYEY2gwnag4/iIin4jIahHpkYMxDhKRyrBzeYvfMQbjaCUiz4vIhyLygYgcG/V81s+lyzizfj5F5Miw468UkW9F5JqobbJ+Pl3GmfXzGYzjWhFZKyLvi8gzItIs6vk9RWRG8HwuDd5V0LX8v6dt+q4GPgD2ifP8DFW90sd44hmsqvH6cE8CDg8++gIPBX/6LVGMAG+q6qm+RRPbn4G5qjpSRPYAWkQ9nyvnMlmckOXzqaofAaXgXDgBm4HZUZtl/Xy6jBOyfD5FpAS4CjhaVXeKyExgDDA9bLOLgW9U9f+IyBjgXuBst8co6Ct8EekAnAI8mu1Y0nQG8IQ63gVaichPsh1UrhGRfYABwGMAqvqjqm6P2izr59JlnLlmCPCpqkYPnMz6+YwSL85c0RRoLiJNcf7Ib4l6/gzg8eDvzwNDRNzP017QCR94ELgeqE2wzVnBj6LPi8hBPsUVTYF5IlIevOl7tBLgi7DlTcF1fkoWI8CxIrJKRF4TkWP8DC7oUKACmBYs4z0qIntFbZML59JNnJD98xluDPBMjPW5cD7DxYsTsnw+VXUz8AdgI/AfoFJV50VtVnc+VbUGqATauD1GwSZ8ETkV+EpVyxNs9r9AJ1XtCvyL+r+sfuuvqj1wPh7/XxEZEPV8rL/wfrdfJYtxOc4Q8G7AX4E5PscHztVTD+AhVe0O7AAmRG2TC+fSTZy5cD4BCJacTgeei/V0jHVZaQ1MEmfWz6eI7IdzBX8IcCCwl4j8MnqzGC91fT4LNuED/YHTReRz4FngeBF5KnwDVd2qqj8EFx8BevobYl0cW4I/v8KpPfaJ2mQTEP7powMNPwpmVLIYVfVbVf0++PurQLGItPUzRpzztElVlwaXn8dJrNHbZPVc4iLOHDmfIScBy1X1vzGey4XzGRI3zhw5n78APlPVClWtBl4A+kVtU3c+g2WffYFtbg9QsAlfVSeqagdV7YTzMW+Bqkb8NY2qNZ6O8+Wur0RkLxFpGfodGAq8H7XZS8AFwY6In+F8FPxPLsUoIgeEao0i0gfnv72tfsUIoKpfAl+IyJHBVUOAdVGbZfVcuo0zF85nmHOIXybJ+vkMEzfOHDmfG4GfiUiLYCxDaJhzXgIuDP4+Eidvub7Cty6dKCJyB1Cmqi8BV4nI6UANzl/RsVkIaX9gdvC/xabAP1R1rohcBqCqU4BXgZOBT4Aq4Fc5GONI4HIRqQF2AmNS+Q/VQ78Gng5+vF8P/CrHzqXbOHPifIpIC+AE4NKwdTl3Pl3EmfXzqapLReR5nPJSDbACmBqVkx4DnhSRT3By0phUjmEjbY0xpkAUbEnHGGMKjSV8Y4wpEJbwjTGmQFjCN8aYAmEJ3xhjCoQlfNMoBWc/jDUDasz1HhxvuIgcHba8SEQS3oNU6mdofNWD4zcXZ5bHH7M4AMvkOEv4xnhjOHB00q0aelNVT0734Kq6U1VLyd4oVpMHLOGbrAiOzn0lOFnV+yJydnB9TxF5IzgJ2+uh0c7BK+YHReTt4PZ9guv7BNetCP48MtFxY8TwdxF5L/j6M4Lrx4rICyIyV0T+LSL3hb3mYhH5OBjPIyLyNxHphzMS+/7gVfZhwc1Hiciy4PY/dxnT9eLcV2CViEwOe+9/EpHF4syN3zsY379F5C6379cYG2lrsuVEYIuqngIgIvuKSDHOxFVnqGpF8I/AJOCi4Gv2UtV+4kzM9negM/AhMEBVa0TkF8DdwFkuY7gJZ2j6RSLSClgmIv8KPlcKdAd+AD4Skb8CAeBmnHltvgMWAKtU9W0ReQl4WVWfD74fgKaq2kdETgZuxZkrJS4ROQnnk0JfVa0SkdZhT/+oqgNE5GrgRZx5nbYBn4rIn1Q1W9MqmDxiCd9kyxrgDyJyL06ifFNEOuMk8X8GE2YRzjSxIc8AqOpiEdknmKRbAo+LyOE4swYWpxDDUJwJ9H4XXG4GHBz8fb6qVgKIyDqgI9AWeENVtwXXPwcckWD/LwR/lgOdXMTzC2CaqlYBhI4T9FLw5xpgbWg+GhFZjzOZliV8k5QlfJMVqvqxiPTEmWflHhGZhzPL5lpVPTbey2Is3wksVNUR4tzubVEKYQhwVvCOSPUrRfriXNmHBHD+X3F9o4mg0D5Cr3cTT7y5TkL7qo2Krdblvo2xGr7JDhE5EKhS1adwbvrQA/gIaCfB+7eKSLFE3ogiVOc/DmfWxUqc6WE3B58fm2IYrwO/Ds5MiIh0T7L9MmCgiOwnztS04aWj73A+baRjHnBRcKIvoko6xqTNEr7Jli44NfOVOLX0u1T1R5xZC+8VkVXASiLnA/9GRN4GpuDc2xPgPpxPCEtwSkCpuBOnBLRaRN4PLscVvCPR3cBSnBvirMO54xA491S4Lvjl72FxdpGQqs7FKd2UBc/L75K8xJiU2GyZJi+IyCLgd6paluU49lbV74NX+LOBv6tqrBtiu9nXIJz35NmNs8W5oU8vTXwzeVOg7ArfmNTcFrz6fh/4jPRuhfcj0NnLgVc4n1gS3aPZFDC7wjfGmAJhV/jGGFMgLOEbY0yBsIRvjDEFwhK+McYUCEv4xhhTICzhG2NMgfj/x/4u12cipAEAAAAASUVORK5CYII=\n",
164 | "text/plain": [
165 | ""
166 | ]
167 | },
168 | "metadata": {
169 | "needs_background": "light"
170 | },
171 | "output_type": "display_data"
172 | }
173 | ],
174 | "source": [
175 | "import matplotlib.pyplot as plt\n",
176 | "%matplotlib inline\n",
177 | "\n",
178 | "# Break up the data frame and graph each species separately. \n",
179 | "species = df.species.unique()\n",
180 | "markers = ['o', 'x', '^']\n",
181 | "for i in range(3):\n",
182 | " df_segment = df[df['species'] == species[i]]\n",
183 | " plt.scatter('sepal_length', \n",
184 | " 'petal_length', \n",
185 | " data=df_segment, \n",
186 | " marker=markers[i],\n",
187 | " label=species[i])\n",
188 | "# Add proper labels and show the result. \n",
189 | "plt.xlabel('sepal length [cm]')\n",
190 | "plt.ylabel('petal length [cm]')\n",
191 | "plt.legend(loc='upper left')\n",
192 | "plt.show()"
193 | ]
194 | },
195 | {
196 | "cell_type": "markdown",
197 | "metadata": {},
198 | "source": [
199 | "From this we can see that iris-setosa is linearly separable from the other two species. This is significant for running machine learning. \n",
200 | "\n",
201 | "One final note is that when you don't know what's coming back it's good to describe the data set to ensure the values you think are numeric actually are. For example ClickHouse Decimal values don't automatically coerce to floats which means data science stack operations won't work as expected. "
202 | ]
203 | },
204 | {
205 | "cell_type": "code",
206 | "execution_count": 4,
207 | "metadata": {},
208 | "outputs": [
209 | {
210 | "data": {
211 | "text/html": [
212 | "\n",
213 | "\n",
226 | "
\n",
227 | " \n",
228 | " \n",
229 | " | \n",
230 | " sepal_length | \n",
231 | " sepal_width | \n",
232 | " petal_length | \n",
233 | " petal_width | \n",
234 | "
\n",
235 | " \n",
236 | " \n",
237 | " \n",
238 | " | count | \n",
239 | " 150.000000 | \n",
240 | " 150.000000 | \n",
241 | " 150.000000 | \n",
242 | " 150.000000 | \n",
243 | "
\n",
244 | " \n",
245 | " | mean | \n",
246 | " 5.843333 | \n",
247 | " 3.057333 | \n",
248 | " 3.758000 | \n",
249 | " 1.199333 | \n",
250 | "
\n",
251 | " \n",
252 | " | std | \n",
253 | " 0.828066 | \n",
254 | " 0.435866 | \n",
255 | " 1.765298 | \n",
256 | " 0.762238 | \n",
257 | "
\n",
258 | " \n",
259 | " | min | \n",
260 | " 4.300000 | \n",
261 | " 2.000000 | \n",
262 | " 1.000000 | \n",
263 | " 0.100000 | \n",
264 | "
\n",
265 | " \n",
266 | " | 25% | \n",
267 | " 5.100000 | \n",
268 | " 2.800000 | \n",
269 | " 1.600000 | \n",
270 | " 0.300000 | \n",
271 | "
\n",
272 | " \n",
273 | " | 50% | \n",
274 | " 5.800000 | \n",
275 | " 3.000000 | \n",
276 | " 4.350000 | \n",
277 | " 1.300000 | \n",
278 | "
\n",
279 | " \n",
280 | " | 75% | \n",
281 | " 6.400000 | \n",
282 | " 3.300000 | \n",
283 | " 5.100000 | \n",
284 | " 1.800000 | \n",
285 | "
\n",
286 | " \n",
287 | " | max | \n",
288 | " 7.900000 | \n",
289 | " 4.400000 | \n",
290 | " 6.900000 | \n",
291 | " 2.500000 | \n",
292 | "
\n",
293 | " \n",
294 | "
\n",
295 | "
"
296 | ],
297 | "text/plain": [
298 | " sepal_length sepal_width petal_length petal_width\n",
299 | "count 150.000000 150.000000 150.000000 150.000000\n",
300 | "mean 5.843333 3.057333 3.758000 1.199333\n",
301 | "std 0.828066 0.435866 1.765298 0.762238\n",
302 | "min 4.300000 2.000000 1.000000 0.100000\n",
303 | "25% 5.100000 2.800000 1.600000 0.300000\n",
304 | "50% 5.800000 3.000000 4.350000 1.300000\n",
305 | "75% 6.400000 3.300000 5.100000 1.800000\n",
306 | "max 7.900000 4.400000 6.900000 2.500000"
307 | ]
308 | },
309 | "execution_count": 4,
310 | "metadata": {},
311 | "output_type": "execute_result"
312 | }
313 | ],
314 | "source": [
315 | "import pandas\n",
316 | "df.describe()"
317 | ]
318 | },
319 | {
320 | "cell_type": "code",
321 | "execution_count": null,
322 | "metadata": {},
323 | "outputs": [],
324 | "source": []
325 | }
326 | ],
327 | "metadata": {
328 | "kernelspec": {
329 | "display_name": "Python 3",
330 | "language": "python",
331 | "name": "python3"
332 | },
333 | "language_info": {
334 | "codemirror_mode": {
335 | "name": "ipython",
336 | "version": 3
337 | },
338 | "file_extension": ".py",
339 | "mimetype": "text/x-python",
340 | "name": "python",
341 | "nbconvert_exporter": "python",
342 | "pygments_lexer": "ipython3",
343 | "version": "3.7.1"
344 | }
345 | },
346 | "nbformat": 4,
347 | "nbformat_minor": 2
348 | }
349 |
--------------------------------------------------------------------------------
/notebooks/EX-5-Airline-OnTime-Data.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Graphing Airline Ontime Data\n",
8 | "\n",
9 | "This notebook shows how to create a time-series graph from airline ontime data, which can be downloaded from the [US Bureau of Transportation Statistics](https://www.transtats.bts.gov/tables.asp?DB_ID=120). See https://github.com/Altinity/altinity-datasets for tools to help with loading. "
10 | ]
11 | },
12 | {
13 | "cell_type": "markdown",
14 | "metadata": {},
15 | "source": [
16 | "First import SQLAlchemy and activate the %sql function. This just needs to be done once. "
17 | ]
18 | },
19 | {
20 | "cell_type": "code",
21 | "execution_count": 1,
22 | "metadata": {
23 | "scrolled": true
24 | },
25 | "outputs": [],
26 | "source": [
27 | "from sqlalchemy import create_engine\n",
28 | "%load_ext sql"
29 | ]
30 | },
31 | {
32 | "cell_type": "markdown",
33 | "metadata": {},
34 | "source": [
35 | "Run a query using %%sql. This needs to go in a separate cell. "
36 | ]
37 | },
38 | {
39 | "cell_type": "code",
40 | "execution_count": 2,
41 | "metadata": {},
42 | "outputs": [
43 | {
44 | "name": "stdout",
45 | "output_type": "stream",
46 | "text": [
47 | "Done.\n"
48 | ]
49 | },
50 | {
51 | "data": {
52 | "text/html": [
53 | "\n",
54 | " \n",
55 | " | t | \n",
56 | " cancelled | \n",
57 | " delayed | \n",
58 | "
\n",
59 | " \n",
60 | " | 1987 | \n",
61 | " 0.015005801074227831 | \n",
62 | " 0.15847681018671683 | \n",
63 | "
\n",
64 | " \n",
65 | " | 1988 | \n",
66 | " 0.009642843961357115 | \n",
67 | " 0.13082207633230913 | \n",
68 | "
\n",
69 | " \n",
70 | " | 1989 | \n",
71 | " 0.014711774974212489 | \n",
72 | " 0.16047806077917956 | \n",
73 | "
\n",
74 | " \n",
75 | " | 1990 | \n",
76 | " 0.009952393266188481 | \n",
77 | " 0.1329419891468106 | \n",
78 | "
\n",
79 | " \n",
80 | " | 1991 | \n",
81 | " 0.008569163420771431 | \n",
82 | " 0.11384922960256455 | \n",
83 | "
\n",
84 | " \n",
85 | " | 1992 | \n",
86 | " 0.010375956593639985 | \n",
87 | " 0.11081983528787506 | \n",
88 | "
\n",
89 | " \n",
90 | " | 1993 | \n",
91 | " 0.011802581243944139 | \n",
92 | " 0.118570334568517 | \n",
93 | "
\n",
94 | " \n",
95 | " | 1994 | \n",
96 | " 0.012884050495284986 | \n",
97 | " 0.12803356262335794 | \n",
98 | "
\n",
99 | " \n",
100 | " | 1995 | \n",
101 | " 0.01725126632234837 | \n",
102 | " 0.1554094981919066 | \n",
103 | "
\n",
104 | " \n",
105 | " | 1996 | \n",
106 | " 0.024016518737073715 | \n",
107 | " 0.18197890389412671 | \n",
108 | "
\n",
109 | " \n",
110 | " | 1997 | \n",
111 | " 0.018064640825685447 | \n",
112 | " 0.15648458390237854 | \n",
113 | "
\n",
114 | " \n",
115 | " | 1998 | \n",
116 | " 0.02683685932845917 | \n",
117 | " 0.16164161522946127 | \n",
118 | "
\n",
119 | " \n",
120 | " | 1999 | \n",
121 | " 0.027915021371649622 | \n",
122 | " 0.1695536664662283 | \n",
123 | "
\n",
124 | " \n",
125 | " | 2000 | \n",
126 | " 0.03299110494775074 | \n",
127 | " 0.19912962183842575 | \n",
128 | "
\n",
129 | " \n",
130 | " | 2001 | \n",
131 | " 0.03874103938147854 | \n",
132 | " 0.1598262670540804 | \n",
133 | "
\n",
134 | " \n",
135 | " | 2002 | \n",
136 | " 0.012357913775176383 | \n",
137 | " 0.1360878665255013 | \n",
138 | "
\n",
139 | " \n",
140 | " | 2003 | \n",
141 | " 0.01595893603961728 | \n",
142 | " 0.13144318872073027 | \n",
143 | "
\n",
144 | " \n",
145 | " | 2004 | \n",
146 | " 0.01792006755249836 | \n",
147 | " 0.1665800285302703 | \n",
148 | "
\n",
149 | " \n",
150 | " | 2005 | \n",
151 | " 0.019069045573072995 | \n",
152 | " 0.18150869494248564 | \n",
153 | "
\n",
154 | " \n",
155 | " | 2006 | \n",
156 | " 0.01707299519653113 | \n",
157 | " 0.1994948978720294 | \n",
158 | "
\n",
159 | " \n",
160 | " | 2007 | \n",
161 | " 0.021569298626590076 | \n",
162 | " 0.210983416444704 | \n",
163 | "
\n",
164 | " \n",
165 | " | 2008 | \n",
166 | " 0.01960590185693421 | \n",
167 | " 0.18941510695282526 | \n",
168 | "
\n",
169 | " \n",
170 | " | 2009 | \n",
171 | " 0.013856286970265655 | \n",
172 | " 0.16836124295283075 | \n",
173 | "
\n",
174 | " \n",
175 | " | 2010 | \n",
176 | " 0.017558596223913456 | \n",
177 | " 0.1726871000944634 | \n",
178 | "
\n",
179 | " \n",
180 | " | 2011 | \n",
181 | " 0.019058774771452625 | \n",
182 | " 0.17160785179846255 | \n",
183 | "
\n",
184 | " \n",
185 | " | 2012 | \n",
186 | " 0.01293506290716285 | \n",
187 | " 0.16289138398382616 | \n",
188 | "
\n",
189 | " \n",
190 | " | 2013 | \n",
191 | " 0.015073753250264308 | \n",
192 | " 0.19332121513177994 | \n",
193 | "
\n",
194 | " \n",
195 | " | 2014 | \n",
196 | " 0.021819265264799836 | \n",
197 | " 0.2053970481171983 | \n",
198 | "
\n",
199 | " \n",
200 | " | 2015 | \n",
201 | " 0.015446430612129514 | \n",
202 | " 0.18173906901762288 | \n",
203 | "
\n",
204 | " \n",
205 | " | 2016 | \n",
206 | " 0.011723924809947491 | \n",
207 | " 0.16974030814976632 | \n",
208 | "
\n",
209 | " \n",
210 | " | 2017 | \n",
211 | " 0.01399881896870509 | \n",
212 | " 0.19478701373546048 | \n",
213 | "
\n",
214 | " \n",
215 | " | 2018 | \n",
216 | " 0.010669114159862703 | \n",
217 | " 0.17753310427890504 | \n",
218 | "
\n",
219 | "
"
220 | ],
221 | "text/plain": [
222 | "[(1987, 0.015005801074227831, 0.15847681018671683),\n",
223 | " (1988, 0.009642843961357115, 0.13082207633230913),\n",
224 | " (1989, 0.014711774974212489, 0.16047806077917956),\n",
225 | " (1990, 0.009952393266188481, 0.1329419891468106),\n",
226 | " (1991, 0.008569163420771431, 0.11384922960256455),\n",
227 | " (1992, 0.010375956593639985, 0.11081983528787506),\n",
228 | " (1993, 0.011802581243944139, 0.118570334568517),\n",
229 | " (1994, 0.012884050495284986, 0.12803356262335794),\n",
230 | " (1995, 0.01725126632234837, 0.1554094981919066),\n",
231 | " (1996, 0.024016518737073715, 0.18197890389412671),\n",
232 | " (1997, 0.018064640825685447, 0.15648458390237854),\n",
233 | " (1998, 0.02683685932845917, 0.16164161522946127),\n",
234 | " (1999, 0.027915021371649622, 0.1695536664662283),\n",
235 | " (2000, 0.03299110494775074, 0.19912962183842575),\n",
236 | " (2001, 0.03874103938147854, 0.1598262670540804),\n",
237 | " (2002, 0.012357913775176383, 0.1360878665255013),\n",
238 | " (2003, 0.01595893603961728, 0.13144318872073027),\n",
239 | " (2004, 0.01792006755249836, 0.1665800285302703),\n",
240 | " (2005, 0.019069045573072995, 0.18150869494248564),\n",
241 | " (2006, 0.01707299519653113, 0.1994948978720294),\n",
242 | " (2007, 0.021569298626590076, 0.210983416444704),\n",
243 | " (2008, 0.01960590185693421, 0.18941510695282526),\n",
244 | " (2009, 0.013856286970265655, 0.16836124295283075),\n",
245 | " (2010, 0.017558596223913456, 0.1726871000944634),\n",
246 | " (2011, 0.019058774771452625, 0.17160785179846255),\n",
247 | " (2012, 0.01293506290716285, 0.16289138398382616),\n",
248 | " (2013, 0.015073753250264308, 0.19332121513177994),\n",
249 | " (2014, 0.021819265264799836, 0.2053970481171983),\n",
250 | " (2015, 0.015446430612129514, 0.18173906901762288),\n",
251 | " (2016, 0.011723924809947491, 0.16974030814976632),\n",
252 | " (2017, 0.01399881896870509, 0.19478701373546048),\n",
253 | " (2018, 0.010669114159862703, 0.17753310427890504)]"
254 | ]
255 | },
256 | "execution_count": 2,
257 | "metadata": {},
258 | "output_type": "execute_result"
259 | }
260 | ],
261 | "source": [
262 | "%%sql clickhouse://default:@localhost/airline\n",
263 | "SELECT toYear(FlightDate) t, \n",
264 | " sum(Cancelled)/count(*) cancelled, \n",
265 | " sum(DepDel15)/count(*) delayed\n",
266 | "FROM airline.ontime GROUP BY t ORDER BY t"
267 | ]
268 | },
269 | {
270 | "cell_type": "markdown",
271 | "metadata": {},
272 | "source": [
273 | "Turn the result into a nice dataframe and prove it has some data in it. "
274 | ]
275 | },
276 | {
277 | "cell_type": "code",
278 | "execution_count": 3,
279 | "metadata": {},
280 | "outputs": [
281 | {
282 | "data": {
283 | "text/html": [
284 | "\n",
285 | "\n",
298 | "
\n",
299 | " \n",
300 | " \n",
301 | " | \n",
302 | " t | \n",
303 | " cancelled | \n",
304 | " delayed | \n",
305 | "
\n",
306 | " \n",
307 | " \n",
308 | " \n",
309 | " | 27 | \n",
310 | " 2014 | \n",
311 | " 0.021819 | \n",
312 | " 0.205397 | \n",
313 | "
\n",
314 | " \n",
315 | " | 28 | \n",
316 | " 2015 | \n",
317 | " 0.015446 | \n",
318 | " 0.181739 | \n",
319 | "
\n",
320 | " \n",
321 | " | 29 | \n",
322 | " 2016 | \n",
323 | " 0.011724 | \n",
324 | " 0.169740 | \n",
325 | "
\n",
326 | " \n",
327 | " | 30 | \n",
328 | " 2017 | \n",
329 | " 0.013999 | \n",
330 | " 0.194787 | \n",
331 | "
\n",
332 | " \n",
333 | " | 31 | \n",
334 | " 2018 | \n",
335 | " 0.010669 | \n",
336 | " 0.177533 | \n",
337 | "
\n",
338 | " \n",
339 | "
\n",
340 | "
"
341 | ],
342 | "text/plain": [
343 | " t cancelled delayed\n",
344 | "27 2014 0.021819 0.205397\n",
345 | "28 2015 0.015446 0.181739\n",
346 | "29 2016 0.011724 0.169740\n",
347 | "30 2017 0.013999 0.194787\n",
348 | "31 2018 0.010669 0.177533"
349 | ]
350 | },
351 | "execution_count": 3,
352 | "metadata": {},
353 | "output_type": "execute_result"
354 | }
355 | ],
356 | "source": [
357 | "result = _\n",
358 | "df = result.DataFrame()\n",
359 | "df.tail()"
360 | ]
361 | },
362 | {
363 | "cell_type": "markdown",
364 | "metadata": {},
365 | "source": [
366 | "Time to make a quick graph using matplotlib. I'm not the greatest at this but once you have a data frame everything is possible. "
367 | ]
368 | },
369 | {
370 | "cell_type": "code",
371 | "execution_count": 4,
372 | "metadata": {},
373 | "outputs": [
374 | {
375 | "data": {
376 | "image/png": "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\n",
377 | "text/plain": [
378 | ""
379 | ]
380 | },
381 | "metadata": {
382 | "needs_background": "light"
383 | },
384 | "output_type": "display_data"
385 | }
386 | ],
387 | "source": [
388 | "import matplotlib.pyplot as plt\n",
389 | "%matplotlib inline\n",
390 | "\n",
391 | "plt.plot('t', 'cancelled', \n",
392 | " data=df, linestyle='--', \n",
393 | " marker='o', label='Cancelled')\n",
394 | "plt.plot('t', 'delayed', \n",
395 | " data=df, linestyle='--', \n",
396 | " marker='o', label='Delayed')\n",
397 | "plt.xlabel('Year')\n",
398 | "plt.ylabel('Percentage')\n",
399 | "plt.legend(loc='upper left')\n",
400 | "plt.title('Fetch data the easy way')\n",
401 | "plt.show()"
402 | ]
403 | },
404 | {
405 | "cell_type": "markdown",
406 | "metadata": {},
407 | "source": [
408 | "The %sql magic function is great but we can also do the same thing using the clickhouse-driver client library and direct API calls. "
409 | ]
410 | },
411 | {
412 | "cell_type": "code",
413 | "execution_count": 5,
414 | "metadata": {},
415 | "outputs": [
416 | {
417 | "data": {
418 | "text/html": [
419 | "\n",
420 | "\n",
433 | "
\n",
434 | " \n",
435 | " \n",
436 | " | \n",
437 | " t | \n",
438 | " cancelled | \n",
439 | " delayed | \n",
440 | "
\n",
441 | " \n",
442 | " \n",
443 | " \n",
444 | " | 27 | \n",
445 | " 2014 | \n",
446 | " 0.021819 | \n",
447 | " 0.205397 | \n",
448 | "
\n",
449 | " \n",
450 | " | 28 | \n",
451 | " 2015 | \n",
452 | " 0.015446 | \n",
453 | " 0.181739 | \n",
454 | "
\n",
455 | " \n",
456 | " | 29 | \n",
457 | " 2016 | \n",
458 | " 0.011724 | \n",
459 | " 0.169740 | \n",
460 | "
\n",
461 | " \n",
462 | " | 30 | \n",
463 | " 2017 | \n",
464 | " 0.013999 | \n",
465 | " 0.194787 | \n",
466 | "
\n",
467 | " \n",
468 | " | 31 | \n",
469 | " 2018 | \n",
470 | " 0.010669 | \n",
471 | " 0.177533 | \n",
472 | "
\n",
473 | " \n",
474 | "
\n",
475 | "
"
476 | ],
477 | "text/plain": [
478 | " t cancelled delayed\n",
479 | "27 2014 0.021819 0.205397\n",
480 | "28 2015 0.015446 0.181739\n",
481 | "29 2016 0.011724 0.169740\n",
482 | "30 2017 0.013999 0.194787\n",
483 | "31 2018 0.010669 0.177533"
484 | ]
485 | },
486 | "execution_count": 5,
487 | "metadata": {},
488 | "output_type": "execute_result"
489 | }
490 | ],
491 | "source": [
492 | "import pandas\n",
493 | "from clickhouse_driver import Client\n",
494 | "\n",
495 | "client = Client('localhost', database='airline')\n",
496 | "result, columns = client.execute(\n",
497 | " 'SELECT toYear(FlightDate) t,'\n",
498 | " 'sum(Cancelled)/count(*) cancelled,'\n",
499 | " 'sum(DepDel15)/count(*) delayed '\n",
500 | " 'FROM airline.ontime GROUP BY t ORDER BY t', \n",
501 | " with_column_types=True)\n",
502 | "\n",
503 | "df2 = pandas.DataFrame(result, columns=[tuple[0] for tuple in columns])\n",
504 | "df2.tail()"
505 | ]
506 | },
507 | {
508 | "cell_type": "markdown",
509 | "metadata": {},
510 | "source": [
511 | "The graph looks just the same, so we change the title to tell them apart. "
512 | ]
513 | },
514 | {
515 | "cell_type": "code",
516 | "execution_count": 6,
517 | "metadata": {},
518 | "outputs": [
519 | {
520 | "data": {
521 | "image/png": "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\n",
522 | "text/plain": [
523 | ""
524 | ]
525 | },
526 | "metadata": {
527 | "needs_background": "light"
528 | },
529 | "output_type": "display_data"
530 | }
531 | ],
532 | "source": [
533 | "import matplotlib.pyplot as plt\n",
534 | "%matplotlib inline\n",
535 | "\n",
536 | "plt.plot('t', 'cancelled', data=df2, \n",
537 | " linestyle='--', marker='o', label='Cancelled')\n",
538 | "plt.plot('t', 'delayed', data=df2, \n",
539 | " linestyle='--', marker='o', label='Delayed')\n",
540 | "plt.xlabel('Year')\n",
541 | "plt.ylabel('Percentage')\n",
542 | "plt.legend(loc='upper left')\n",
543 | "plt.title('Fetch data the hard way')\n",
544 | "plt.show()"
545 | ]
546 | },
547 | {
548 | "cell_type": "markdown",
549 | "metadata": {},
550 | "source": [
551 | "That's all folks!"
552 | ]
553 | },
554 | {
555 | "cell_type": "code",
556 | "execution_count": null,
557 | "metadata": {},
558 | "outputs": [],
559 | "source": []
560 | }
561 | ],
562 | "metadata": {
563 | "kernelspec": {
564 | "display_name": "Python 3",
565 | "language": "python",
566 | "name": "python3"
567 | },
568 | "language_info": {
569 | "codemirror_mode": {
570 | "name": "ipython",
571 | "version": 3
572 | },
573 | "file_extension": ".py",
574 | "mimetype": "text/x-python",
575 | "name": "python",
576 | "nbconvert_exporter": "python",
577 | "pygments_lexer": "ipython3",
578 | "version": "3.7.1"
579 | }
580 | },
581 | "nbformat": 4,
582 | "nbformat_minor": 2
583 | }
584 |
--------------------------------------------------------------------------------
/notebooks/EX-2-ClickHouse-SQL-Alchemy.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# ClickHouse SQLAlchemy\n",
8 | "\n",
9 | "This notebook provides simple examples from the clickhouse-sqlalchemy driver including a demonstration of integration with pandas and matplotlib. "
10 | ]
11 | },
12 | {
13 | "cell_type": "markdown",
14 | "metadata": {},
15 | "source": [
16 | "Import SQLAlchemy + clickhouse-sqlalchemy entities."
17 | ]
18 | },
19 | {
20 | "cell_type": "code",
21 | "execution_count": 1,
22 | "metadata": {
23 | "scrolled": true
24 | },
25 | "outputs": [],
26 | "source": [
27 | "from sqlalchemy import create_engine, Column, MetaData, literal\n",
28 | "from clickhouse_sqlalchemy import Table, make_session, get_declarative_base, types, engines"
29 | ]
30 | },
31 | {
32 | "cell_type": "markdown",
33 | "metadata": {},
34 | "source": [
35 | "Initialize SQLAlchemy to use local server with native connectivity. If you leave off '+native' the driver will use http[s]. "
36 | ]
37 | },
38 | {
39 | "cell_type": "code",
40 | "execution_count": 2,
41 | "metadata": {},
42 | "outputs": [],
43 | "source": [
44 | "uri = 'clickhouse+native://default:@localhost/default'\n",
45 | "\n",
46 | "engine = create_engine(uri)\n",
47 | "session = make_session(engine)\n",
48 | "metadata = MetaData(bind=engine)\n",
49 | "\n",
50 | "Base = get_declarative_base(metadata=metadata)"
51 | ]
52 | },
53 | {
54 | "cell_type": "markdown",
55 | "metadata": {},
56 | "source": [
57 | "Define a class to represent sensor data from devices. "
58 | ]
59 | },
60 | {
61 | "cell_type": "code",
62 | "execution_count": 3,
63 | "metadata": {},
64 | "outputs": [],
65 | "source": [
66 | "class SensorData(Base):\n",
67 | " dev_id = Column(types.Int32, primary_key=True)\n",
68 | " type = Column(types.String)\n",
69 | " mdate = Column(types.Date)\n",
70 | " mdatetime = Column(types.DateTime, primary_key=True)\n",
71 | " value = Column(types.Float64)\n",
72 | "\n",
73 | " __table_args__ = (\n",
74 | " engines.MergeTree('mdate', ('dev_id', 'mdate')),\n",
75 | " )"
76 | ]
77 | },
78 | {
79 | "cell_type": "markdown",
80 | "metadata": {},
81 | "source": [
82 | "Drop and then recreate the SQL table. Ignore errors if the table does not exist previously. "
83 | ]
84 | },
85 | {
86 | "cell_type": "code",
87 | "execution_count": 4,
88 | "metadata": {},
89 | "outputs": [],
90 | "source": [
91 | "table = SensorData.__table__\n",
92 | "try:\n",
93 | " table.drop()\n",
94 | "except:\n",
95 | " # Exceptions are ignored\n",
96 | " pass\n",
97 | "table.create()"
98 | ]
99 | },
100 | {
101 | "cell_type": "markdown",
102 | "metadata": {},
103 | "source": [
104 | "Create sensor data for 5 mythical devices. Readings increase linearly from a base that is randomly selected for each device. "
105 | ]
106 | },
107 | {
108 | "cell_type": "code",
109 | "execution_count": 5,
110 | "metadata": {},
111 | "outputs": [
112 | {
113 | "data": {
114 | "text/plain": [
115 | ""
116 | ]
117 | },
118 | "execution_count": 5,
119 | "metadata": {},
120 | "output_type": "execute_result"
121 | }
122 | ],
123 | "source": [
124 | "from datetime import date, datetime, timedelta\n",
125 | "from random import random\n",
126 | "today = date.today()\n",
127 | "this_instant = datetime.today()\n",
128 | "data = []\n",
129 | "for i in range(5):\n",
130 | " base = random()\n",
131 | " for j in range(10): \n",
132 | " data.append({'dev_id': i, \n",
133 | " 'type': 'widget-a', \n",
134 | " 'mdate': today, \n",
135 | " 'mdatetime': this_instant + timedelta(minutes=j), \n",
136 | " 'value': base + j * 0.1})\n",
137 | "session.execute(table.insert(), data)"
138 | ]
139 | },
140 | {
141 | "cell_type": "markdown",
142 | "metadata": {},
143 | "source": [
144 | "Enable %sql magic function. "
145 | ]
146 | },
147 | {
148 | "cell_type": "code",
149 | "execution_count": 6,
150 | "metadata": {},
151 | "outputs": [
152 | {
153 | "data": {
154 | "text/plain": [
155 | "'Connected: default@default'"
156 | ]
157 | },
158 | "execution_count": 6,
159 | "metadata": {},
160 | "output_type": "execute_result"
161 | }
162 | ],
163 | "source": [
164 | "%load_ext sql\n",
165 | "%sql clickhouse://default:@localhost/default"
166 | ]
167 | },
168 | {
169 | "cell_type": "markdown",
170 | "metadata": {},
171 | "source": [
172 | "Prove that the magic function works by showing tables. %sql can handle any query. "
173 | ]
174 | },
175 | {
176 | "cell_type": "code",
177 | "execution_count": 7,
178 | "metadata": {},
179 | "outputs": [
180 | {
181 | "name": "stdout",
182 | "output_type": "stream",
183 | "text": [
184 | " * clickhouse://default:***@localhost/default\n",
185 | "Done.\n"
186 | ]
187 | },
188 | {
189 | "data": {
190 | "text/html": [
191 | "\n",
192 | " \n",
193 | " | name | \n",
194 | "
\n",
195 | " \n",
196 | " | airports | \n",
197 | "
\n",
198 | " \n",
199 | " | f | \n",
200 | "
\n",
201 | " \n",
202 | " | f_1 | \n",
203 | "
\n",
204 | " \n",
205 | " | f_long | \n",
206 | "
\n",
207 | " \n",
208 | " | iris | \n",
209 | "
\n",
210 | " \n",
211 | " | iris_from_csv | \n",
212 | "
\n",
213 | " \n",
214 | " | iris_remote | \n",
215 | "
\n",
216 | " \n",
217 | " | iris_url_local | \n",
218 | "
\n",
219 | " \n",
220 | " | iris_web | \n",
221 | "
\n",
222 | " \n",
223 | " | ontime | \n",
224 | "
\n",
225 | " \n",
226 | " | sdata | \n",
227 | "
\n",
228 | " \n",
229 | " | sensor_data | \n",
230 | "
\n",
231 | "
"
232 | ],
233 | "text/plain": [
234 | "[('airports',),\n",
235 | " ('f',),\n",
236 | " ('f_1',),\n",
237 | " ('f_long',),\n",
238 | " ('iris',),\n",
239 | " ('iris_from_csv',),\n",
240 | " ('iris_remote',),\n",
241 | " ('iris_url_local',),\n",
242 | " ('iris_web',),\n",
243 | " ('ontime',),\n",
244 | " ('sdata',),\n",
245 | " ('sensor_data',)]"
246 | ]
247 | },
248 | "execution_count": 7,
249 | "metadata": {},
250 | "output_type": "execute_result"
251 | }
252 | ],
253 | "source": [
254 | "%sql show tables"
255 | ]
256 | },
257 | {
258 | "cell_type": "markdown",
259 | "metadata": {},
260 | "source": [
261 | "Select all rows back and convert to a data frame. "
262 | ]
263 | },
264 | {
265 | "cell_type": "code",
266 | "execution_count": 8,
267 | "metadata": {},
268 | "outputs": [
269 | {
270 | "name": "stdout",
271 | "output_type": "stream",
272 | "text": [
273 | " * clickhouse://default:***@localhost/default\n",
274 | "Done.\n"
275 | ]
276 | },
277 | {
278 | "data": {
279 | "text/html": [
280 | "\n",
281 | "\n",
294 | "
\n",
295 | " \n",
296 | " \n",
297 | " | \n",
298 | " dev_id | \n",
299 | " type | \n",
300 | " mdate | \n",
301 | " mdatetime | \n",
302 | " value | \n",
303 | "
\n",
304 | " \n",
305 | " \n",
306 | " \n",
307 | " | 0 | \n",
308 | " 0 | \n",
309 | " widget-a | \n",
310 | " 2019-02-24 | \n",
311 | " 2019-02-24 00:03:59 | \n",
312 | " 0.470658 | \n",
313 | "
\n",
314 | " \n",
315 | " | 1 | \n",
316 | " 0 | \n",
317 | " widget-a | \n",
318 | " 2019-02-24 | \n",
319 | " 2019-02-24 00:04:59 | \n",
320 | " 0.570658 | \n",
321 | "
\n",
322 | " \n",
323 | " | 2 | \n",
324 | " 0 | \n",
325 | " widget-a | \n",
326 | " 2019-02-24 | \n",
327 | " 2019-02-24 00:05:59 | \n",
328 | " 0.670658 | \n",
329 | "
\n",
330 | " \n",
331 | " | 3 | \n",
332 | " 0 | \n",
333 | " widget-a | \n",
334 | " 2019-02-24 | \n",
335 | " 2019-02-24 00:06:59 | \n",
336 | " 0.770658 | \n",
337 | "
\n",
338 | " \n",
339 | " | 4 | \n",
340 | " 0 | \n",
341 | " widget-a | \n",
342 | " 2019-02-24 | \n",
343 | " 2019-02-24 00:07:59 | \n",
344 | " 0.870658 | \n",
345 | "
\n",
346 | " \n",
347 | " | 5 | \n",
348 | " 0 | \n",
349 | " widget-a | \n",
350 | " 2019-02-24 | \n",
351 | " 2019-02-24 00:08:59 | \n",
352 | " 0.970658 | \n",
353 | "
\n",
354 | " \n",
355 | " | 6 | \n",
356 | " 0 | \n",
357 | " widget-a | \n",
358 | " 2019-02-24 | \n",
359 | " 2019-02-24 00:09:59 | \n",
360 | " 1.070658 | \n",
361 | "
\n",
362 | " \n",
363 | " | 7 | \n",
364 | " 0 | \n",
365 | " widget-a | \n",
366 | " 2019-02-24 | \n",
367 | " 2019-02-24 00:10:59 | \n",
368 | " 1.170658 | \n",
369 | "
\n",
370 | " \n",
371 | " | 8 | \n",
372 | " 0 | \n",
373 | " widget-a | \n",
374 | " 2019-02-24 | \n",
375 | " 2019-02-24 00:11:59 | \n",
376 | " 1.270658 | \n",
377 | "
\n",
378 | " \n",
379 | " | 9 | \n",
380 | " 0 | \n",
381 | " widget-a | \n",
382 | " 2019-02-24 | \n",
383 | " 2019-02-24 00:12:59 | \n",
384 | " 1.370658 | \n",
385 | "
\n",
386 | " \n",
387 | " | 10 | \n",
388 | " 1 | \n",
389 | " widget-a | \n",
390 | " 2019-02-24 | \n",
391 | " 2019-02-24 00:03:59 | \n",
392 | " 0.308329 | \n",
393 | "
\n",
394 | " \n",
395 | " | 11 | \n",
396 | " 1 | \n",
397 | " widget-a | \n",
398 | " 2019-02-24 | \n",
399 | " 2019-02-24 00:04:59 | \n",
400 | " 0.408329 | \n",
401 | "
\n",
402 | " \n",
403 | " | 12 | \n",
404 | " 1 | \n",
405 | " widget-a | \n",
406 | " 2019-02-24 | \n",
407 | " 2019-02-24 00:05:59 | \n",
408 | " 0.508329 | \n",
409 | "
\n",
410 | " \n",
411 | " | 13 | \n",
412 | " 1 | \n",
413 | " widget-a | \n",
414 | " 2019-02-24 | \n",
415 | " 2019-02-24 00:06:59 | \n",
416 | " 0.608329 | \n",
417 | "
\n",
418 | " \n",
419 | " | 14 | \n",
420 | " 1 | \n",
421 | " widget-a | \n",
422 | " 2019-02-24 | \n",
423 | " 2019-02-24 00:07:59 | \n",
424 | " 0.708329 | \n",
425 | "
\n",
426 | " \n",
427 | " | 15 | \n",
428 | " 1 | \n",
429 | " widget-a | \n",
430 | " 2019-02-24 | \n",
431 | " 2019-02-24 00:08:59 | \n",
432 | " 0.808329 | \n",
433 | "
\n",
434 | " \n",
435 | " | 16 | \n",
436 | " 1 | \n",
437 | " widget-a | \n",
438 | " 2019-02-24 | \n",
439 | " 2019-02-24 00:09:59 | \n",
440 | " 0.908329 | \n",
441 | "
\n",
442 | " \n",
443 | " | 17 | \n",
444 | " 1 | \n",
445 | " widget-a | \n",
446 | " 2019-02-24 | \n",
447 | " 2019-02-24 00:10:59 | \n",
448 | " 1.008329 | \n",
449 | "
\n",
450 | " \n",
451 | " | 18 | \n",
452 | " 1 | \n",
453 | " widget-a | \n",
454 | " 2019-02-24 | \n",
455 | " 2019-02-24 00:11:59 | \n",
456 | " 1.108329 | \n",
457 | "
\n",
458 | " \n",
459 | " | 19 | \n",
460 | " 1 | \n",
461 | " widget-a | \n",
462 | " 2019-02-24 | \n",
463 | " 2019-02-24 00:12:59 | \n",
464 | " 1.208329 | \n",
465 | "
\n",
466 | " \n",
467 | " | 20 | \n",
468 | " 2 | \n",
469 | " widget-a | \n",
470 | " 2019-02-24 | \n",
471 | " 2019-02-24 00:03:59 | \n",
472 | " 0.766993 | \n",
473 | "
\n",
474 | " \n",
475 | " | 21 | \n",
476 | " 2 | \n",
477 | " widget-a | \n",
478 | " 2019-02-24 | \n",
479 | " 2019-02-24 00:04:59 | \n",
480 | " 0.866993 | \n",
481 | "
\n",
482 | " \n",
483 | " | 22 | \n",
484 | " 2 | \n",
485 | " widget-a | \n",
486 | " 2019-02-24 | \n",
487 | " 2019-02-24 00:05:59 | \n",
488 | " 0.966993 | \n",
489 | "
\n",
490 | " \n",
491 | " | 23 | \n",
492 | " 2 | \n",
493 | " widget-a | \n",
494 | " 2019-02-24 | \n",
495 | " 2019-02-24 00:06:59 | \n",
496 | " 1.066993 | \n",
497 | "
\n",
498 | " \n",
499 | " | 24 | \n",
500 | " 2 | \n",
501 | " widget-a | \n",
502 | " 2019-02-24 | \n",
503 | " 2019-02-24 00:07:59 | \n",
504 | " 1.166993 | \n",
505 | "
\n",
506 | " \n",
507 | " | 25 | \n",
508 | " 2 | \n",
509 | " widget-a | \n",
510 | " 2019-02-24 | \n",
511 | " 2019-02-24 00:08:59 | \n",
512 | " 1.266993 | \n",
513 | "
\n",
514 | " \n",
515 | " | 26 | \n",
516 | " 2 | \n",
517 | " widget-a | \n",
518 | " 2019-02-24 | \n",
519 | " 2019-02-24 00:09:59 | \n",
520 | " 1.366993 | \n",
521 | "
\n",
522 | " \n",
523 | " | 27 | \n",
524 | " 2 | \n",
525 | " widget-a | \n",
526 | " 2019-02-24 | \n",
527 | " 2019-02-24 00:10:59 | \n",
528 | " 1.466993 | \n",
529 | "
\n",
530 | " \n",
531 | " | 28 | \n",
532 | " 2 | \n",
533 | " widget-a | \n",
534 | " 2019-02-24 | \n",
535 | " 2019-02-24 00:11:59 | \n",
536 | " 1.566993 | \n",
537 | "
\n",
538 | " \n",
539 | " | 29 | \n",
540 | " 2 | \n",
541 | " widget-a | \n",
542 | " 2019-02-24 | \n",
543 | " 2019-02-24 00:12:59 | \n",
544 | " 1.666993 | \n",
545 | "
\n",
546 | " \n",
547 | " | 30 | \n",
548 | " 3 | \n",
549 | " widget-a | \n",
550 | " 2019-02-24 | \n",
551 | " 2019-02-24 00:03:59 | \n",
552 | " 0.880996 | \n",
553 | "
\n",
554 | " \n",
555 | " | 31 | \n",
556 | " 3 | \n",
557 | " widget-a | \n",
558 | " 2019-02-24 | \n",
559 | " 2019-02-24 00:04:59 | \n",
560 | " 0.980996 | \n",
561 | "
\n",
562 | " \n",
563 | " | 32 | \n",
564 | " 3 | \n",
565 | " widget-a | \n",
566 | " 2019-02-24 | \n",
567 | " 2019-02-24 00:05:59 | \n",
568 | " 1.080996 | \n",
569 | "
\n",
570 | " \n",
571 | " | 33 | \n",
572 | " 3 | \n",
573 | " widget-a | \n",
574 | " 2019-02-24 | \n",
575 | " 2019-02-24 00:06:59 | \n",
576 | " 1.180996 | \n",
577 | "
\n",
578 | " \n",
579 | " | 34 | \n",
580 | " 3 | \n",
581 | " widget-a | \n",
582 | " 2019-02-24 | \n",
583 | " 2019-02-24 00:07:59 | \n",
584 | " 1.280996 | \n",
585 | "
\n",
586 | " \n",
587 | " | 35 | \n",
588 | " 3 | \n",
589 | " widget-a | \n",
590 | " 2019-02-24 | \n",
591 | " 2019-02-24 00:08:59 | \n",
592 | " 1.380996 | \n",
593 | "
\n",
594 | " \n",
595 | " | 36 | \n",
596 | " 3 | \n",
597 | " widget-a | \n",
598 | " 2019-02-24 | \n",
599 | " 2019-02-24 00:09:59 | \n",
600 | " 1.480996 | \n",
601 | "
\n",
602 | " \n",
603 | " | 37 | \n",
604 | " 3 | \n",
605 | " widget-a | \n",
606 | " 2019-02-24 | \n",
607 | " 2019-02-24 00:10:59 | \n",
608 | " 1.580996 | \n",
609 | "
\n",
610 | " \n",
611 | " | 38 | \n",
612 | " 3 | \n",
613 | " widget-a | \n",
614 | " 2019-02-24 | \n",
615 | " 2019-02-24 00:11:59 | \n",
616 | " 1.680996 | \n",
617 | "
\n",
618 | " \n",
619 | " | 39 | \n",
620 | " 3 | \n",
621 | " widget-a | \n",
622 | " 2019-02-24 | \n",
623 | " 2019-02-24 00:12:59 | \n",
624 | " 1.780996 | \n",
625 | "
\n",
626 | " \n",
627 | " | 40 | \n",
628 | " 4 | \n",
629 | " widget-a | \n",
630 | " 2019-02-24 | \n",
631 | " 2019-02-24 00:03:59 | \n",
632 | " 0.673713 | \n",
633 | "
\n",
634 | " \n",
635 | " | 41 | \n",
636 | " 4 | \n",
637 | " widget-a | \n",
638 | " 2019-02-24 | \n",
639 | " 2019-02-24 00:04:59 | \n",
640 | " 0.773713 | \n",
641 | "
\n",
642 | " \n",
643 | " | 42 | \n",
644 | " 4 | \n",
645 | " widget-a | \n",
646 | " 2019-02-24 | \n",
647 | " 2019-02-24 00:05:59 | \n",
648 | " 0.873713 | \n",
649 | "
\n",
650 | " \n",
651 | " | 43 | \n",
652 | " 4 | \n",
653 | " widget-a | \n",
654 | " 2019-02-24 | \n",
655 | " 2019-02-24 00:06:59 | \n",
656 | " 0.973713 | \n",
657 | "
\n",
658 | " \n",
659 | " | 44 | \n",
660 | " 4 | \n",
661 | " widget-a | \n",
662 | " 2019-02-24 | \n",
663 | " 2019-02-24 00:07:59 | \n",
664 | " 1.073713 | \n",
665 | "
\n",
666 | " \n",
667 | " | 45 | \n",
668 | " 4 | \n",
669 | " widget-a | \n",
670 | " 2019-02-24 | \n",
671 | " 2019-02-24 00:08:59 | \n",
672 | " 1.173713 | \n",
673 | "
\n",
674 | " \n",
675 | " | 46 | \n",
676 | " 4 | \n",
677 | " widget-a | \n",
678 | " 2019-02-24 | \n",
679 | " 2019-02-24 00:09:59 | \n",
680 | " 1.273713 | \n",
681 | "
\n",
682 | " \n",
683 | " | 47 | \n",
684 | " 4 | \n",
685 | " widget-a | \n",
686 | " 2019-02-24 | \n",
687 | " 2019-02-24 00:10:59 | \n",
688 | " 1.373713 | \n",
689 | "
\n",
690 | " \n",
691 | " | 48 | \n",
692 | " 4 | \n",
693 | " widget-a | \n",
694 | " 2019-02-24 | \n",
695 | " 2019-02-24 00:11:59 | \n",
696 | " 1.473713 | \n",
697 | "
\n",
698 | " \n",
699 | " | 49 | \n",
700 | " 4 | \n",
701 | " widget-a | \n",
702 | " 2019-02-24 | \n",
703 | " 2019-02-24 00:12:59 | \n",
704 | " 1.573713 | \n",
705 | "
\n",
706 | " \n",
707 | "
\n",
708 | "
"
709 | ],
710 | "text/plain": [
711 | " dev_id type mdate mdatetime value\n",
712 | "0 0 widget-a 2019-02-24 2019-02-24 00:03:59 0.470658\n",
713 | "1 0 widget-a 2019-02-24 2019-02-24 00:04:59 0.570658\n",
714 | "2 0 widget-a 2019-02-24 2019-02-24 00:05:59 0.670658\n",
715 | "3 0 widget-a 2019-02-24 2019-02-24 00:06:59 0.770658\n",
716 | "4 0 widget-a 2019-02-24 2019-02-24 00:07:59 0.870658\n",
717 | "5 0 widget-a 2019-02-24 2019-02-24 00:08:59 0.970658\n",
718 | "6 0 widget-a 2019-02-24 2019-02-24 00:09:59 1.070658\n",
719 | "7 0 widget-a 2019-02-24 2019-02-24 00:10:59 1.170658\n",
720 | "8 0 widget-a 2019-02-24 2019-02-24 00:11:59 1.270658\n",
721 | "9 0 widget-a 2019-02-24 2019-02-24 00:12:59 1.370658\n",
722 | "10 1 widget-a 2019-02-24 2019-02-24 00:03:59 0.308329\n",
723 | "11 1 widget-a 2019-02-24 2019-02-24 00:04:59 0.408329\n",
724 | "12 1 widget-a 2019-02-24 2019-02-24 00:05:59 0.508329\n",
725 | "13 1 widget-a 2019-02-24 2019-02-24 00:06:59 0.608329\n",
726 | "14 1 widget-a 2019-02-24 2019-02-24 00:07:59 0.708329\n",
727 | "15 1 widget-a 2019-02-24 2019-02-24 00:08:59 0.808329\n",
728 | "16 1 widget-a 2019-02-24 2019-02-24 00:09:59 0.908329\n",
729 | "17 1 widget-a 2019-02-24 2019-02-24 00:10:59 1.008329\n",
730 | "18 1 widget-a 2019-02-24 2019-02-24 00:11:59 1.108329\n",
731 | "19 1 widget-a 2019-02-24 2019-02-24 00:12:59 1.208329\n",
732 | "20 2 widget-a 2019-02-24 2019-02-24 00:03:59 0.766993\n",
733 | "21 2 widget-a 2019-02-24 2019-02-24 00:04:59 0.866993\n",
734 | "22 2 widget-a 2019-02-24 2019-02-24 00:05:59 0.966993\n",
735 | "23 2 widget-a 2019-02-24 2019-02-24 00:06:59 1.066993\n",
736 | "24 2 widget-a 2019-02-24 2019-02-24 00:07:59 1.166993\n",
737 | "25 2 widget-a 2019-02-24 2019-02-24 00:08:59 1.266993\n",
738 | "26 2 widget-a 2019-02-24 2019-02-24 00:09:59 1.366993\n",
739 | "27 2 widget-a 2019-02-24 2019-02-24 00:10:59 1.466993\n",
740 | "28 2 widget-a 2019-02-24 2019-02-24 00:11:59 1.566993\n",
741 | "29 2 widget-a 2019-02-24 2019-02-24 00:12:59 1.666993\n",
742 | "30 3 widget-a 2019-02-24 2019-02-24 00:03:59 0.880996\n",
743 | "31 3 widget-a 2019-02-24 2019-02-24 00:04:59 0.980996\n",
744 | "32 3 widget-a 2019-02-24 2019-02-24 00:05:59 1.080996\n",
745 | "33 3 widget-a 2019-02-24 2019-02-24 00:06:59 1.180996\n",
746 | "34 3 widget-a 2019-02-24 2019-02-24 00:07:59 1.280996\n",
747 | "35 3 widget-a 2019-02-24 2019-02-24 00:08:59 1.380996\n",
748 | "36 3 widget-a 2019-02-24 2019-02-24 00:09:59 1.480996\n",
749 | "37 3 widget-a 2019-02-24 2019-02-24 00:10:59 1.580996\n",
750 | "38 3 widget-a 2019-02-24 2019-02-24 00:11:59 1.680996\n",
751 | "39 3 widget-a 2019-02-24 2019-02-24 00:12:59 1.780996\n",
752 | "40 4 widget-a 2019-02-24 2019-02-24 00:03:59 0.673713\n",
753 | "41 4 widget-a 2019-02-24 2019-02-24 00:04:59 0.773713\n",
754 | "42 4 widget-a 2019-02-24 2019-02-24 00:05:59 0.873713\n",
755 | "43 4 widget-a 2019-02-24 2019-02-24 00:06:59 0.973713\n",
756 | "44 4 widget-a 2019-02-24 2019-02-24 00:07:59 1.073713\n",
757 | "45 4 widget-a 2019-02-24 2019-02-24 00:08:59 1.173713\n",
758 | "46 4 widget-a 2019-02-24 2019-02-24 00:09:59 1.273713\n",
759 | "47 4 widget-a 2019-02-24 2019-02-24 00:10:59 1.373713\n",
760 | "48 4 widget-a 2019-02-24 2019-02-24 00:11:59 1.473713\n",
761 | "49 4 widget-a 2019-02-24 2019-02-24 00:12:59 1.573713"
762 | ]
763 | },
764 | "execution_count": 8,
765 | "metadata": {},
766 | "output_type": "execute_result"
767 | }
768 | ],
769 | "source": [
770 | "result = %sql select * from sensor_data\n",
771 | "df = result.DataFrame()\n",
772 | "df"
773 | ]
774 | },
775 | {
776 | "cell_type": "code",
777 | "execution_count": 12,
778 | "metadata": {},
779 | "outputs": [
780 | {
781 | "data": {
782 | "text/html": [
783 | "\n",
784 | "\n",
797 | "
\n",
798 | " \n",
799 | " \n",
800 | " | \n",
801 | " dev_id | \n",
802 | " value | \n",
803 | "
\n",
804 | " \n",
805 | " \n",
806 | " \n",
807 | " | count | \n",
808 | " 50.000000 | \n",
809 | " 50.000000 | \n",
810 | "
\n",
811 | " \n",
812 | " | mean | \n",
813 | " 2.000000 | \n",
814 | " 1.070138 | \n",
815 | "
\n",
816 | " \n",
817 | " | std | \n",
818 | " 1.428571 | \n",
819 | " 0.357015 | \n",
820 | "
\n",
821 | " \n",
822 | " | min | \n",
823 | " 0.000000 | \n",
824 | " 0.308329 | \n",
825 | "
\n",
826 | " \n",
827 | " | 25% | \n",
828 | " 1.000000 | \n",
829 | " 0.822995 | \n",
830 | "
\n",
831 | " \n",
832 | " | 50% | \n",
833 | " 2.000000 | \n",
834 | " 1.072185 | \n",
835 | "
\n",
836 | " \n",
837 | " | 75% | \n",
838 | " 3.000000 | \n",
839 | " 1.345493 | \n",
840 | "
\n",
841 | " \n",
842 | " | max | \n",
843 | " 4.000000 | \n",
844 | " 1.780996 | \n",
845 | "
\n",
846 | " \n",
847 | "
\n",
848 | "
"
849 | ],
850 | "text/plain": [
851 | " dev_id value\n",
852 | "count 50.000000 50.000000\n",
853 | "mean 2.000000 1.070138\n",
854 | "std 1.428571 0.357015\n",
855 | "min 0.000000 0.308329\n",
856 | "25% 1.000000 0.822995\n",
857 | "50% 2.000000 1.072185\n",
858 | "75% 3.000000 1.345493\n",
859 | "max 4.000000 1.780996"
860 | ]
861 | },
862 | "execution_count": 12,
863 | "metadata": {},
864 | "output_type": "execute_result"
865 | }
866 | ],
867 | "source": [
868 | "df.describe()"
869 | ]
870 | },
871 | {
872 | "cell_type": "markdown",
873 | "metadata": {},
874 | "source": [
875 | "Data frames integrate nicely with graphics. Use selection on the data frame to pull out rows for each device in sucession and plot them as separate lines. "
876 | ]
877 | },
878 | {
879 | "cell_type": "code",
880 | "execution_count": 9,
881 | "metadata": {},
882 | "outputs": [
883 | {
884 | "data": {
885 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXcAAAEeCAYAAABxO1VsAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAAIABJREFUeJzs3Xd8VFX+//HXnZbeeyUhJIRQQu+9N2kJKJZVt6i7rPtbdV11m3511y2uX/e7irK6xbIrbApNQLChdGkSWiAJBEiY9GTSkyn3/P4YQKqgzmQyyXk+Hj4kuZc5HwU+czhz7vsoQggkSZKkrkXj6gIkSZIkx5PNXZIkqQuSzV2SJKkLks1dkiSpC5LNXZIkqQuSzV2SJKkLks1dkiSpC5LNXZIkqQuSzV2SJKkL0rlq4NDQUJGQkOCq4SVJktzSgQMHqoUQYTe7z2XNPSEhgf3797tqeEmSJLekKMrZW7lPLstIkiR1QbK5S5IkdUE3be6KovxTUZRKRVGO3uB6gKIo7ymKkqcoyjFFUe53fJmSJEnS13ErM/c3gZlfcX0ZcFwIkQ5MBF5UFMXw7UuTJEmSvqmbNnchxDag9qtuAfwURVEA3wv3Wh1TniRJkvRNOGLN/RWgD2AEjgD/TwihXu9GRVEeUBRlv6Io+6uqqhwwtCRJkvupevkVp4/hiOY+AzgERAMDgVcURfG/3o1CiNeFEEOFEEPDwm66TVOSJKlLql6+3OljOGKf+/3AH4T9vL4iRVGKgVRgrwNeW5Ikqcto+uwzLGXlHTKWI5r7OWAKsF1RlAigN3DaAa8rSZLk9iwVlegjwql6+ZUrZuz5qX0ACF22jLCHf+zwcW/a3BVFWYl9F0yooiilwNOAHkAIsQJ4DnhTUZQjgAI8IYSodnilkiRJbkJYLDR+shVTVhbNu3aRuG4tYQ//mKC770Lr58eJfv3pcyLfqTXctLkLIZbe5LoRmO6wiiRJktyUzWSi5h//wLR6DbaaGnSRkYQuW4YuOBgAXVBQh9XismwZSZKkrkA1m7GWl2OIjwedjrqVq/AeMYKgJYvxGTsWRau95ueELlvm9Lpkc5ckSfoG2k8XY8rOpn7tWnQRESSuWY3W15den36K1tfnK3+uM9bYryabuyRJ0tfQtHMnNa+toGX/ftDp8Js0icAlSy5dv1lj7yiyuUuSJN1Ee1ERurAwtAEBWCursFRWEvboowQuXICukz6zI5u7JEnSdaitrTRs3oIpO5vWgwcJf+IJQu6/j4Db5hIwfx6KpnOH6srmLkmSdBmhqlQ8/3vq161DbWzEkJBA+OOPEzB/HgCKzj3apntUKUmS5ERqSwstX3yB75gxKBoNlpISfCdOJHBxJt7DhmHPRXQvsrlLktRtVL38yhU7VVqPHcOUnU3DextQ29pI/nQrurAwYle85pYN/XKde9FIkiTJgS4+/t969BjFGZmcycikfs1a/KZOpcc7b6MNDQVw+8YOcuYuSVI3IISg7ciRS1/rQkMQqkrEr35FwG1z0QYEdFgtVS1VPL7tcf484c+EeoU6bRw5c5ckqcuyNTRw7oEHONEnjTNLbgfsgV1FEyfhN3kywXff1aGNHWDF4RUcrDjIirwVTh1HNndJkrqkqr/+lcLxE2jeth2PtD5EPvM0AH1O5NPnRH6HPCV6tTP1Z1hTuAaBYG3RWqpbnZexKJu7JEldgs1kovadf6O2twOgDQ4hYN48EnJy6Ll6NUF33OHiCuF7H3wPi2oBQBWqU2fvcs1dkiS3JYSg9cAB6rKyaNy8BWE2o4+NwW/SJILvvuua+zsisOuiBnMDG09vZH3Rel6d+ipW1UpdW92l6xbVwtqitTyU/pBT1t5lc5ckyS1Za2s5e/c9mE+fRuPrS2BmJoFLFuOZmnrDn+PspRghBHlVeWQXZPPBmQ9os7XRJ7gPlS2VZBVkXXP/xdn7r0b+yuG1yOYuSZJbEKpKy969WEpLCczMRBsUhNeAAYT84Af4z5yBxsvLdbUJgaIoGJuN3PP+PXjrvJmbNJfMlEz6hvQFIK8y79KSzEUW1cKhykNOqUmxH33a8YYOHSr279/vkrElSXIf1upqTGvWYMrJwXL2HLroKHp9+OF1c9I7khCCAxUHyC3MxapaeWHCCwB8VvIZwyKH4a33dsq4iqIcEEIMvdl9cuYuSVKnVZedTfn/PAtWK95DhxK2bBl+06e7tLHXtdWx/tR6cgpyONNwBl+9Lwt6Lbg0e58QN8FltV3uVs5Q/ScwF6gUQvS7wT0Tgb9gP1u1WgjROf7rJElyK5bKSupXr8Fn9Ci8BgzAa0A6wXffTeCSxXj07OmyulShIoRAq9Gy6uQqXj30KgPDBvLbMb9lesJ0vHSuWxK6kVuZub8JvAK8fb2LiqIEAq8CM4UQ5xRFCXdceZIkdXXCZqN5xw7qsrNp2vop2GygKHgNGIBn7xQ8n3zCZbVVt1azrmgduYW5PDLkEab1mMaSlCVMjZ9KclCyy+q6FbdyQPY2RVESvuKWO4HVQohzF+6vdExpkiR1dUIIzixeQtvx42hDQgi5/z4CMzMxJCS4tKbdZbvJKchh67mtWIWVIRFD8Df4AxDiFUKIV4jL6rtVjlhzTwH0iqJ8CvgB/yeEuNEs/wHgAYD4+HgHDC1Jkju4mMYorFaatm2j8ZNPiHr2WRSNhsCld6D188dv8iQUg8FlNbZaWy8trzz/+fM0tDdwV5+7WJSyiJ4BrlsS+qYc0dx1wBBgCuAF7FYUZY8QouDqG4UQrwOvg323jAPGliTJDVQvX45QbdTnrsZaWYk2LBTL+fMY4uIIWrzYZXXZVBs7jTvJKcghryqPLRlb8NR58vLkl4nxjcGgdfybTXN9Ox/8/SjTv98PnwAPh7/+RY6IHygFNgshmoUQ1cA2IN0BrytJUhfQcvALAGpW/A2P1N7EvvIyyZ98giEurkPrqGqp4r7N91HdWk11azWvHXqNmatnsuzjZeRV5bGg1wLMqhmAxIBEpzR2gP0bizEW1bN/Y7FTXv8iR8zc1wGvKIqiAwzACOAlB7yuJEluyFxSgik7h7bjx2jesfPLC0LQvG07Xv0H4Dd1aofX9Vrea5fSGOclzePVvFcZHT2anw/7ORNjJ6LX6p06/ooff4rNql76+ug2I0e3GdHqNDz0ykSHj3crWyFXAhOBUEVRSoGnsW95RAixQgiRryjKZuAwoAJ/F0IcdXilkiR1WsJspvGTTzBlZdG8azdoNARmZNDnRD5gj9m9+OOOZmwy8s7xd8guyAZgbdFaHhzwIB9kfECUb5RTx1ZVwfkTdcT2CeKe341izYsHaahqRQjQ6TX0HBTG6IxeThn7VnbLLL2Fe14AXnBIRZIkuZ2yp5+hfs0adNFRhP7kYQIXLUIfGenSmraVbuPdE++y6/wuBAIFBYFAFSp/O/w3p+S5XNRY20b+TiP5u8poqmtn4WODiU4OJLZ3EMeqWtHqNVitKgZPrdPW3eUTqpIkfS1qezuNH36EKSuLyGeewaNnIkF334X/7Fn4jB593adHOyqN8XzTeaJ9olEUhe2l2ymqK+KetHtYdWLVpfV0Z6YxNpva2frvE5w7VoMA4vsEM3ZJMhE97dsoWxvN9BsfQ99x0RzbbqSlvt2h419OZstIknRL2k+dwpSVTf26ddhMJvRxcUQ99yw+I0e6tC6LzcLHJR+TW5DLnrI9vDXzLQZHDKbR3IiXzovf7/09awrXXBHapdfoWZS8yCGz94bqVhpr2ojpHYTNqpL9h/0kDgilz+go/EMd/+SqzJaRJMlhbE3NFC/KQKgqflOmELRkMd4jR6JoXHfeT6O5kTcOv8G6U+uobaslyieKZQOXEe9vf4bGz+AHOCeN0WZTOZNXzbEdRkrya/EP8eTu50ah1Wm4/ZfDOsUB27K5S5J0jbaTBZiyszGfOUP8399A6+tDzF9ewmvAAHQhrns6s93WTmljKUmBSXhoPXjv9HsMDh9MRkoGo6JGodVcuySUMy/HoTWc3FPGztwiWhst+AZ5MGxOIn1GR11q6J2hsYNs7pIkXaC2tNDw/vuYsrJpzctD0evxmz4dtb0djYcHfpMmuay206bT5BTmsP7Uenz1vmxatAmD1sD7i97HU+fp1LFtFpXTeVVE9gzAL9gTDx89kT0DSBsbTXzfEDSaztHMryabuyR1c0JVUTQa6jdupPzXv8GQlET4k08QMH8+uqAgl9b2ednnvHroVQ5WHkSn0TE5bjKZKZmXrjuzsdeVN3N8h5ETe8ppa7IwckFPhsxMIKF/KAn9HX8snqPJ5i5J3ZCtqZmGTRsxZWUTsGABwXffRcDs2Xj07InX4MEuXVooqCsgyCOIMO8wWiwt1LTV8OiQR5mXNK9DAruEKnjv5UOU5Neh0SgkpoeSNjaauD7BTh/bkWRzl6Qu7GJg10WtR45iysqifuNGREsLHsnJ6ILts3ONjw/eQ4a4pM4WSwtbzmwhpzCHw1WHeWDAAzw86GEmxE1gYtxEp7/Z1BibKM2vI31KHIpGITjGl5jeQaSOinJq/oszyeYuSV1Y9fLlhDz4AJoLaYsVf/wDbUeP4T97NkFLFuOZnu7SWboQgj/u+yPritbRZGmiZ0BPfj7s59zW8zYANIrjduNcHdhlMds4daCSY9uNlJ+uR6NT6DU0HJ8AD8Zmdu6s9lshm7skdUFCCNry8gAoHDuOpPc3oQsJIeq559CFhqL18+uwWqpaqnh82+P8ecKfCfUKpdnSzJ6yPUyJn4KiKDS0NzA53r6WPjBsoNPebC4P7Oo1NIJNrx3B3GolMMKb0Rm9SB0ZiZef6yKHHU0+xCRJXYitqYnzjzxK8/bt11wLXbbsiiWajvLcnufIPpnN1B5T8Tf4s6l4E63WVjYu3Ei8f/yls0ed5erArosUBRY8OoioXoGdZvvirZAPMUlSNyGEQG1qQuvnh81konnHDjz79SNw8WLKn37aZYFdYJ+1ry1ci0Dw4dkP8dR6MitxFhkpGcT52SN/ndlYK882kDQkjMJ9FYgL/f3ywC53XU+/FbK5S5KbstbVUb9uHabsHAxxccSteA1DbCxJm9/H0KMHAOVPP93hdQkhyKvKw6paef/M+wjsqwNaRcvsxNn8z5j/6ZA6Pn7rOCd2l6PVawgI9cJU2TGBXZ2FbO6S5GZaDx2i9t//oXHLFoTFgld6On4zZly6frGxQ8cFdgHUt9ez4fQGcgpyKDIVkR6WzonaE5ce/bcJGxuLN/Lw4IcdHtglhKDyTCPHdxoZtTAJTx89ielhhPfwJ2V4BJ+8nU9sn+AOCezqLOSauyS5AWttLVpfXxSDgeoVK6j5xz8JmDePwCWL8ezd29Xl8be8v/HGkTdot7XTL6QfGSkZHKk6wnun33NaYBdAe4uFgr0VHNtupOZ8EzqDhtk/HOB2e9K/DrnmLkluTqgqLXv2UJedTeNHHxPzpz/iP2sWQXffQ/C996Lxcnzi4K0ytZlYf2o983vNJ8AjgBi/GBb0WkBmSiapwakArDqxyuGBXZdrbTTz9i93YTWrhMX7MeHO3qQMi8DgJdsayOYuSZ2OMJup+debmHJysJSUoA0IIPjOO/FMSwNA6+vjmrqEYF/5PnIKc/jo7EdYVAuhXqHM7jmbuT3nMrfn3Cvud3RgV1uzhZN7ymlpaGfUwl54+RkYPrcnMb0DCe/h79CxugLZ3CWpExA2G+YzZ/BISgK9nvp169BHRRH2//4fftOmovFw7Yd/zZZm7thwB2cazuBn8GNxymIyUjJICUpx6rhCCMqKTBzbbuTUwSpsVpWopABUVaDRKAyaHu/U8d3ZrZyh+k9gLlAphOj3FfcNA/YAtwshHPuWLUldlKWiAlNuLqacHNTGJpK3fYbGy4vE7Cw0Pq6ZoQOoQmVP2R5OmU5xT9o9+Oh9GBMzhgcGPMC0HtOcnsR40aGPStiVW4TBU0vamCjSxkUTGttxD2C5s1uZub8JvAK8faMbFEXRAn8EtjimLEnq2try86n668s0ffYZqCo+o0cRuGQJis7+R9JVjb2qpYp1p9aRU5DD+abzhHqFsqT3Ejy0Hjw5/Emnji1UwfmCOo7vMJIyIpKE/qH0GhKOl6+epCHh6A3XZrVLN3YrB2RvUxQl4Sa3PQzkAsMcUJMkdUkWoxGhCgyxMQirldajRwj5/vcJzMzAEO/65YUNpzfwqx2/wiZsDIscxk8G/YQpPabgoXXuklBLg5kTu8s4vsNIfVUrHt46YlPtu138gj1JHRXl1PG7qm+95q4oSgywEJjMTZq7oigPAA8AxHeC38yS5ExVL79C6EMP0vTZZ9RlZdG8fQcBGYuI/u1v8ezXj+RPPkHR611WX3lzOWuK1jAofBAjo0YyKHwQ30n7DouSF5EQkNAhNQghWPPiQUwVLUQnBzJsbiJJg8LQyVn6t3ZL+9wvzNw3XG/NXVGUbOBFIcQeRVHevHDfTdfc5T53qavLT+2DNiwUW1U1uvBwAjMzCMzIQB8T47KarKqVHed3kFuQy7bz21CFyoMDHuTHg5yXOXN5GiMC8neVUXy4mkWPDUar11CSX4tvkAdBka77jKGjrP3iPC9sOYnR1Ep0oBePz+jNgkFf7/dDR+5zHwqsupAPEQrMVhTFKoRY64DXliS3IcxmmnbsxHfSl/njXn37EbhkCb7jx11aT+8oV6cxAnxvy/c4WHmQUK9QvtvvuyxKXnQp48VZ9m0oxlhYT+6f9tNUZ0aogpjeQbQ0mvEL9uzSDxxdbu0X53lq9RFaLTYAzptaeWr1EYCv3eBvxbeeuV9135vImbvUzZjPnMGUk4NpzVpsNTXXvccViYzP7n6WnIIcYn1jWbtgLQatgc1nNqNX9IyPG49e49wloRulMWp0Cj98xXXnsbrKmD98wnlT6zXfjwn0YueTk2/5dRw2c1cUZSUwEQhVFKUUeBrQAwghVtxyRZLUxVjKyzE+8SQtn38OWi2+kyYStHgxPmPHomi15Kf2cUkiY0ljCf8+/m+yC7LtXzeVkFeZx7CoYcxMmOnUsVWbytmjNRzfYSR5eAQ2i0rxoSqsFhWtXkPShTTG7qSp3Yqvhw7jdRo7cMPvf1u3sltm6a2+mBDivm9VjSR1cu2nT2MpK8N3zBh0wcGoba2E/fSnBCxciD4i3NXlcbL2JJnv2Q+QVlAQCPQaPVvObmFYlPM2szXUtJK/s4z8nUaa6814BxhInxxHQ3UrVqu9sdu6SRoj2D8o/ry4llV7z/H+0XI2/3Q80YFe1525Rwc6J0ZCPqEqSTehtrXR+MEHmLKyadm/H32PeJI2b0YxGEj8739v+PM6IpHxbMNZcgtz8dB6sGzgMlKCUliWvow3jryBWTUD9jyXtUVreSj9IYemMdpsKhqNgqIoHNh8luM7jPToG8L4pdEk9A9Bo9Xw/orD9Bsf023SGBvbLKzaW8LKfec4XdWMn6eOO4bFYdBpeHxG7yvW3AG89Foen+Gc4DfZ3CXpK5hyc6n40wuo9fXoe8QT9tijBC5ceEsHTDhrjd1sM/PR2Y/ILcxlb/letIr2Uq6LoihUtVVdylC/SBUqK/JWOCSNsb6qheM7ysjfXcbsh/oT2TOAobMSGDorAb/gK59cnfXQgEs/nrDU9emVzqCqgppmM2F+Hlhtghc+OEn/mAD+vLgXc/pH4XVhW2fMhQ9Nv+1umVslm7skXUZtbaVh8xZ8hg9DHxODLjwc3zFjCFyyGO/hw1E0jjuw+Zt6cf+LvHviXWJ8Y/jJoJ+woNcCwrzDLl3Pq8xzeBqjzaZy+osqju8wUnqiDkWBHv1D0ers/z+uburdQWVjGzkHSvnvvhKCfQys+dEYgnwMbP/5JCL8r///Y8GgGKc186vJPHdJAtpOnMCUlU39e++hNjYS/vjPCPne91xdFm3WNj48+yE5BTk8NvQxBoQNoLi+mLLmMkZGjUSjOPfNxtxmxeCpw2qx8eYTOzF46kgbG0XqqGh8g7r+2vn1HDhbyxvbivkovwKrKhiRGMzS4fHMHxjdIWexyjx3SboFwmbj7HfupfXAARSDAb+ZMwhasgSvIUNcWldhXSG5hbmsP7WeRnMj8X7x1LfXA5AYkEhiQKLTxrZabJz+osq+Rt5g5s5nRqDTa8n4+RACwr3RaNznMGlHqWhow9dDh4+HjhPljew9U8t3xyZy+7A4ksJ8XV3edcnmLnU7rUeP0bx7F6E/+AGKVov34MH4z5hOwLx5aAMDXVaXEAJFUTDbzNy3+T5ara1MjZ9KZkomQyOHOn2WXl/VwpGt5znxeRntzVb8Qz1JGxuNahVo9Uq3eIL0cjZV8FlBJSv3lvDJiUqeuS2Ne0YlkDE4lswhsXjoOndEgmzuUrdga2qiYcMGTFnZtB0/juLpSeCCBejCwgh/7FGX1nai9gQ5BTkcqz7Gu3PexaA18NLEl0gOSibIM8ipY1vNNlSbwOClo7qkiSOflZKYHkbfcdHE9g5C6YazdFUV/PWTQrL2lWCsbyPU18APxvVkQop9q6unvnM39Ytkc5e6nKqXX7lip0rznj2U/PBHiNZWPFJTifjNrwmYOxetv+tO72mxtPB+8fvkFORwtOYoBo2B6QnTabY042vwZXjUcKeOX3O+iWM7jBR8Xk76lDiGzUkkIT2Ue38/Bm9/g1PH7oysNpXjZQ0MiA1Eo1HYVVRDrwg/fj03jSl9IjDoXP9B+tclm7vU5VQvX442KAhdRDj+06bhmZZGwG23Ebg4E89+/TrkQ68bsapWdBodO87v4Jndz9ArsBdPDn+SuT3nEuAR4NCxLg/suvjg0Ik9ZRz97DwVxQ1odApJg8IvZbtotZou29hvFNhVUttC1v4SsvaXUNdsYc8vphDsY+Df3x/hlg39cnK3jNQlCCFo/eIL+46XtfbMuoAFC4j+w+9dUs/loV2eWk82FW8ipyCHyfGTeSj9ISw2C8dqjpEelu60N5vP3j3B0e1GkoeGM/179lioTa8dxlTRQtrYaHqPjMTLt2s288tdHdgF4KHTkBDqQ0FFIwATU8JYOjyeyanh6LSdu6nL3TJSt3J6/gLMBQVXfK9+7Vr0MTEdHtgFsOLwCg5WHOS7m79LeUs5rdZWegf1Jt7Pfo6BXqtnYPhA54x9VWBX4b5KCvd9glan4f4XxmLw1Lr0by8d7YUtJ69o7ADtVpWiikZ+MjmZJcPiiHFSBIAryeYuuR0hBC379lGfm0vEU0+hDQwk/NFHsNXU4D9zJieHDHVJYBfY19KbLc2sK1qHQFDcUMycxDncnXY3fUP6Or2pNtW103NwGEX7KxAX+rtGq5A4MIxxS5Lx8Opef+Tbrbbr5rkAqAIemebcA75dqXv9SktuzVpbS/2atZiyszGfOYPGz4+AhYvwGTkCv4kTXVaXEIJDVYfIKcjhw7MfMiluEuqFzqrX6PE1+NIv9CvTsr+V9lYrLfXtBEX6oNUrnDtaQ0CYN6aKlkuBXV4+um4R2HW5v312ir9tO33D684K7OosZHOX3IK1poaiiZMQFgtegwcT9eCD+M+cgcbr2j+gHRHYBdBsaWZ14WpyCnI4XX8aH70PU+OnsuXMlkuP/zsrtEsIQUVxA8d2GCnaV0FonB8ZPx+Cl6+B+/84lg/+cZTY1KBuE9gF0Gax8cHxCmb2jcSg02BVBcMTgukR6s3bu87QavlyqcqZgV2dhfxAVeqUrNXVmNaswVZdQ8RTTwJQ+86/8Rk5Ao/kZJfVJYTA1G4iyDOI2rZapmZPpU9IHzKTM5mRMIMXD7zImsI1V2S76DV6FiUvckhoF0DRgUr2bSym1tiM3kNL8vAI+o6NJryH67Z2ulJhRSMr95aw+otSTC0W3vjOUKalRVxxjyOOt+ss5AeqktsRqkrzzl2YsrNp/OQTsFrxHjUSYbOhaLUE33O3y2qraa1h/an1rC5cTbBnMG/Neotgz2A2LdpEpE/kpfucEdolhKCsqJ7QWF8MXjramszo9Bom3tWb5GERGDy75x/j2mYzD76zn31n6tBrFab3jeTO4fGM6hlyzb0dGdjVWXTP3xVSp1T7r39R+cKf0QYFEXzPPQQuzsSjZ0+X1pRXlcc7x9/h43MfY1WtDAofREZKxqWogMsbO0DOvJueMHnLWpvMnNxTzvEdRurKW5hwZ+8L2egx9JsQ67Bx3El+WQPF1c3M7h9FkLceXw8dv5idSsbgWEJ8u9dnCjcjm7vkEsJmo2n7dkzZOQRmZOA3eRL+c+agj4rCd+pUNAbX7b+ubq3GW+eNt96b/Jp89pTt4Y7ed5CZkklSYJLTx7dZVD5+6zinDlWhWgWRPf2Z/J1Ueg2xLzV0t0iA5nYrGw4bWbm3hEMlJsL8PJjRNxKtRuFf9zv3SV6H2vEXiBkMieO//F7xNjh/EMb+1OHD3coZqv8E5gKV1zsgW1GUu4AnLnzZBPxQCJHn0CqlLsNSVoYpdzWm3FysZWVoQ0LwmzoVAH1kJPrZs11SlypUdht3k1OQw6cln/LUiKdY0nsJC3otYGHyQjy0zp0VtjSYqTjTQOKAULR6DeY2G/3GxZA2NpqQmM6ZOtgR1nxRyq/XHqOp3UpyuC+/npvGokExaN3xDS5mMGTfB4vftDf44m1ffu0EtzJzfxN4BXj7BteLgQlCiDpFUWYBrwMjHFOe1BVcXMIQQnDu/u9iPnsWn9GjiXjySfwmTURx4Szdptr4+5G/s7pwNcZmI0EeQdyddjcjo0YC4Klz3iEUQhWUnqjj2A4jxXlVKIrC/S+MxcNLx9wfpztt3M6ssc3C+jwjQ3oEkRrpT89QX6b3jeDO4fEM6RHk3g9fJY6HAXfAu0tg1MOw/x9fNnonuJUDsrcpipLwFdd3XfblHqB7LgZK1zCXnseUk03TJ1tJyMlGYzAQ9dyz6KKiMMS67reJTbVRaCokNTgVrUbL9vPbifOP45GhjzA5bjIGrfPfbEpP1rH1nXwaqtvw9NHTf2IsaWOju91DRmB/888rrWfV3nOszzPSYrbxk8m9SI30Jz0ukP+Nc86TvB1CCCjZC3HDQVHA0gLeobDtTzD+505r7OD4NffvAe/f6KKiKA8ADwDEx8c7eGjJ1apefoVTx/S9AAAgAElEQVTQhx6k8ZOtmLKzad65ExQF33HjsNXVoYmIwHvYMJfVV9ZUxpqiNawpWkNtay0fL/6YQM9A/jHjH05fdlFVQUl+LV6+esJ7+OMb5IFfiCcj5vek58AwdG4SI+toQgjueH0PnxfX4qXXclt6FEuHxzMwznW5+g7RVAV578KBt6D2FHzvQ3uD7zMP8tfbG/v+f0DiOKc1+Fva535h5r7hemvul90zCXgVGCuEqLnZa8p97l2LsNk40bcfPd79D2fvvAtdZCSBGRkEZixCHx3dYXVcHth18aGhgroC/nLgL+w07kQIwejo0WSkZDAxbiJ6jd4pdVxMZBy7OIUzR6o5vtNIU207vUdEMvX+NKeM2Rldvb/8Z9NTiA/x4cPjFTwxszeKovDGttN4GbTMHxiNn6dzfj06TGMFbH4C8jeAaoH4UTDkPkibD6X7brzm/jUafIfuc1cUZQDwd2DWrTR2qWtQzWaaPvqIuuxsPBLtx755DRpE/D//gfeIESjajp+NXgzs+vO+P/Ng+oMkBiRi0Bg4WXuS7/f/PouSFxHj6/z9zvs3FmMsrCfr+X0AxKYGMSYjmcR0xz2l2tldncZ43tTKo1l5CMDHoGXp8Dh6hPjwg/Gu3e76rTVWgOkcxA0DzwAoOwzDfwCD74Xw1C/vO3/wykaeON7+9fmDTpm9f+uZu6Io8cAnwHeuWn//SnLm7r7aTxdjyrZH69rq6q57T+iyZR2exmhsMjJnzRysqhWAcTHjeHXqq4B9nV2rce6bTWNtG+/8ajdCvfbPlFan4aFXJjp1/M5mzB8+uW5oV6CXnp1PTsbHw40/X1BtcGorHPgXFGyGwHh4+KB9XV0I+7+dxGEzd0VRVgITgVBFUUqBpwE9gBBiBfAbIAR49cIn2dZbGVhyL2p7O4rBgKIo1L71FqbcXPwmTyZw8WJ8xoxG0WjIT+3jsjTGt469xctfvHypsWvQEOjx5bqtsxq7zaZy9kgNx7YbOXe8BoR9ll5+qh6rRUWn19BzUBijM3o5ZfzOqLbZzOqDpTdMY6xvtbh3Yz+SAx89A/Ul4B0CI39kn6VfbOidZEfPreyWWXqT698Hvu+wiqROpb2o6MIsfR2xr72G9+BBhP7oh4Q9/GN0oa5bYjDbzGwt2crk+MnoNXqqW6ux2L587F9F5YOzH/Do0EcdGth1uYbqVnL/dICWBjM+AQaGzkqgz+goDm45S+nJOrR6DVarisFT2+UTGYUQ7D5dw8q9JWw5Wo7ZpuKl116Tow5umMZos0LRRxCVDv5RoPOEkCSY/hz0ngO6znngiRu/fUrOIsxm6jduwpSdTevBg6DX4zd1ChofHwD0ERHX/XkdkcZYXF9MbkEu60+tp669jlcmv8KEuAm0WFrQarSo6pfJf6pQWZG3wmGBXTarSnFeNe0tFvqOi8Ev2JOE/iEkpIfRo28wmgsn+LQ2mi/EBHSfRMZfrDnCyr0l+HvquHNEPEuHx5Nf1nDNCUhulcZoKoEv3oEv/g0N52HKb2DcY9Bnrv2fTk6mQkqX2Orr0QYEoLa3UzR+AtqgIAIXLyZg4QJ0wcEura22rZbHPn2M/RX70Sk6JsVPIjM5k5HRI9EoGjLXZ3Ky7uQ1P693UO9vnfdiqmjh+E4jJ3aX0dpoITTOlyW/GObeD9R8C6oq2HmqmlV7S3hyVipxwd7sO1NLSW0Ls/tH4XnZtk63TGNUVfjvXXDywq7uXlPsyy69Z4HW9bt5bnXNXTb3bk5taaHh/fepy8rCVmciafP7KBoN5tJS9DExLm1gRXVFnG08y5T4KahC5aEPH2JE1Ajm95rvtKWWqx3ccpbda06haBQS+ofQd1wMcWnBaNzx8fdvqbKhjewDpazad46S2lYCvfW8dPtAJvUOd3Vp317dGTj9GQy51/71hkft6+mD7oagHi4t7Woy8lf6Su2nT1P79ts0vLcBtbkZQ1ISwXfdCVYrGAwue4K01drKB2c+IKcgh0NVhwjzCmNi7ES0Gi2vT3/d6ePXlTdzbIeR3iMiCYvzIzY1iBHze9JndFSXXzf/Kk3tVsa/sJU2i8qoniH8bHpvZvSNvGKW3mndKLCrZJ997fzgW/adL4oGUmaAXyTM/V/X1esgsrl3I7amZlBtaP39aT91ivo1a/GfOZPA25fgNWiQy5cZNpzewPN7nqfR0kiCfwI/G/ozbku6zelbGK1mG6cOVnJsh5Gyono0GoWgCG/C4vwI7+HfLQ/BKKtvJWtfKcXVTfzljkH4euh4fmF/BsYF0jPMzYLMrhfYtepuUIC2evCPhYlP2mfpfpE3eTH3IZt7FyeEoO3oUUxZWdRv3ETId79L2I+X4TdxIsnbPkMbEOCy2losLWw+s5n0sHSSApOI84tjfNx4MpMzGRIxpEPebFRV8O4zn9NY20ZAmBejFiaROioKb//OuQPCmaw2lU9PVrFy7zm2nqxEFTAuOZQ2iw1PvZZFg900NipxPCx6A1Yuhd4z7bP0Ba/B4ZUw6Dv2NXUnTyBcQTb3Lqzuv1nUrVxJ+4kTKF5e+M+ehe+Fg6QVvd5ljf14zXFyCnLYVLyJZkszD6U/xLKBy0gPSyc9zLlpiJZ2G0UHKig9WcfU+9LQaBSGzU3AL8SLmJRAl//txZX+u7+EX645SpifBz+cmMTtQ+OJD/F2dVnfTnUhHHgTDr0L5ib7HvXxP4c+c+z/dGGyuXcBVS+/QtjDP0YIQXthIZ4pKQA079gOGoXIZ57Gf+5ctL6u/eu0EILvf/B99pbvxUPrwYyEGSxOWez0hg5QVdLI8e1GCvaWY26zERjhTWujBW9/A31Gd1z2TWdhsal8nF/Jyr3nmNM/iiXD4pjbP5pQXw8mp4ajv7Ct061teAT2/xM0OogdDhVHYfiDTg/s6ixkc+8CqpcvRxsQgCk7m/bCQpK2bMbQowfRf/wjGm/XzbyEEBytPsrWkq08POhhFEVhTMwYpvaYypyec/A3OH4t+2Jg1/Tv97v0AeiZI9VsXH4YrU5D0pAw+o6NIapXQJeepd9oC+K5mhZW7TtH9oFSqhrbifT3ZHZ/+zpzgLeeGX3deM25Mh8OvgMTn7BnvCSMs8cCBCfBhp/CHf+xN/Se479RYJe7kVsh3ZilrIzKl16iYf17AHgOGEDg4kwC5szp8KZ+eRqjQWtg4+mN5BbkcrLuJF46L3Ln5RLnF+f0Oj579wRHtxsJivSm77gY0ifHYbOoHNthJGV4BJ4+rt+n7GxXB3aB/eGh3y/qz792neFIqYnJqeEsHR7PhJQwdO48Sze3wPG19qWXks9Ba4Clq+zr6Bd18PF2zib3uXdR1ro6rFVVNG75gOrly6+57orALoDn9jxH9slsJsdPZuf5nbTZ2ugT3IfMlExmJ87G1+DcJaEVP/4Um1W95vsysOtLMYFe/O2eIYT4GogKcLMIgOtproa/Dob2eghJtu9RT18KPl07eVPuc+9ChKrSsncvpqwsGj/8CM+0NBL+u8q+zm61cqJff5cFdtW317MyfyWrC1cjEOw4v4PZibO5PfV2+ob07bA6olMCKTlee+lrrV5DUjcL7AJot9puGNhlNLXSL8Z1u6O+tfYmOJoLjWX2rYs+oTDyh/YZeY/RnSawq7OQzb2Tq1+/nqrly7GcPYcmIIDAO+4gcHHmpeuKruN/CYUQHKg4QG5hLh+c+QCzakbB/gdLFSoGrcGpjb29xcLJzyvI32Vk1kP98Q/xYuT8nugNGk7nVaPVabB1k8Cui8xWFYNOQ0nt9Rs7uGFg10XGL+zLLkdy7DteotJh/OP27YuTnnJ1dZ2WbO6djFBVmnftxit9AFo/P9SWFvRh4YQtW4bf9OloPK89sLkjArsu9+yeZ8kpyMFX78vMxJm8X/w+FtWeyGhRLawtWstD6Q85NCJACEH5qXqO7TBy6kAlVotKWLwfrY0W/EO8Lj1o1J0Cu9osNjYdKWPV3hLC/DxYftdgeoX78si0ZFZ8eopWy5fLVG4V2HW53a/ClqdA5wX9FtkzXi6eRyp9Jbnm3klYKiqpX7MaU04ultJSIp95hqA7bkcI4dJdHapQ2Ve+j5yCHB4d8ihRvlHsL99PaVMp03tM58UDL7KmcM2l5g6g1+hZlLzIIWmMF//7WxrMvPXkTrQGDSnDI+k7NpqweL9v/fruqLCikf98fo7VB0tpaLOSEOLNPaMS+N7YxEv3uGVglxBw/oB9lt5vESRNtme+FH4I/ReDl5ufq+ogcs3dTahmM+cffZSmrZ+CzYb3iBGEPfJT/KZNA3BZY69urWZd0TpWF67mXOM5/A3+zEuaR5RvFEMjhzIU+++tvMq8Kxo72GfvhyoPfeOxhRAYC00c226kvcXKbQ+n4+1vYO7D6UQk+mPw7H6/bVvMVgxaDTqthvV5Rt79/Bwz+0Vyx/A4RvUMueb3yYJBMZ2/mV/UaoLDWfaMl4qjoPeB6IH25h6UYD+yTvra5MzdBSzl5bTmHcZ/xnQASh9+GEOPHgRmZmJISHBtcUCTuYlJWZNos7UxJGIImSmZTI2fiqfu2iUhR2ptNHNiTznHdxgxVbRg8NLRe2QkYxcnd8sURoBjxnpW7j3Hui+M/O/tA5mWFkFdsxkBBPt0gYgEIeCVYVBTCFED7Tte+mWCZ/fL87lVjjxm75/AXKDyBmeoKsD/AbOBFuA+IcTBr19y1yasVpq2bceUlUXTtm0oej0+Y0aj9fUl9uWXXVpbZUsla4vWcrbhLL8b+zt8Db78YsQvSA9Pp2eAcw8vFqpACIFGq6FgbwW7couISgpgyKw+JA0OR2/oepkfN2OxqeQcKGXV3nPkldZj0GmY0z+KmAsfiAa5S1O/3v7y/I32AzDMTXDPGns++ozfgW84RA9yXa1d0K38/fZN4BXg7RtcnwUkX/hnBPDahX9LFzTt3EnZU7/AWlmJNiyUkB/8gMDMDJfGAdhUGzuNO8kpyGFb6TZswsaIqBGYbWYMWgMLkxc6dfzm+nZO7C7j+A4jQ2cn0Gd0NKmjIontE0RItJulDjqAEIKqxnbC/T3RKgrLtxbhY9Dx9G1pLBwUQ6C3mzT0y11MY8z8lz0C4LM/QfGnF64NsW9pDIy3x+xKDncrZ6huUxQl4StumQ+8LezrO3sURQlUFCVKCFHmoBrdjrBYaPz0U/Th4Xilp2OIi8MjtTeRv/k1vhMmoOhd/5RkTkEOv/38twR7BnNv33vJSM4g3j/eqWMKISjJr+X4diPFedWoqiA6ORCfQPt2RQ9vPR7erv9/05Ea2iysO2Rk5efnKG9oY/dTk/HQaVn9o9GE+Xq4d0RC4nj7I/6r7rY/aIRiP3N00lMQ2d/V1XV5jvhkKgYouezr0gvf6/LN/WJg10XmkhJM2TmY1qzGVlVNwMKF9uYeH0/8684/aOJGrKqV7aXbySnMYUbCDOYlzWNm4kyCvYKZGDsRvZOPDjO3WTF46lAUhT1rT9NY28aAKXGkjYkiKNLHqWN3VqeqmvjbZ6d4L6+MVouNtCh/HpmWwsWPwML9nPv5htOoKpzZbt/xEhgH056FEQ/AthdgzE9h2jOurrDbcERzv97U4rqf0iqK8gDwAEB8vHNniR2hevnyS83d+NQvqF+zBjQafCdMIHDxYnzHj3NpfeebzrO6cDVrC9dS2VpJmFcYk+MmAxDgEcC0HtMcNtbVgV2qKjh3rIZj242cL6jj3udH4+GtZ+YD9utavRvnmXxD9S0W2m02wv08qWkys+FwGQsGRbN0eDz9Y9w8yKypEg79Bw68BXXF4BkIIx60Z7js/6c9Znf/P6DX5C4d1tWZOKK5lwKXJ0LFAsbr3SiEeB14Hey7ZRwwtsuYz5wB7Eswil6PZ/9+6ONiCVy0CH1kxyXrXR7YFeoVesW++Mc+fYzjNccZGzOWX6b8kvGx49FpnLONcP/GYoxF9execwr/EE/yd5XRVNeOl7+B/hNiEReep/EPddOnJL+GK/eYe5IxJJbS2lY2Hinj9mFxPDu/H8MSgtj7y6n4erjxtk5VBc2FN+mP/we++Df0GAOTfgF9boPSfVemLyaO6xZpjJ3FLW2FvLDmvuEGu2XmAD/GvltmBPBXIcTwm72mO26FVM1mzj/2M5o+/PCaa64O7JqdOJso3yg2F28m67Ys/Ax+HK0+SohnCFG+UU4b/0aBXSgw84F+JAwIRevOqYNf0/USGQE8tAqLh8Vx5/AepEW7+Ta/hjI49G84+DYsedu+y6X2NNisEJby5X1dLI2xs3DkVsiVwEQgVFGUUuBpQA8ghFgBbMLe2Iuwb4W8/5uX3XmZS0o4s3gJNpMJfWwsgYsXU/XSSy4L7AIwNhovBXZtLN6IgsKE2AnUt9fjZ/CjX+g178UO1VDdSt9xURzbYUS1CoQAnV5DXN8QJixN6Ta5LhcJIfjtxvxrGjtAsK8Hv13gxh8iqjYo+ti+ll6wGYTN3rTVC2/swdfZMnu9Bp44Xs7aO8it7JZZepPrAujYcJMOoLa10bhlC7amJoLvugt9bCz+c+bgN2Uy3iNHomg0VL30kktqs6gW9Bo9Lx18CatqBUCDhjk95/D8uOedPv7ZozXkfVJCSX4tCuAT5EFTbTtavQarVcXHX9+tGnt1Uzu5B0pZta+E6qbr59mU17d1cFUOYm0HnQdY2yD3e/Yfj34YBn8HQpJcXZ30Fdx4wc852goKMGVlU79+PWpDA57pAwi6804URSHy11dmpXRkYFe7rZ2Pzn5EbmEuoV6hPD70cbaWbL10XUXlg7Mf8OjQRx0a2HVRfVULfiFeaDQKxiITdWXNDJuTSJ/RUezIKiChf2i3Cey6qLKhjf957zgfHC/HYhMMSwjC1GKmrsVyzb1ulchos0LhFvuHo/Ul8MNdYPCB+zZCWCro3HDPfTck4wcuU71iBVV/+T8UvR6/6dMJXLIE7+HDXLqL4XT9aXIKclh/aj317fXE+MawNHUp5xrPOTWwC8BmUTmdV8XxHUZKT9QxZ9kAEvqHYmm3odVrumUkQGVjG+frWhkUH0SbxcbMv2xjSp8I7hgWR3KE31eegtTps17qS+3LLl/82/6AkW8kDLobJvzcPmOXOgUZHHYL2vLzqcvKIjAzE6++ffEdPx7F05OA+fPRBQW5ri5rG3qNHq1Gy/qi9aw8sZLJcZPJTMlkRNQINIqGzPWZDg/susjcZmXfhmJO7CmnrcmCX7AnI+YlXkph1Ht0r0gAmyrYXljFqr0lfJRfQXywNx8/NgFPvZatP5t4xZv/xQbuNomMNgvYzPaZecnnsO3PkDwd5rwIyTNA261bhFvrdjN3W1MzDZs2YsrKpu3oURQPDyJ/82sCMzI6vJarFdQVkFuQy3un3+MP4/7A+Njx1LbVIoQgxCvEqWNbLTbqylsIi/NDVQXvPr2H0Fhf0sZGE9cnGKUbztIB1ucZ+eP7JzhvaiXYx0DmkFhuHxZHUpibRyTUnrbvdvniP/b96ON/Zl9fb6q0P3wkdVpy5n4dwmbj9Ny5WMvL8UhOJuKXvyRg3m1oA1x39JhFtbDh1AZyCnM4XHUYvUbPtB7TiPCOACDYM9ip49cYmzi+w8jJz8vRaBTu/f0YtDoNS58egVbXfbYwXmRTBZ8VVNIvOoBwf08MWoXEUB+emp3KtLQIPHRu8LeWr9qCGJRgf6io+DNQtPZcl7gLO5d1HrKxdyFdurnbGhtp2LCB5s/3EvPS/6JotYQ/9iiGuDg809NdupZe01pDiFcIGjS8lvcaXjovHh/6OPOS5hHo6fxDCYyFdexZe5qyU/VotAo9B4aRNi760jp6d2vs502tZO0rIWt/CWX1bTwxM5UfTkxiZr8oZvZz3nMCTnExsOviw0JH18Cmx+xf73oFaoth0q9g0F3gH+3iYiVn6XLNXQhBW14edVnZNLz/PqK1FY8+fbDV1qILCSHgtttcVluzpZlNxZvILcilrLmMjzI/Qq/V886sdwj3Dnf6m011aSMGLx3+IV4IAa1NFkYv6kXqqEi8/LrnDgibKnjwnQN8fKICgPHJYTx9WxpT+kS4uLJvIXE8LHwdVi4FryD7jpdFf7d/P7yv/UQjjRv8DUT6Vrpcc2/69FNKf/gjFG9vAubOJXDJEjz79XXpLP1M/RnePPYmm4o30WptJTkomQcGPICK/QGQCB/nNRJzm5WiA5Uc226k8kwDAybFMu72FKKTA7nzmRHunWfyDZXUtrDrVDW3D4tHq1EI9/fgx5N6sWRoHHHB3q4u79tprICdf4G8lfbMdHMTJIyHXlPs132c+9mN1Hm4ZXO/mMYohKD14EFMWVl4pPYh5P778BkzhqjfPoffzFlofV2XONhobsRsMxPiFUJVaxWbijcxM2EmGSkZDAgd0CFNdWdOIcd2GLG02QiK8mHs4mR6j7Tn3nS3pm62qnyUX8HKvefYUVSNRlGYlBpOuJ8nzy904ydHASyt0FRhX09XFPv+9JhBUHYYhj8IB/5pP75OPhnarbhlc69evhyNny+m7BzMp06h8fFB36MHABqDgcDMTJfUJYQgryqPnIIctpzZQkZKBk8Of5KhEUP5ePHH+Bkcf6Dz5WmMeoOWM0erSR4agaIo2KyCngPD6Ds2msgkN08dvAU3OhR6b3EtP/rPAaqbzEQHePLTKSksGRbrvrG6F1Ucs+9LP/xfiOgP92+0n2i0+F+w9odwx3/sDb3neBnY1Q25ZXMHqPzDH/FKTyfqd7/Df9ZMNN4d+9fpq9MYcwpy+E/+fygyFeGt82ZOzznMS5oH2GfJzmjsAPs2FmMsrGftS1/QVNeOtd1GcJQPobF+jL8j5eYv0EVc/fDQeVMrP885DMD4lDCG9AjijmHxjE8JQ+vu2zpPbILtL8L5/aA1QNp8GHzvl9cr869s5BcPzTh/UDb3bsRtmnvVy69QvXz5Fd9rzcvDZ+zYDm/sACvyVnCw4iAr8lbwq5G/4nDVYTy1njw96mlmJc7CR+/cJaGr0xhN5S0AaLQKITFuvgf7G3hhy8lrArvMNpUXtpxkwaAY/nbPTbcFd25leRCcBB6+YDoH7Y0w4/eQfgd4X7VdVgZ2SbjpQ0z5qX1clsZoajPxbv67rDi8AoHAoDGwJXML/gZ/DFrn7jgRQlB+ugFLm5WQWF92ZBVSdLASBGj1GpIGhTE6o1e3Cu26KOHJjdf9vgIU/2FOxxbjKO2NcCTHvvRSdghu+ysMudf+VKlGZ19fl7od+RCTg1W1VPHC/hf46OxHVzz2LxCXZu/O0tZs4eSeco7tMFJX1kx4Dz8WPzUMD2/7L59Wr8FmVTF4artNYy+oaOS/+0r46dRk/Dz1BHnr3T+w6yJrO2z6GRzJBUszhKfBrD9Bmn2ZDycfiyh1DW7Z3DsqjbGmtYby5nL6hvbF1+DL4arD3NbzNjac3oBZNQP2J0zXFq3lofSHnJLGePCDs+xdX4zNqhKe4M+ku1PpNTQcgNZGM/3Gx3SbNMZWs40Nh42s2lfCgbN1GLQaJvYOY1xyGE/f1ve6gV2Pz+jtwoq/hrZ6+5p40iT7k6I1p6HfQhh8H8QOlbN06Wtzy2UZZ1KFyp6yPeQW5PJJySfE+8Wzdv5aFEVBFSq/+/x3Tk1jbG0yc2J3OSnDIvAJ9KA4r4qS47WkjYsmNNY5H8q6g+qmdib9+VMa26z0DPPhzuHxLBocS7DPl0thN9ot02kJYT+K7sCbcHQ1IOBnBeAZYL8mG7p0HXJZ5hvYXLyZvxz8C+ebzhPgEcDS1KVkJmde2kKoUTTkVeY5PI1RqILzBXUc32Hk1KEqVKvAw1tH2phoEtPDSEwP+1b/Xe6oud3KhsNGKhra+cmUZEJ9PfjumERGJ4UwPDH4uts6FwyK6dzN/HJnd8HGx6DyOBh8If12GHKfvbGDbOzSt9atm7tNtbG7bDepwan2JRUFon2j+cmgnzClxxQ8tNeuX+fMy3FsDRaV//5uL3XlLXh46+g3Loa0sdHdcscLwJHSelbuO8e6L87TbLbRL8afZZN6odUoPDLNjbd2CgHndoOHH0T2B+9Q0HnCbf8H/TLs35ckB7rVA7JnAv8HaIG/CyH+cNX1eOAtIPDCPU8KITZ91Wu6clmmormCNUVrWF24mrLmMh4Z8gjf7ffdDhlbqILSE3VUnGlg6OwEAPasO0VQpA9Jg8LQGbpv5sfft5/mtxvz8dRrmNM/mjtHxDE4Psi9Hr66OpGxuQa2/g6Or4OWahhwOyx63bU1Sm7NkQdka4HlwDSgFNinKMp6IcTxy277FZAlhHhNUZQ07IdmJ3yjyp3Iptp47LPH2FqyFVWojIwayWNDH2Ny3GSnj91c307+rjLydxppqG7Dy0/PgEmxGLx0jJzf/c6iFEJwqMTEqr0lzBsYzZheoUxLi8Cg0zB/YAwBXm66I+TyRMYTm2DfG6BaITQVpj0LfRe4ukKpm7iVZZnhQJEQ4jSAoiirgPnA5c1dAP4XfhwAGB1Z5LdhbDL+//bOPLyq6tz/n/ecEBJCQoAkQCYI8xCQMYAMoqKAShFEBJxqHWqtba1Wr/d6rVaLtv1dW+/ttddrixerKAq1lSrigAJiqyQMIvMMGRjCPCRkOGf9/lgnEmIIAZK9z07ez/Och7MHzv48JyfvWVl7re8ie282EzpPwO/zExcZx/cyv8ekzpNIi3Mmu3rbqv188Md1mKAhpVs8QyZ0omPfRPxNGlesLsDR4jLeWZ3P61/uZuPe40Q38ZOZ2oJhnRNo3zqG24a6lwd00ZwotJEAN8y0Bb5Nph2Pft3z0P9Wt+2URkZtinsKkFtpOw8YXOWcJ4EPReRHQAwwuk7sLpCyYBlL85Yyb/M8Ps//HJ/4GJ4ynNbRrXlq2FP1fv0Th0+x4R97SEhtTsYlibTrFE/f0Wn0HJZMfBuPpw5eBMYYJr7wOdsPnCQzJY4ZEzP5ziXJxEZ5tJUOEAzCjr/Z5L0AABvqSURBVMV2xMvG92wr/bsLYOCdsPQ3MPIRLeyKK9SmuFfX4Vm1o34aMMsY85yIDAVeFZFMY0yw8kkicg9wD0B6evqF+J6TFftW8PCShyksLiQpOol7+tzDpC6T6nyZusqBXTEtmhIMBNm19iDrlxWwa+1BjIF+V6WTcUkizeIiuXRS5zq9vhc4UlTK2yvz+XjDPl75XhZN/D4eu7YHSbFR9E51b/WrOuPwLnhlPBzZBdGtYPC90P82m9CYM9MW9pyZkDFCp/4rjlOb4p4HVO6/SOXb3S53AmMBjDH/FJEoIAHYX/kkY8xLwEtgb6heiHDVwK6yQBmf5n5KXNM4hrQbQoe4DvRK6MWkzpMYkTqCCF/9DAjKeW8HBVuPkvPeDi6b3p13X1hD7vpDNIuLpP/Y9vQclkxcggdnR14AZ44vj2JivxTyDhezYO1eSsuDXJIWz/7jJaTER3t7EYxgALZ9AkUHbaZLizRIHQRX/hy6XwdNouxydpUTGDNGaCKj4grnHC0jIhHAZuBKIB/IBqYbY9ZVOud94E1jzCwR6QEsAlJMDS9+oaNlnv7iaeZumsu4jHG0iWnDO1vf4dCpQ1zd/mqeG/Xceb/e+VI1sKsCn18Yc3cm7Xu3xu9vPH3pVdMYK2jqF27KSmfqoHR6Jsed5X97hKP5sOo1WPWqXdUosQfc98/qx6LXtH5pdYFeinKe1Ha0TG2HQl4DPI8d5viyMWaGiDwF5Bhj5odGyPwRaI7tsnnEGPNhTa95IcW9sKiQcW+PoyRgp9n78HF5+uXc0OUGLk2+FH89Lx12tLCIrxblsn5ZAYFy+775I4RO/ZMaZWBXMGjIeuZjDpwo/dax5BZR/ONfr3TBqo75x3/DR4+DCULHy21wV7drIaJxLkuouE+dzlANjVlfUGXfzys9Xw8MO1/J8+XFNS8SDHXj+8TH+I7j+eXwX9b3ZQFb2F97/AvEJ8TER3LiUEmjDOwCKDxewrwVeczJ3l1tYQfYc/SUw1Z1xJFc20LvNRGSekDaYBj+U+h3K7TKcNtOUWqNZ2aoFhYV8s7Wd76Z+h80QRbuXMgDAx6ol8CuI/uKWL+sgGDAMHxKF1okNmPUzd1on5nAZ29uokPvhEYT2AW2le4LLXLx64Ubmbcij8EZrThWXOb9NMZAGWxeaJen2/qx3ReTGCrug+xDUTyGZ4p75VZ7BUETrNO43fKyANtXFbJ+WQH5m4/g8wmdByZhjEFE6DXC5paMu7fPN//nsmkeSR28QPYdO8XcnFzmZOfy4i0DyExpwf2Xd+YHozrRKbF5tX3unkpjDAbghcFwaBvEJsNlj0C/WyC+fkZzKYpTeKa410dgV1Wy39vJyoW7iEuIYsj1Hek+tF2j6m6pIBA0LNm8nzeW5/LJxv0EgoZLO7UmELT3GToknJ5oVBHU5Zk0xvJS2LQAdiyBa38LPj8M+QG0SIXOV4HfM78SilIjjTbyt7w0wNaV+1m/rIBB12SQ1rMVxw4Wc3R/MandWiJeX2fzAigpD9A0wk9RaTlZMxYR1cTH5AFpTB2UdkZB9yQHt8HKV2DVbJvx0iIN7v7ELiitKB5CI3/PwsH8E6xbVsDmL/dSUlROi6RoykNdCnGto4lr7aG+4jqgPBDk002FvLF8NwVHinn/JyNoFhnBnHuG0LVNLJERHhnWWdMQxDa9YPZkED90GwcD7rCLYtTz6CpFcZNGUdxN0CA+IRg0/P33X1F8opRO/ZLoNTyZ5K7x3kodrCMKjhTzxvLdvJWTy75jJSTFNmXKwDRKA0GaRvjJTPHYDNLKgV3N28AnM2DbxzBtTmii0RPQdzrEtnXbVFEcoUEX98Ldx0M3Rw8z9fEsfH4fY+7OJL5NNNHNG9845bJAkPKAITrST/bOQ/z3p1sZ1TWRpyekc0X3JCK8PPkqdRD0vx1enWjzXcAOZ6xoyY940D03RXGBBlfcS0+VsyV7H+uXFbB/13H8TXx07p9EaXGAqOY+2nXyWIu0Dth18CRzsnOZm5PHncMz+MGoTozNbMuyDleQ4qUhizXxl7tg47sQFQ+njsCQ+2HsDLetFMU1GkRxN8YQDBj8ET72bT/G4tmbaJUcw4ibutA1qy1RMR5OHbwIFny9h9lf7uLzrQfxCVzRvQ190+IBaBrh925hLz0J6/4KK1+FG/8P4pJh2AOQfikse+50YFe3MZrnojRaPFfcK6cxRkT62bJ8L+uWFZDarSXDJnchtXtLJv/LQJI6xDb4vvTqFoQe2qk1beKiAHgrJ5edB4p46Kqu3DgwjbYtolw2vkj2rLHRul/PhZJjkNDV5r7EJUN5sS3sGtilKIAHh0IueX0ja5cWEN+mGScOn6K8NEhCWnP6jk6n2+DGc7OsuslDPoGggc8ftd0tB0+UEN8sEr+Xh3UaYwO6TuyH57qBPxJ6Xm8Xk04fcjq8SwO7lEZCgxsKWTWN8ci+IsCmMU75t0ENvpVelf/3waZvJTEGDcRFRRATWoe1dXOPTsAyBgpW2VZ68SG46TU7Hv2m2dB+KES3/Pb/qa6AZ4zUVrvSaPFMcb91xlA+n7eVHasLKS8L4m/io1O/RC69oXOjKuzFpQEOnCih4EhxtcePnyonvplHRwKdOmq7XFa8AnvXQEQ09L7BRgT4/ND9GrcNFcUzeKa4x7RoSmSUn/LyYKNMY9yw5xhzlu/m7VX5ZCa3IDk+mvxqCrynArvAttKNAZ8PVv4ZPvx3aNMbrvkP6DMFohrf6CZFqQs8U9wBio+XkjkypVGlMX64bi9/WLyN1blHiPT7GNe7LdOy0tl79JS3A7uKD8Oat2wrfdiP7cpGfW+G9pdCcv/qF8JQFKXWeKq4N5Y0xrX5R+mYGEOzyAhyDxdzoqScx6/ryaR+KbSMObPLxTOBXWBb6Llf2r70dX+F8lPQru/p1nmzVvahKMpF47nRMg2VEyXlzF9dwBvLd/N1/lF+c0MfpgxKoywQJMIn3r6vUF4CEU1tcX9xBBzeCX1utDNKk/u6baconqLBjZZpqJSUB3jinXXM/6qAotIA3dvG8ovv9GJMLzuss0m4RwLUNAQxdaBtpW9dBA+sgaaxMHkmxKVA0+auKStKY6BWxV1ExgL/iV1D9U/GmF9Vc84U4EnsGqpfGWOm16Fng+LYqTK+zjvKsM4JNI3ws/3ASa7r045pWen0TfNYkFnlwK6MkbDhPXj7LoiOh4+fgKYt4JKbbOu9aSwkNtzuNEUJJ87ZLSMifmAzcBWQB2QD00Lrplac0wV4C7jCGHNYRJKMMftret3G1i1jjGHl7iO8sXw3764pACD7sdHERjX5ZqUnz7JtCcz7Lgy6C5a/ZLNd0obYiUY9J0BkM7cNFaXBUJfdMlnAVmPM9tALzwEmAOsrnXM38IIx5jDAuQp7Y+PL7Qd5/J21bN53gphIPxP7pTI9K53YKJt549nCfnwfrJ5tF8GIbQtLf2NzXfpOg1Yd3bZTlEZNbYp7CpBbaTsPGFzlnK4AIvI5tuvmSWPMwjox9CDGGLJ3HiYuOoLubeNoFRNJdBM/v5rUm/GXJBPT1OO3OnZ8Bsv/Fza9b+N12/S2N0krArsyRmhxVxSXqU2Vqa5ZWbUvJwLoAowCUoHPRCTTGHPkjBcSuQe4ByA93bsLEFcX2HV9vxQOnSzl7ZV5vLF8N9sKTzKpfwq/ndKXLm1ieef+4W5rXxzH9tgIAJ8ftnwIu/4BQ+6DpJ7w4WMw7XUN7FKUMKI2fe5DsS3xMaHtfwUwxjxb6ZwXgS+MMbNC24uAR40x2Wd7Xa/2uVcX2BXdxM/ADi35cvshSgNB+qfHMzUrnev6tKNZpIdb6cEAbPnIdrtsXgg3z4XOo21MQEQ0RERqYJeiOExd9rlnA11EJAPIB6YCVUfC/A2YBswSkQRsN83281P2BtUFdhWXBfgq9wjTB6czLSudbm1jXbKrI0pPwuf/Categ2P5EJMEw34CCaGRLpUjATSwS1HCknMWd2NMuYjcD3yA7U9/2RizTkSeAnKMMfNDx64WkfVAAHjYGHOwPsXdIBg01ea5gA3sevI7vRw2qkMCZXBoByR2BX9TWDUbknrA2F/ZRaX9jXPBE0XxKrXqMzDGLAAWVNn380rPDfBg6NEgyT1UxPQ/fXHW454L7Krg8E67otGq1+z2T9faQn7/coiMcVVNUZQLx8MdwvVLIGhYuqWQo0VlXN8vheT4aPqmtWRU10TmrsjjVNnpbHlPBXZVkLscFj8L2z61IV2dr7Lj0iU0I1YLu6J4Gi3uVdh79BRv5eTyZnYu+UeK6d42lgl9k/H7hN9P6wfAgPatvBXYVcHBbdAk2i5LV3oSCjfDqEeh3y3QItVtO0VR6hANDqvEH5du59n3NxA0MKJLAtOy0hndow2REWGe71IT5SWw8V2b8bJjKQz5IYx9BoJBwNihjYqieAYNDqsFeYeLeCs7l/GXJNOlTSz928dz72WdmDoonfTWDWDK/Ce/hJyXoeggtEiHK/4d+t5ij/k8/IWlKMo5aXTFvSwQZNGG/czJ3s2SzYUAJMZF0aVNLAPat2JAe4/kiVc3vnzLx7D2LzDxf+z2iX3QfpjtS+94uRZ0RWlENKriHggarv7dUnYcOEnbuCh+dEUXpgxMJbWlB1vpldMYYxLhk2dg498BA0N/CG0zYfx/6YpGitJIadDFvbQ8yEfr9/HP7Qd4ekImfp9wx7AOpMRHc1nXRCLCPSu9JjJGwphn4NWJNt8FoMMIGPmwjQQALeyK0ohpkMV9e+EJ3szOZd6KPA6eLCUlPpqDo0tJaN6U24Z2cFvv4tj7NRQfsRku3a+Dj56AE3th6P0wZobbdoqihAkNrrh/unE/d8zKxu8TRvdIYmpWOiO7JOL3ebgVW3IC1r1tR7zkr7Drjn5/CRSshGDZ6TTGrmN02r+iKIDHint1aYyZKS2Ys3w3nZOaMzUrnSEdW/PI2G5M7p9KUlyU28oXzxf/A5/MgNLjkNjdxgH0uckOa6ycvqhpjIqiVMIzxb1qGmP+kWIefGs1QQMRPuHO4RkAREf6uW9UZzdVL45Tx2DtPNvl0jwJYttBj/F2xEta1ul+9PyVZxbyjJF2O3+lFndFUbxT3KtLYwwaiIuKYNFDo0iMbeqSWR1gjO1uWTHLDmUsKwIEBt4Bva63j6poGqOiKDXgmeJeUEMao6cLe3kJ/OlKe6O0SQxk3gAD7rBDHRVFUS4QzxT35PjoauN2PZfGaAzkfmlb6kN/CBFNocNIGPg9yJwMUXFuGyqK0gDwTHF/eEy3aldA8kwaY9EhWPOm7Xop3GgXvOh3qy3mY59x205RlAaGZ4p7ReqiJ9MYN74Hc++AQAmkDIDv/B56TYKmzd02UxSlgeKZ4g62wHuimJ88CF+9Dok9oMtoSBkI/W+DAbdD295u2ymK0gjwVHEPC862IHTeCkjpBytesRG7gVIYfK8t7rFt4Nr/cM9ZUZRGR63CVURkrIhsEpGtIvJoDedNFhEjIufMGvYsFYFdO5ba7YrJRBvfhT9PgG2fwMA74b4vYNyv3TRVFKURc86Wu4j4gReAq4A8IFtE5htj1lc5Lxb4MfBlfYiGDRkj4Yb/gzk329WLju+FKa9A8WE7rLHHeLvakaIoiovUplsmC9hqjNkOICJzgAnA+irnPQ38BvhZnRqGE8f2wOrXYOWfoeQY7F9vR7zoxCFFUcKM2nTLpAC5lbbzQvu+QUT6AWnGmHdreiERuUdEckQkp7Cw8LxlXeXQDvhdL7u6UVQ8RDaH4Q/CpgWnu2gURVHChNoU9+riFL9ZeFVEfMDvgIfO9ULGmJeMMQONMQMTExNrb+kGR/Nh8a9h0VN2u1UGXP00TPxfOJYP096A0U/YPJfKffCKoihhQG2Kex6QVmk7FSiotB0LZAKLRWQnMASY78mbqoFy2LgAXr8Jns+Exc/Cgc12VinYGaXH9549sEtRFCVMEGNMzSeIRACbgSuBfCAbmG6MWXeW8xcDPzPG5NT0ugMHDjQ5OTWe4jyLnoLPnoPmbaHfLdD/VmjZwW0rRVGUbxCRFcaYczaez3lD1RhTLiL3Ax8AfuBlY8w6EXkKyDHGzL94XRcIlMGm920cwPAHbAu8782Q3N8ueuFv4rahoijKBVOrSUzGmAXAgir7fn6Wc0ddvFY9cmi7He2yajac3A9xKXYYI0DrTvahKIricRrHDFVj7CIXwQC8PA5OFtrW+YDvQufR4PO7bagoilKnNOzifmArrJwFOz6Duz+xRXzSS5DQBeKS3bZTFEWpNxpecS87BRv+bvvSdy0DXwR0GwfFRyCmNXS8zG1DRVGUeqfhFPdgwLbMd34Gb99lR7lc+YS9SRrbxm07RVEUR/FOca8ujXHLR7B6to0FaD8URj8Jna6A2+ZDhxHgq1UumqIoSoPDO8W9Io3xxlnQrDV8+oxdBAMDrTqdHo/u82vXi6IojR7vFPeKmaBzvwsxSVC4ATIug5EPQ4fhdjSMoiiKAtQyzz1syBhps9ILN8DQH8Ht8yFjhBZ2RVGUKniruO9YCjkzYeQjdhk7DetSFEWpFu8U94oVj26cBVc8pmmMiqIoNeCd4p6/UtMYFUVRaol3bqgOf+Db+zJG6ipIiqIo1eCdlruiKIpSa7S4K4qiNEC0uCuKojRAtLgriqI0QLS4K4qiNEDOuYZqvV1YpBDYdREvkQAcqCOdi0E9wssB1KMq6nEm4eBxMQ7tjTGJ5zrJteJ+sYhITm0WiVWPxuWgHurhBQ8nHLRbRlEUpQGixV1RFKUB4uXi/pLbAiHU4zTh4ADqURX1OJNw8Kh3B8/2uSuKoihnx8std0VRFOUsaHFXFEVpgHiyuIvIfWHg0FxE+otIvMPXjRQ5vfSUiFwuIg+JyDgHHfo4da1zISLpFT8DEekgIpNFJNMll4EiMlFExotId5ccWojITSLyoIj8NPTc0c9oTYjIVQ5fL05EOlWz37HPsIi0FZG2oeeJIjJJRHrV93XDvriHPqSVHw8BT1VsO+jxh0rPhwPrgeeAr0XkGqc8gGygopg9DMwAooEHReRZhxxWichWEXlaRHo6dM1vISKPAkuAL0TkLmAhMA540+HPxmUikgP8CngZ+D4wU0QWi0iagx63ASuBUUAzIAa4HFgROhYOzHTqQiIyBdgI/EVE1onIoEqHZznk8H3gn9jP6A+Ad4HrgLdF5M56vbgxJqwfwHHgTeDnwBOhx+GK5w56rKz0/FOgf+h5RyDHQY+1lZ7nANGh5xHAGoccVgGZ2C+WrcBXwKNAB4c/G+uwX2ytQ5+TxND+mMrvk0PvR8W1M4C/hp5fBXzooMcmIL6a/S2BzQ56zD/L4+/ASQc9VgPtQs+zsIV+UsXPzCGHr7FftK2BE0DbSj+T1fV5bS8s1tEL+C32F/YXxpgiEbndGPMLF53ijDErAYwx20XE7+C1j4lIpjFmLXb6chRQjC3uTv0lZkLXfwx4TESygKnAZyKSa4y51CGPgDGmWERKse/BwZDcSXF20XS/MaYw9Hw30D7k8ZGIPO+ghwDVDX8Lho45xQjgFmwxq4xgi6xT+I0xewCMMctF5HLgXRFJpfr3qT4oM8YUAUUiss0Yszfkc1hE6tUh7Iu7MWY3MFlEJgAficjvXFLpLiJrsB/QDiLSMvQD8gFNHPS4F5gtIl8B+4EcEVkC9AGeccjhjEJhjFkOLA91mTm5NNZKEXkd+8W/CHhFRBYCV2C7zZwiR0RmhhwmAIsBRKQZ4OQX/wzse/IhkBval479C+JpBz2+AIqMMUuqHhCRTQ56HBeRTsaYbQDGmD0iMgr4G7bR6ARBEWlijCkDrq3YKSJR1HNjzFPj3EO/LL8ABhtjHF1fT0TaV9m1xxhTKiIJwEhjzNsOuviBq4Gu2C/oPOADY8wRh64/3RjzuhPXOodHBHAjthU2D9sqnI5tPb9gjDnpkEcT4G6gJ7aL6mVjTEBEooEkY8zFBOSdr0tLYAyQgv0SrvhsHHbKIVwQkUuw3UBbq+xvAkwxxsx2wCEdKDDGlFfZnwL0MMZ8XG/X9lhxb4XtEnD1g6oe4eWgHorybbwwWiZdROaIjQj+EsgWkf2hfR0ascd+tzz0vQhPj5oQka/ddgD1cNIh7PvcsSNlngduNsYE4JtuiRuBOcAQ9XDcIxwc1KMKIjLpbIeAtk44qEf4OIR9t4yIbDHGdDnfY+rRsB3Uo9prlQGzqX4kyGRjTKx6OOvhpoMXivsc4BDwCqdHAKQBtwMJxpgp6uGsRzg4qEe1HiuA20PDVKseyzXGODKhSj3Cw8ELxT0SuBM7xKxiBEAudkLETGNMiXo46xEODupRrccIYFdo+HDVYwONMTnq4ayHmw5hX9wVRVGU8yfsR8tURkSuq2lbPZz3CAcH9VAPL3g47eCp4g4MOse2U6hHeDlUd131qHnbKdTDJQftllEURWmAeGGcO2KzsStuVhmgAJhvjNmgHu54hIODeqiHFzzccgj7bhkR+RfsRBABlmPzzAV4Q2yet3o47BEODuqhHl7wcNMh7LtlRGQz0CuUqlZ5fySwzsEJIuoRRg7qoR5e8HDTIexb7tgs6uRq9rcLHVMP5z3CwUE91MMLHq45eKHP/QFgkYhs4cyM6s7A/erhikc4OKiHenjBwzWHsO+WARC7IEYWZ2ZUZ1eENKmH8x7h4KAe6uEFD7ccvNByB3uHueIRrPSverjnEQ4O6qEeXvBwxSHsW+4icjXwB2ALkB/anYr9s+Y+Y8yH6uGsRzg4qId6eMHDVQfj0ErkF/oANgAdqtmfAWxQD+c9wsFBPdTDCx5uOnhhtEzFGqFVycfZhanVI7wc1EM9vODhmoMX+txfxi5bNoczs7KnAjPVwxWPcHBQD/XwgodrDmHf5w4gIj04Mys7Dzt9d716uOMRDg7qoR5e8HDLwRPFXVEURTk/vNDnriiKopwnWtwVRVEaIJ4s7iKS5LYDqEe4OYB6VEU9ziQcPJxyCPs+dxFpVXUXsALoh/U/pB7OeoSDg3qohxc83HTwQnEPAruq7E7F3nE2xpiO6uGsRzg4qId6eMHDVQenZotdxAyvnwELgd6V9u1QD/c8wsFBPdTDCx5uOjj6Zl/EG5QKzAV+C8QC29XDXY9wcFAP9fCCh1sOjr/ZF/kmjQe+APaqR3h4hIODeqiHFzycdgj7PveqiEg00MkYs1Y9wsMjHBzUQz284OGkgyeGQopIdxG5UkSaG2OKK94YERmrHu54hIODeqiHFzxcc3DzT6Va/inzY2AT8DdgJzCh0rGV6uG8Rzg4qId6eMHDTQdH3uSLfHO+BpqHnncAcoCfhLZXqYfzHuHgoB7q4QUPNx28EPnrN8acADDG7BSRUcA8EWmPnRCgHs57hIODeqiHFzxcc/BCn/teEelbsRF6o64DEoDe6uGKRzg4qId6eMHDNYewHy0jIqlAuTFmbzXHhhljPlcPZz3CwUE91MMLHm46hH1xVxRFUc4fL3TLKIqiKOeJFndFUZQGiBZ3RVGUBogWd0VRlAaIFndFUZQGyP8HKGlhyymlYIQAAAAASUVORK5CYII=\n",
886 | "text/plain": [
887 | ""
888 | ]
889 | },
890 | "metadata": {
891 | "needs_background": "light"
892 | },
893 | "output_type": "display_data"
894 | }
895 | ],
896 | "source": [
897 | "import matplotlib.pyplot as plt\n",
898 | "%matplotlib inline\n",
899 | "\n",
900 | "# Break up the data frame and graph each device separately. \n",
901 | "markers = ['o', 'x', '^', '+', '*']\n",
902 | "for i in range(5):\n",
903 | " df_segment = df[df['dev_id'] == i]\n",
904 | " plt.plot('mdatetime', 'value', data=df_segment, linestyle='--', marker=markers[i])\n",
905 | " \n",
906 | "plt.xticks(rotation=90)\n",
907 | "plt.show()"
908 | ]
909 | },
910 | {
911 | "cell_type": "markdown",
912 | "metadata": {},
913 | "source": [
914 | "It's more common to use ClickHouse to compute aggregates. Find the min, average, and max values for each device and likewise convert them to a data frame."
915 | ]
916 | },
917 | {
918 | "cell_type": "code",
919 | "execution_count": 10,
920 | "metadata": {},
921 | "outputs": [
922 | {
923 | "name": "stdout",
924 | "output_type": "stream",
925 | "text": [
926 | " * clickhouse://default:***@localhost/default\n",
927 | "Done.\n"
928 | ]
929 | },
930 | {
931 | "data": {
932 | "text/html": [
933 | "\n",
934 | "\n",
947 | "
\n",
948 | " \n",
949 | " \n",
950 | " | \n",
951 | " dev_id | \n",
952 | " min(value) | \n",
953 | " avg(value) | \n",
954 | " max(value) | \n",
955 | "
\n",
956 | " \n",
957 | " \n",
958 | " \n",
959 | " | 0 | \n",
960 | " 0 | \n",
961 | " 0.470658 | \n",
962 | " 0.920658 | \n",
963 | " 1.370658 | \n",
964 | "
\n",
965 | " \n",
966 | " | 1 | \n",
967 | " 1 | \n",
968 | " 0.308329 | \n",
969 | " 0.758329 | \n",
970 | " 1.208329 | \n",
971 | "
\n",
972 | " \n",
973 | " | 2 | \n",
974 | " 2 | \n",
975 | " 0.766993 | \n",
976 | " 1.216993 | \n",
977 | " 1.666993 | \n",
978 | "
\n",
979 | " \n",
980 | " | 3 | \n",
981 | " 3 | \n",
982 | " 0.880996 | \n",
983 | " 1.330996 | \n",
984 | " 1.780996 | \n",
985 | "
\n",
986 | " \n",
987 | " | 4 | \n",
988 | " 4 | \n",
989 | " 0.673713 | \n",
990 | " 1.123713 | \n",
991 | " 1.573713 | \n",
992 | "
\n",
993 | " \n",
994 | "
\n",
995 | "
"
996 | ],
997 | "text/plain": [
998 | " dev_id min(value) avg(value) max(value)\n",
999 | "0 0 0.470658 0.920658 1.370658\n",
1000 | "1 1 0.308329 0.758329 1.208329\n",
1001 | "2 2 0.766993 1.216993 1.666993\n",
1002 | "3 3 0.880996 1.330996 1.780996\n",
1003 | "4 4 0.673713 1.123713 1.573713"
1004 | ]
1005 | },
1006 | "execution_count": 10,
1007 | "metadata": {},
1008 | "output_type": "execute_result"
1009 | }
1010 | ],
1011 | "source": [
1012 | "result = %sql select dev_id, min(value), avg(value), max(value) from sensor_data group by dev_id order by dev_id\n",
1013 | "df2 = result.DataFrame()\n",
1014 | "df2"
1015 | ]
1016 | },
1017 | {
1018 | "cell_type": "markdown",
1019 | "metadata": {},
1020 | "source": [
1021 | "Let's put the average values per device into a nice bar chart. It's easy to add additional sets of bars or create subplots but this will do for today. "
1022 | ]
1023 | },
1024 | {
1025 | "cell_type": "code",
1026 | "execution_count": 11,
1027 | "metadata": {},
1028 | "outputs": [
1029 | {
1030 | "data": {
1031 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAEWCAYAAACJ0YulAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAAGSVJREFUeJzt3Xm0ZWV95vHvQxUgIIJa5UQxqYWABNEUSBaJooAWJIBJjAEnNEil7aAR7LRoIipqEqMGZUEaqxUJKCA4VmxsIM3khFIiEAEhJYhVAUKBgIhjkV//sffdHC93Krj7Hrj3+1nrrrWH97znt+/07PE9qSokSQLYYNgFSJIeOQwFSVLHUJAkdQwFSVLHUJAkdQwFSVLHUNCjWpJ3J/nUNPRzcpJ3TkdN0qOZoTDLJbk4yV1JNh52LY9kVfXfquq9w65DD2h/d98w7DrmGkNhFkuyHfB7QAEH9fQe8/voVzPPn6XAUJjtXgtcBpwKHDayMMmeSW5LMm9g2R8mubqd3iDJMUl+kOTOJGcneUK7brskleTwJD8CLmyXn9P2eU+SS5M8e6DvJyb5lyQ/SXJ5kvcl+drA+h2TXJDkx0muT/KK8TYoyfZJLklyb5ILgAWj1u+Z5BtJ7k5yVZK92+WHJFk5qu1RSVa006cmed/AuoOTXNnW/IMkS9vlWyT5RJJbk/xHuy3zGEN7auucJJ9q6/23JDskeXuS25OsTvKSgfbj9p3kGUkubH8edyT5dJItB177tvY197bfw33G2a69k6wZmP9h+9qrgfuSzE/ytCSfS7I2yU1J3tzTNr0uydeSfKg9mr0pyf7tuvfT7NCcmOSnSU5M4/j2fe5JcnWSXcb7XdFDVFV+zdIvYBXw34HfBn4NPHlg3Q+A/QbmzwGOaaffQhMmi4CNgY8BZ7brtqM58jgN2AzYpF3+Z8DmbfuPAFcO9H1W+7UpsDOwGvhau26zdv71wHzgecAdwLPH2aZvAv/Yvs8LgHuBT7XrtgLuBA6g2eHZr51f2L73vcDigb4uBw5pp08F3tdO7wHc075+g7bfHdt1X2y/H5sBTwK+Dfz5OLW+G/gF8NJ2204DbgL+GtgQOAK4aaD9uH0Dz2zr2bjdnkuBj7TrntV+D5828DN6xujtauf3BtYMzP8QuBLYGtik3d7vAMcCGwFPB24EXtrDNr2O5vfyCGAe8EbgFiDt+ouBNwz09dK2ti2BADsBTx3239ls+xp6AX719IOF323/4Ba0898HjhpY/z7glHZ6c+A+YNt2/jpgn4G2T237ms8DofD0Cd57y7bNFu0f+6+BZ41675FQ+FPgq6Ne/zHgXWP0uw2wDthsYNkZPBAKbwNOH/Wa84DD2ulPAce204tpQmLTdr7759m+//FjvP+TgV/SBmG77FDgonG+D+8GLhiYPxD4KTBv4Pte7fdrfft+GfDddvqZwO3AvsCGo9p129XO782DQ+HPBuafD/xoVB9vBz453dtEEwqrBtZt2r72Ke38xfxmKLwYuAHYE9hg2H9js/XLc4iz12HA+VV1Rzt/Rrvs+IH5byR5I/BHwBVVdXO7blvgC0n+a6C/+2n+yEesHploTwe8H/gTmr3YkdctoNn7nD/YftT0tsDzk9w9sGw+cPoY2/Q04K6qum9g2c00e7kjff1JkgMH1m8IXDSwzR8GjgNeCXyxqn42xvtsDZw7xvJt2/5uTTKybINR2zPafw5M/xy4o6ruH5gHeGy7beP2neRJwAk0p1Q2b9fdBVBVq5K8heYf9rOTnAccXVW3TFDXoNE/j6eN+nnMA7463dvUum1koqp+1rZ77FhFVtWFSU4ETgK2SfIF4H9U1U8m3UJNmaEwCyXZBHgFMC/JyB/dxsCWSZ5TVVdV1bVJbgb2p/kHecZAF6tp9h6/Pkbf27WTg8PrvhI4mGZP9Yc0Rwh30Rzir6XZu19Es5cHD/wTH3mvS6pqvyls2q3A45NsNhAM2wzUsprmSOGIcV5/PrAgyW40e6xHjdNuNfCMcZb/kuboa90U6l0fk/X9dzTbuWtV3ZnkZcCJIyur6gzgjCSPoznS+QDwGpojwE0H+nnKGH0P/ixX05z+WfxwNmagr4fz/XrQEM5VdQJwQhuSZwN/BXgr8TTyQvPs9DKaPfudgd3ar51o9vZeO9DuDODNNOfmzxlYfjLw/iTbAiRZmOTgCd5vc5o//jtp/gH97ciKdg/y88C7k2yaZMdRNXwZ2CHJa5Js2H7tnmSn0W/SHsmsBN6TZKMkv0tz+mLEp4ADk7w0ybwkj2kvrC5qX78O+CzwQeAJwAXjbM8ngNcn2SfNRfetkuxYVbfSBMuHkzyuXfeMJC+c4HszJVPoe3Oa0zR3J9mK5p8hAEmeleTFaW47/gXN3vrInvuVwAFJnpDkKTTXiybybeAn7cXnTdrv4y5Jdu9hmybznzTXNABofy+en2RDmrD7BQ9sp6aJoTA7HUZzDvhHVXXbyBfNnuWr8sCth2fSnGO+cOA0E8BHgRXA+Unupbno/PwJ3u80mtM4/wFc27YfdCTN0cNtNKeFzqQJEarqXuAlwCE0Fxlvo9nLHe+5ile2tfwYeFf73rR9raY5YnkHzRHKapp/noO/52fQHNGcM97ea1V9m+bC9/E0F5wvoTmtAk2gbdRu5100IfPUcWpdXxP1/R6ai/D3AP+HJmhHbAz8Pc0F+ttoLui+o113OnAVzRHc+cBnJiqgDfEDaXYkbmr7/DjNz2+6t2kyHwVe3t6ZdALwOOB/t/3cTLMT8qGHWJfGMXKVX5oxST5AczHxsEkbS5pRHimod2meQ9i1vc98D+Bw4AvDrkvSg/UWCklOaR8y+d4k7XZPcn+Sl/dVi4Zuc5rTHffRXBz8MPCloVYkaUy9nT5K8gKaC2OnVdWYTx22tzJeQHPB6JSq+mwvxUiSpqS3I4WqupTmYuBE3gR8jubBG0nSkA3tOYX2tro/pHlKccLb3ZIsA5YBbLbZZr+944479l+gJM0i3/nOd+6oqoWTtRvmw2sfAd5WVfcPPO04pqpaDiwHWLJkSa1cuXLC9pKk39Q+rDqpYYbCEuCsNhAW0Dxgs66qvjjEmiRpThtaKFTV9iPTSU4FvmwgSNJw9RYKSUaell2QZvz2d9EMjkVVndzX+0qSHrreQqGqDl2Ptq/rqw5J0tT5RLMkqWMoSJI6hoIkqWMoSJI6hoIkqePHcUpzwPEX3DB5o0eBo/bbYdglzHoeKUiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKnT24fsJDkF+APg9qraZYz1rwLe1s7+FHhjVV3VVz2a22bLh8yAHzSjfvV5pHAqsHSC9TcBL6yqXYH3Ast7rEWSNAW9HSlU1aVJtptg/TcGZi8DFvVViyRpah4p1xQOB74y3soky5KsTLJy7dq1M1iWJM0tQw+FJC+iCYW3jdemqpZX1ZKqWrJw4cKZK06S5pjeTh9NRZJdgY8D+1fVncOsRZI0xCOFJNsAnwdeU1Wz59YQSXoU6/OW1DOBvYEFSdYA7wI2BKiqk4FjgScC/5QEYF1VLemrHknS5Pq8++jQSda/AXhDX+8vSVp/Q7/QLEl65DAUJEkdQ0GS1DEUJEkdQ0GS1DEUJEmdoT7RLEl9c9j09eORgiSpYyhIkjqGgiSpYyhIkjqGgiSpYyhIkjqGgiSpYyhIkjqGgiSpYyhIkjqGgiSpYyhIkjqGgiSpYyhIkjqGgiSp01soJDklye1JvjfO+iQ5IcmqJFcneV5ftUiSpqbPI4VTgaUTrN8fWNx+LQP+V4+1SJKmoLdQqKpLgR9P0ORg4LRqXAZsmeSpfdUjSZrcMK8pbAWsHphf0y57kCTLkqxMsnLt2rUzUpwkzUXDDIWMsazGalhVy6tqSVUtWbhwYc9lSdLcNcxQWANsPTC/CLhlSLVIkhhuKKwAXtvehbQncE9V3TrEeiRpzpvfV8dJzgT2BhYkWQO8C9gQoKpOBs4FDgBWAT8DXt9XLZKkqektFKrq0EnWF/AXfb2/JGn9+USzJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKnT23MKj0THX3DDsEuYNkftt8OwS5A0C3mkIEnqGAqSpI6hIEnqGAqSpI6hIEnqGAqSpI6hIEnqGAqSpI6hIEnqGAqSpI6hIEnqGAqSpI6hIEnqGAqSpE6voZBkaZLrk6xKcswY67dJclGS7ya5OskBfdYjSZpYb6GQZB5wErA/sDNwaJKdRzX7G+DsqnoucAjwT33VI0maXJ9HCnsAq6rqxqr6FXAWcPCoNgU8rp3eArilx3okSZPoMxS2AlYPzK9plw16N/DqJGuAc4E3jdVRkmVJViZZuXbt2j5qlSTRbyhkjGU1av5Q4NSqWgQcAJye5EE1VdXyqlpSVUsWLlzYQ6mSJOg3FNYAWw/ML+LBp4cOB84GqKpvAo8BFvRYkyRpAn2GwuXA4iTbJ9mI5kLyilFtfgTsA5BkJ5pQ8PyQJA1Jb6FQVeuAI4HzgOto7jK6JslxSQ5qm70VOCLJVcCZwOuqavQpJknSDJk/WYMkTwb+FnhaVe3f3lb6O1X1icleW1Xn0lxAHlx27MD0tcBe6121JKkXUzlSOJVmb/9p7fwNwFv6KkiSNDyTHikAC6rq7CRvh+a0UJL7e65LPTj+ghuGXcK0OWq/HYZdgjQrTeVI4b4kT6S9nTTJnsA9vVYlSRqKqRwpHE1z19AzknwdWAi8vNeqJElDMWkoVNUVSV4IPIvmgbTrq+rXvVcmSZpxU7n76LWjFj0vCVV1Wk81SZKGZCqnj3YfmH4MzcNmVwCGgiTNMlM5ffQbg9Ql2QI4vbeKJElD81CeaP4ZsHi6C5EkDd9Urin8Cw+MbroBzQfmnN1nUZKk4ZjKNYUPDUyvA26uqjU91SNJGqKpXFO4ZCYKkSQN37ihkOReHvyhONA8q1BV9bgx1kmSHsXGDYWq2nwmC5EkDd9UrikAkORJNM8pAFBVP+qlIknS0Ex6S2qSg5L8O3ATcAnwQ+ArPdclSRqCqTyn8F5gT+CGqtqe5onmr/dalSRpKKYSCr+uqjuBDZJsUFUXAbv1XJckaQimck3h7iSPBb4KfDrJ7TTPK0iSZplxjxSSnJhkL+BgmqEt3gL8X+AHwIEzU54kaSZNdKTw7zRPMz8V+AxwZlX984xUJUkainGPFKrqo1X1O8ALgR8Dn0xyXZJ3JvEDciVpFpr0QnNV3VxVH6iq5wKvBP4IuG4qnSdZmuT6JKuSHDNOm1ckuTbJNUnOWK/qJUnTaiqjpG4ILAUOobkd9RLgPVN43TzgJGA/YA1weZIVVXXtQJvFwNuBvarqrvYBOUnSkEw09tF+wKHA7wPfBs4CllXVfVPsew9gVVXd2PZ3Fs1F62sH2hwBnFRVdwFU1e3rvQWSpGkz0emjdwDfBHaqqgOr6tPrEQgAWwGrB+bXtMsG7QDskOTrSS5LsnSsjpIsS7Iyycq1a9euRwmSpPUx0YB4L3qYfWesbsd4/8XA3sAi4KtJdqmqu0fVshxYDrBkyZKxRm6VJE2Dh/JxnFO1Bth6YH4RcMsYbb5UVb+uqpuA6/GjPiVpaPoMhcuBxUm2T7IRzYXqFaPafBF4EUCSBTSnk27ssSZJ0gR6C4WqWgccCZxHcwvr2VV1TZLjkhzUNjsPuDPJtcBFwF+14yxJkoZgyp+n8FBU1bnAuaOWHTswXcDR7Zckacj6PH0kSXqUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSZ1eQyHJ0iTXJ1mV5JgJ2r08SSVZ0mc9kqSJ9RYKSeYBJwH7AzsDhybZeYx2mwNvBr7VVy2SpKnp80hhD2BVVd1YVb8CzgIOHqPde4F/AH7RYy2SpCnoMxS2AlYPzK9pl3WSPBfYuqq+3GMdkqQp6jMUMsay6lYmGwDHA2+dtKNkWZKVSVauXbt2GkuUJA3qMxTWAFsPzC8CbhmY3xzYBbg4yQ+BPYEVY11srqrlVbWkqpYsXLiwx5IlaW7rMxQuBxYn2T7JRsAhwIqRlVV1T1UtqKrtqmo74DLgoKpa2WNNkqQJ9BYKVbUOOBI4D7gOOLuqrklyXJKD+npfSdJDN7/PzqvqXODcUcuOHaft3n3WIkmanE80S5I6hoIkqWMoSJI6hoIkqWMoSJI6hoIkqWMoSJI6hoIkqWMoSJI6hoIkqWMoSJI6hoIkqWMoSJI6hoIkqWMoSJI6hoIkqWMoSJI6hoIkqWMoSJI6hoIkqWMoSJI6hoIkqWMoSJI6vYZCkqVJrk+yKskxY6w/Osm1Sa5O8v+SbNtnPZKkifUWCknmAScB+wM7A4cm2XlUs+8CS6pqV+CzwD/0VY8kaXJ9HinsAayqqhur6lfAWcDBgw2q6qKq+lk7exmwqMd6JEmT6DMUtgJWD8yvaZeN53DgK2OtSLIsycokK9euXTuNJUqSBvUZChljWY3ZMHk1sAT44Fjrq2p5VS2pqiULFy6cxhIlSYPm99j3GmDrgflFwC2jGyXZF/hr4IVV9cse65EkTaLPI4XLgcVJtk+yEXAIsGKwQZLnAh8DDqqq23usRZI0Bb2FQlWtA44EzgOuA86uqmuSHJfkoLbZB4HHAuckuTLJinG6kyTNgD5PH1FV5wLnjlp27MD0vn2+vyRp/fhEsySpYyhIkjqGgiSpYyhIkjqGgiSpYyhIkjqGgiSpYyhIkjqGgiSpYyhIkjqGgiSpYyhIkjqGgiSpYyhIkjqGgiSpYyhIkjqGgiSpYyhIkjqGgiSpYyhIkjqGgiSpYyhIkjq9hkKSpUmuT7IqyTFjrN84yWfa9d9Ksl2f9UiSJtZbKCSZB5wE7A/sDByaZOdRzQ4H7qqqZwLHAx/oqx5J0uT6PFLYA1hVVTdW1a+As4CDR7U5GPjndvqzwD5J0mNNkqQJzO+x762A1QPza4Dnj9emqtYluQd4InDHYKMky4Bl7exPk1zfS8XTZwGjtmG6Hd1n5w9P79sOc3v73fZHpEfD7/22U2nUZyiMtcdfD6ENVbUcWD4dRc2EJCurasmw6xiGubztMLe3322fHdve5+mjNcDWA/OLgFvGa5NkPrAF8OMea5IkTaDPULgcWJxk+yQbAYcAK0a1WQEc1k6/HLiwqh50pCBJmhm9nT5qrxEcCZwHzANOqaprkhwHrKyqFcAngNOTrKI5Qjikr3pm2KPmVFcP5vK2w9zefrd9Fog75pKkET7RLEnqGAqSpI6hMI0mG9ZjNktySpLbk3xv2LXMtCRbJ7koyXVJrknyl8OuaSYleUySbye5qt3+9wy7ppmWZF6S7yb58rBrebgMhWkyxWE9ZrNTgaXDLmJI1gFvraqdgD2Bv5hjP/tfAi+uqucAuwFLk+w55Jpm2l8C1w27iOlgKEyfqQzrMWtV1aXM0WdMqurWqrqinb6X5p/DVsOtauZU46ft7Ibt15y5gyXJIuD3gY8Pu5bpYChMn7GG9Zgz/xjUaEf6fS7wreFWMrPa0ydXArcDF1TVXNr+jwD/E/ivYRcyHQyF6TOlITs0eyV5LPA54C1V9ZNh1zOTqur+qtqNZuSCPZLsMuyaZkKSPwBur6rvDLuW6WIoTJ+pDOuhWSrJhjSB8Omq+vyw6xmWqrobuJi5c31pL+CgJD+kOWX84iSfGm5JD4+hMH2mMqyHZqF2uPdPANdV1T8Ou56ZlmRhki3b6U2AfYHvD7eqmVFVb6+qRVW1Hc3f/IVV9eohl/WwGArTpKrWASPDelwHnF1V1wy3qpmT5Ezgm8CzkqxJcviwa5pBewGvodlLvLL9OmDYRc2gpwIXJbmaZufogqp61N+aOVc5zIUkqeORgiSpYyhIkjqGgiSpYyhIkjqGgiSpYyhozklyf3vb6DXtyJ5HJ3lIfwtJliQ5YRpqOjXJy9vpi9vRdq9O8v0kJ448ByD1zVDQXPTzqtqtqp4N7AccALzroXRUVSur6s3TWl3jVVW1K7ArzSikX+rhPaQHMRQ0p1XV7cAy4Mg05iX5YJLL2z31PwdI8pnBB9LaPfs/TrL3yBj6SR6b5JNJ/q197R+3y1+S5JtJrkhyTjtG0lTr+xXNYGvbJHnOdG67NBZDQXNeVd1I87fwJOBw4J6q2h3YHTgiyfY049r8KUA7jMk+wLmjunpn+9rfavfyL0yyAPgbYN+qeh6wEjh6Peu7H7gK2PEhbqI0ZfOHXYD0CDEyyu1LgF1Hzu8DWwCLga8AJyTZmGawt0ur6ufNsEedfWnGvwGgqu5qR9HcGfh623YjmuFAHmp9Uq8MBc15SZ4O3E/zWQAB3lRV543R7mLgpTRHDGeO1RUPHi49NGMBHfow6psH/Baz5JO99Mjm6SPNaUkWAicDJ1YzENh5wBvbobBJskOSzdrmZwGvB36vbTfa+TSDIo70/XjgMmCvJM9sl22aZIf1qG9D4O+A1VV19fpun7S+DAXNRZuM3JIK/CvNP/ORD5v/OHAtcEWS7wEf44Ej6vOBFwD/2l4AHu19wOOTfC/JVcCLqmot8DrgzHYU0cuY2rWBT7ftvwdsxhz6aFcNl6OkSpI6HilIkjqGgiSpYyhIkjqGgiSpYyhIkjqGgiSpYyhIkjr/H6366ib3DbP3AAAAAElFTkSuQmCC\n",
1032 | "text/plain": [
1033 | ""
1034 | ]
1035 | },
1036 | "metadata": {
1037 | "needs_background": "light"
1038 | },
1039 | "output_type": "display_data"
1040 | }
1041 | ],
1042 | "source": [
1043 | "plt.bar('dev_id', 'avg(value)', data=df2, align='center', alpha=0.5)\n",
1044 | "plt.title('Average device measurements')\n",
1045 | "plt.xlabel('Device ID')\n",
1046 | "plt.ylabel('Value')\n",
1047 | "plt.show()"
1048 | ]
1049 | },
1050 | {
1051 | "cell_type": "markdown",
1052 | "metadata": {},
1053 | "source": []
1054 | }
1055 | ],
1056 | "metadata": {
1057 | "kernelspec": {
1058 | "display_name": "Python 3",
1059 | "language": "python",
1060 | "name": "python3"
1061 | },
1062 | "language_info": {
1063 | "codemirror_mode": {
1064 | "name": "ipython",
1065 | "version": 3
1066 | },
1067 | "file_extension": ".py",
1068 | "mimetype": "text/x-python",
1069 | "name": "python",
1070 | "nbconvert_exporter": "python",
1071 | "pygments_lexer": "ipython3",
1072 | "version": "3.7.1"
1073 | }
1074 | },
1075 | "nbformat": 4,
1076 | "nbformat_minor": 2
1077 | }
1078 |
--------------------------------------------------------------------------------