├── .gitignore
├── LICENSE
├── README.md
├── data
├── countries-aggregated.csv
├── countries.geojson
├── reference.csv
└── us_confirmed.csv
├── docker
├── .env
├── Makefile
└── docker-compose.yml
├── docs
├── Makefile
├── make.bat
├── requirements.txt
└── source
│ ├── conf.py
│ ├── images
│ ├── dashboard.gif
│ ├── geoloop.png
│ ├── grafana_login.png
│ ├── influx.png
│ ├── postgres.png
│ ├── preview.gif
│ ├── us.png
│ └── worldmap.png
│ └── index.rst
└── scripts
├── delete_tables.sql
├── schema.sql
└── write_points.py
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | *.pyc
3 | scripts/__pychache__/
4 | docs/build/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Aleksey Piskun
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # docker-postgres-influxdb-grafana
2 |
3 | This tutorial provides a quick guide of how to install a dashboard environment
4 | from Grafana, Postgres and InfluxDB with docker-compose, create map overlays with Worldmap Panel plugin and
5 | build animated maps using GeoLoop Panel plugin.
6 |
7 | To illustrate the process of building the animated maps with GeoLoop,
8 | we will use time series data tracking the number of people affected by COVID-19 worldwide,
9 | including confirmed cases of Coronavirus infection, the number of people died while
10 | sick with Coronavirus, and the number of people recovered from it.
11 |
12 | The data is borrowed from “covid-19” [dataset][1]
13 | and stored as csv files in [data](https://github.com/viktorsapozhok/docker-postgres-influxdb-grafana/tree/master/data)
14 | directory.
15 |
16 | [Read the tutorial][2] for more.
17 |
18 |
19 |
20 | ## License
21 |
22 | MIT License (see [LICENSE](LICENSE)).
23 |
24 | [1]: https://github.com/datasets/covid-19
25 | [2]: https://viktorsapozhok.github.io/docker-postgres-grafana/ "Docker with postgres, influxdb and grafana"
26 |
--------------------------------------------------------------------------------
/data/countries.geojson:
--------------------------------------------------------------------------------
1 | geo(
2 | {
3 | "type": "FeatureCollection",
4 | "features": [
5 | {"type": "Feature", "id": 0, "properties": {"name": "Afghanistan"}, "geometry": {"type": "Point", "coordinates": [67.70995, 33.93911]}},
6 | {"type": "Feature", "id": 1, "properties": {"name": "Albania"}, "geometry": {"type": "Point", "coordinates": [20.1683, 41.1533]}},
7 | {"type": "Feature", "id": 2, "properties": {"name": "Algeria"}, "geometry": {"type": "Point", "coordinates": [1.6596, 28.0339]}},
8 | {"type": "Feature", "id": 3, "properties": {"name": "Andorra"}, "geometry": {"type": "Point", "coordinates": [1.5218, 42.5063]}},
9 | {"type": "Feature", "id": 4, "properties": {"name": "Angola"}, "geometry": {"type": "Point", "coordinates": [17.8739, -11.2027]}},
10 | {"type": "Feature", "id": 5, "properties": {"name": "Antigua and Barbuda"}, "geometry": {"type": "Point", "coordinates": [-61.7964, 17.0608]}},
11 | {"type": "Feature", "id": 6, "properties": {"name": "Argentina"}, "geometry": {"type": "Point", "coordinates": [-63.6167, -38.4161]}},
12 | {"type": "Feature", "id": 7, "properties": {"name": "Armenia"}, "geometry": {"type": "Point", "coordinates": [45.0382, 40.0691]}},
13 | {"type": "Feature", "id": 8, "properties": {"name": "Austria"}, "geometry": {"type": "Point", "coordinates": [14.5501, 47.5162]}},
14 | {"type": "Feature", "id": 9, "properties": {"name": "Azerbaijan"}, "geometry": {"type": "Point", "coordinates": [47.5769, 40.1431]}},
15 | {"type": "Feature", "id": 10, "properties": {"name": "Bahamas"}, "geometry": {"type": "Point", "coordinates": [-78.03589, 25.025885]}},
16 | {"type": "Feature", "id": 11, "properties": {"name": "Bahrain"}, "geometry": {"type": "Point", "coordinates": [50.55, 26.0275]}},
17 | {"type": "Feature", "id": 12, "properties": {"name": "Bangladesh"}, "geometry": {"type": "Point", "coordinates": [90.3563, 23.685]}},
18 | {"type": "Feature", "id": 13, "properties": {"name": "Barbados"}, "geometry": {"type": "Point", "coordinates": [-59.5432, 13.1939]}},
19 | {"type": "Feature", "id": 14, "properties": {"name": "Belarus"}, "geometry": {"type": "Point", "coordinates": [27.9534, 53.7098]}},
20 | {"type": "Feature", "id": 15, "properties": {"name": "Belgium"}, "geometry": {"type": "Point", "coordinates": [4.469936, 50.8333]}},
21 | {"type": "Feature", "id": 16, "properties": {"name": "Belize"}, "geometry": {"type": "Point", "coordinates": [-88.4976, 17.1899]}},
22 | {"type": "Feature", "id": 17, "properties": {"name": "Benin"}, "geometry": {"type": "Point", "coordinates": [2.3158, 9.3077]}},
23 | {"type": "Feature", "id": 18, "properties": {"name": "Bhutan"}, "geometry": {"type": "Point", "coordinates": [90.4336, 27.5142]}},
24 | {"type": "Feature", "id": 19, "properties": {"name": "Bolivia"}, "geometry": {"type": "Point", "coordinates": [-63.5887, -16.2902]}},
25 | {"type": "Feature", "id": 20, "properties": {"name": "Bosnia and Herzegovina"}, "geometry": {"type": "Point", "coordinates": [17.6791, 43.9159]}},
26 | {"type": "Feature", "id": 21, "properties": {"name": "Botswana"}, "geometry": {"type": "Point", "coordinates": [24.6849, -22.3285]}},
27 | {"type": "Feature", "id": 22, "properties": {"name": "Brazil"}, "geometry": {"type": "Point", "coordinates": [-51.9253, -14.235]}},
28 | {"type": "Feature", "id": 23, "properties": {"name": "Brunei"}, "geometry": {"type": "Point", "coordinates": [114.7277, 4.5353]}},
29 | {"type": "Feature", "id": 24, "properties": {"name": "Bulgaria"}, "geometry": {"type": "Point", "coordinates": [25.4858, 42.7339]}},
30 | {"type": "Feature", "id": 25, "properties": {"name": "Burkina Faso"}, "geometry": {"type": "Point", "coordinates": [-1.5616, 12.2383]}},
31 | {"type": "Feature", "id": 26, "properties": {"name": "Burma"}, "geometry": {"type": "Point", "coordinates": [95.956, 21.9162]}},
32 | {"type": "Feature", "id": 27, "properties": {"name": "Burundi"}, "geometry": {"type": "Point", "coordinates": [29.9189, -3.3731]}},
33 | {"type": "Feature", "id": 28, "properties": {"name": "Cabo Verde"}, "geometry": {"type": "Point", "coordinates": [-23.0418, 16.5388]}},
34 | {"type": "Feature", "id": 29, "properties": {"name": "Cambodia"}, "geometry": {"type": "Point", "coordinates": [104.9167, 11.55]}},
35 | {"type": "Feature", "id": 30, "properties": {"name": "Cameroon"}, "geometry": {"type": "Point", "coordinates": [11.5021, 3.848]}},
36 | {"type": "Feature", "id": 31, "properties": {"name": "Central African Republic"}, "geometry": {"type": "Point", "coordinates": [20.9394, 6.6111]}},
37 | {"type": "Feature", "id": 32, "properties": {"name": "Chad"}, "geometry": {"type": "Point", "coordinates": [18.7322, 15.4542]}},
38 | {"type": "Feature", "id": 33, "properties": {"name": "Chile"}, "geometry": {"type": "Point", "coordinates": [-71.543, -35.6751]}},
39 | {"type": "Feature", "id": 34, "properties": {"name": "Colombia"}, "geometry": {"type": "Point", "coordinates": [-74.2973, 4.5709]}},
40 | {"type": "Feature", "id": 35, "properties": {"name": "Congo (Brazzaville)"}, "geometry": {"type": "Point", "coordinates": [15.8277, -0.228]}},
41 | {"type": "Feature", "id": 36, "properties": {"name": "Congo (Kinshasa)"}, "geometry": {"type": "Point", "coordinates": [21.7587, -4.0383]}},
42 | {"type": "Feature", "id": 37, "properties": {"name": "Comoros"}, "geometry": {"type": "Point", "coordinates": [43.3333, -11.6455]}},
43 | {"type": "Feature", "id": 38, "properties": {"name": "Costa Rica"}, "geometry": {"type": "Point", "coordinates": [-83.7534, 9.7489]}},
44 | {"type": "Feature", "id": 39, "properties": {"name": "Cote d'Ivoire"}, "geometry": {"type": "Point", "coordinates": [-5.5471, 7.54]}},
45 | {"type": "Feature", "id": 40, "properties": {"name": "Croatia"}, "geometry": {"type": "Point", "coordinates": [15.2, 45.1]}},
46 | {"type": "Feature", "id": 41, "properties": {"name": "Cuba"}, "geometry": {"type": "Point", "coordinates": [-77.781166, 21.521757]}},
47 | {"type": "Feature", "id": 42, "properties": {"name": "Cyprus"}, "geometry": {"type": "Point", "coordinates": [33.4299, 35.1264]}},
48 | {"type": "Feature", "id": 43, "properties": {"name": "Czechia"}, "geometry": {"type": "Point", "coordinates": [15.473, 49.8175]}},
49 | {"type": "Feature", "id": 44, "properties": {"name": "Denmark"}, "geometry": {"type": "Point", "coordinates": [9.5018, 56.2639]}},
50 | {"type": "Feature", "id": 45, "properties": {"name": "Djibouti"}, "geometry": {"type": "Point", "coordinates": [42.5903, 11.8251]}},
51 | {"type": "Feature", "id": 46, "properties": {"name": "Dominica"}, "geometry": {"type": "Point", "coordinates": [-61.371, 15.415]}},
52 | {"type": "Feature", "id": 47, "properties": {"name": "Dominican Republic"}, "geometry": {"type": "Point", "coordinates": [-70.1627, 18.7357]}},
53 | {"type": "Feature", "id": 48, "properties": {"name": "Ecuador"}, "geometry": {"type": "Point", "coordinates": [-78.1834, -1.8312]}},
54 | {"type": "Feature", "id": 49, "properties": {"name": "Egypt"}, "geometry": {"type": "Point", "coordinates": [30.802498, 26.820553]}},
55 | {"type": "Feature", "id": 50, "properties": {"name": "El Salvador"}, "geometry": {"type": "Point", "coordinates": [-88.8965, 13.7942]}},
56 | {"type": "Feature", "id": 51, "properties": {"name": "Equatorial Guinea"}, "geometry": {"type": "Point", "coordinates": [10.2679, 1.6508]}},
57 | {"type": "Feature", "id": 52, "properties": {"name": "Eritrea"}, "geometry": {"type": "Point", "coordinates": [39.7823, 15.1794]}},
58 | {"type": "Feature", "id": 53, "properties": {"name": "Estonia"}, "geometry": {"type": "Point", "coordinates": [25.0136, 58.5953]}},
59 | {"type": "Feature", "id": 54, "properties": {"name": "Eswatini"}, "geometry": {"type": "Point", "coordinates": [31.4659, -26.5225]}},
60 | {"type": "Feature", "id": 55, "properties": {"name": "Ethiopia"}, "geometry": {"type": "Point", "coordinates": [40.4897, 9.145]}},
61 | {"type": "Feature", "id": 56, "properties": {"name": "Fiji"}, "geometry": {"type": "Point", "coordinates": [178.065, -17.7134]}},
62 | {"type": "Feature", "id": 57, "properties": {"name": "Finland"}, "geometry": {"type": "Point", "coordinates": [25.748152, 61.92411]}},
63 | {"type": "Feature", "id": 58, "properties": {"name": "France"}, "geometry": {"type": "Point", "coordinates": [2.2137, 46.2276]}},
64 | {"type": "Feature", "id": 59, "properties": {"name": "Gabon"}, "geometry": {"type": "Point", "coordinates": [11.6094, -0.8037]}},
65 | {"type": "Feature", "id": 60, "properties": {"name": "Gambia"}, "geometry": {"type": "Point", "coordinates": [-15.3101, 13.4432]}},
66 | {"type": "Feature", "id": 61, "properties": {"name": "Georgia"}, "geometry": {"type": "Point", "coordinates": [43.3569, 42.3154]}},
67 | {"type": "Feature", "id": 62, "properties": {"name": "Germany"}, "geometry": {"type": "Point", "coordinates": [10.451526, 51.16569]}},
68 | {"type": "Feature", "id": 63, "properties": {"name": "Ghana"}, "geometry": {"type": "Point", "coordinates": [-1.0232, 7.9465]}},
69 | {"type": "Feature", "id": 64, "properties": {"name": "Greece"}, "geometry": {"type": "Point", "coordinates": [21.8243, 39.0742]}},
70 | {"type": "Feature", "id": 65, "properties": {"name": "Grenada"}, "geometry": {"type": "Point", "coordinates": [-61.679, 12.1165]}},
71 | {"type": "Feature", "id": 66, "properties": {"name": "Guatemala"}, "geometry": {"type": "Point", "coordinates": [-90.2308, 15.7835]}},
72 | {"type": "Feature", "id": 67, "properties": {"name": "Guinea"}, "geometry": {"type": "Point", "coordinates": [-9.6966, 9.9456]}},
73 | {"type": "Feature", "id": 68, "properties": {"name": "Guinea-Bissau"}, "geometry": {"type": "Point", "coordinates": [-15.1804, 11.8037]}},
74 | {"type": "Feature", "id": 69, "properties": {"name": "Guyana"}, "geometry": {"type": "Point", "coordinates": [-58.93018, 4.860416]}},
75 | {"type": "Feature", "id": 70, "properties": {"name": "Haiti"}, "geometry": {"type": "Point", "coordinates": [-72.2852, 18.9712]}},
76 | {"type": "Feature", "id": 71, "properties": {"name": "Holy See"}, "geometry": {"type": "Point", "coordinates": [12.4534, 41.9029]}},
77 | {"type": "Feature", "id": 72, "properties": {"name": "Honduras"}, "geometry": {"type": "Point", "coordinates": [-86.2419, 15.2]}},
78 | {"type": "Feature", "id": 73, "properties": {"name": "Hungary"}, "geometry": {"type": "Point", "coordinates": [19.5033, 47.1625]}},
79 | {"type": "Feature", "id": 74, "properties": {"name": "Iceland"}, "geometry": {"type": "Point", "coordinates": [-19.0208, 64.9631]}},
80 | {"type": "Feature", "id": 75, "properties": {"name": "India"}, "geometry": {"type": "Point", "coordinates": [78.96288, 20.593683]}},
81 | {"type": "Feature", "id": 76, "properties": {"name": "Indonesia"}, "geometry": {"type": "Point", "coordinates": [113.9213, -0.7893]}},
82 | {"type": "Feature", "id": 77, "properties": {"name": "Iran"}, "geometry": {"type": "Point", "coordinates": [53.688046, 32.42791]}},
83 | {"type": "Feature", "id": 78, "properties": {"name": "Iraq"}, "geometry": {"type": "Point", "coordinates": [43.67929, 33.22319]}},
84 | {"type": "Feature", "id": 79, "properties": {"name": "Ireland"}, "geometry": {"type": "Point", "coordinates": [-7.6921, 53.1424]}},
85 | {"type": "Feature", "id": 80, "properties": {"name": "Israel"}, "geometry": {"type": "Point", "coordinates": [34.851612, 31.046051]}},
86 | {"type": "Feature", "id": 81, "properties": {"name": "Italy"}, "geometry": {"type": "Point", "coordinates": [12.56738, 41.87194]}},
87 | {"type": "Feature", "id": 82, "properties": {"name": "Jamaica"}, "geometry": {"type": "Point", "coordinates": [-77.2975, 18.1096]}},
88 | {"type": "Feature", "id": 83, "properties": {"name": "Japan"}, "geometry": {"type": "Point", "coordinates": [138.25293, 36.204823]}},
89 | {"type": "Feature", "id": 84, "properties": {"name": "Jordan"}, "geometry": {"type": "Point", "coordinates": [36.51, 31.24]}},
90 | {"type": "Feature", "id": 85, "properties": {"name": "Kazakhstan"}, "geometry": {"type": "Point", "coordinates": [66.9237, 48.0196]}},
91 | {"type": "Feature", "id": 86, "properties": {"name": "Kenya"}, "geometry": {"type": "Point", "coordinates": [37.9062, -0.0236]}},
92 | {"type": "Feature", "id": 87, "properties": {"name": "Korea South"}, "geometry": {"type": "Point", "coordinates": [127.76692, 35.907757]}},
93 | {"type": "Feature", "id": 88, "properties": {"name": "Kosovo"}, "geometry": {"type": "Point", "coordinates": [20.902977, 42.602634]}},
94 | {"type": "Feature", "id": 89, "properties": {"name": "Kuwait"}, "geometry": {"type": "Point", "coordinates": [47.481766, 29.31166]}},
95 | {"type": "Feature", "id": 90, "properties": {"name": "Kyrgyzstan"}, "geometry": {"type": "Point", "coordinates": [74.7661, 41.20438]}},
96 | {"type": "Feature", "id": 91, "properties": {"name": "Laos"}, "geometry": {"type": "Point", "coordinates": [102.4955, 19.85627]}},
97 | {"type": "Feature", "id": 92, "properties": {"name": "Latvia"}, "geometry": {"type": "Point", "coordinates": [24.6032, 56.8796]}},
98 | {"type": "Feature", "id": 93, "properties": {"name": "Lebanon"}, "geometry": {"type": "Point", "coordinates": [35.8623, 33.8547]}},
99 | {"type": "Feature", "id": 94, "properties": {"name": "Lesotho"}, "geometry": {"type": "Point", "coordinates": [28.2336, -29.61]}},
100 | {"type": "Feature", "id": 95, "properties": {"name": "Liberia"}, "geometry": {"type": "Point", "coordinates": [-9.429499, 6.428055]}},
101 | {"type": "Feature", "id": 96, "properties": {"name": "Libya"}, "geometry": {"type": "Point", "coordinates": [17.22833, 26.3351]}},
102 | {"type": "Feature", "id": 97, "properties": {"name": "Liechtenstein"}, "geometry": {"type": "Point", "coordinates": [9.55, 47.14]}},
103 | {"type": "Feature", "id": 98, "properties": {"name": "Lithuania"}, "geometry": {"type": "Point", "coordinates": [23.8813, 55.1694]}},
104 | {"type": "Feature", "id": 99, "properties": {"name": "Luxembourg"}, "geometry": {"type": "Point", "coordinates": [6.1296, 49.8153]}},
105 | {"type": "Feature", "id": 100, "properties": {"name": "Madagascar"}, "geometry": {"type": "Point", "coordinates": [46.869106, -18.766947]}},
106 | {"type": "Feature", "id": 101, "properties": {"name": "Malawi"}, "geometry": {"type": "Point", "coordinates": [34.3015, -13.2543]}},
107 | {"type": "Feature", "id": 102, "properties": {"name": "Malaysia"}, "geometry": {"type": "Point", "coordinates": [101.97577, 4.210484]}},
108 | {"type": "Feature", "id": 103, "properties": {"name": "Maldives"}, "geometry": {"type": "Point", "coordinates": [73.2207, 3.2028]}},
109 | {"type": "Feature", "id": 104, "properties": {"name": "Mali"}, "geometry": {"type": "Point", "coordinates": [-3.996166, 17.570692]}},
110 | {"type": "Feature", "id": 105, "properties": {"name": "Malta"}, "geometry": {"type": "Point", "coordinates": [14.3754, 35.9375]}},
111 | {"type": "Feature", "id": 106, "properties": {"name": "Mauritania"}, "geometry": {"type": "Point", "coordinates": [-10.9408, 21.0079]}},
112 | {"type": "Feature", "id": 107, "properties": {"name": "Mauritius"}, "geometry": {"type": "Point", "coordinates": [57.55215, -20.348404]}},
113 | {"type": "Feature", "id": 108, "properties": {"name": "Mexico"}, "geometry": {"type": "Point", "coordinates": [-102.5528, 23.6345]}},
114 | {"type": "Feature", "id": 109, "properties": {"name": "Moldova"}, "geometry": {"type": "Point", "coordinates": [28.3699, 47.4116]}},
115 | {"type": "Feature", "id": 110, "properties": {"name": "Monaco"}, "geometry": {"type": "Point", "coordinates": [7.4167, 43.7333]}},
116 | {"type": "Feature", "id": 111, "properties": {"name": "Mongolia"}, "geometry": {"type": "Point", "coordinates": [103.8467, 46.8625]}},
117 | {"type": "Feature", "id": 112, "properties": {"name": "Montenegro"}, "geometry": {"type": "Point", "coordinates": [19.37439, 42.70868]}},
118 | {"type": "Feature", "id": 113, "properties": {"name": "Morocco"}, "geometry": {"type": "Point", "coordinates": [-7.0926, 31.7917]}},
119 | {"type": "Feature", "id": 114, "properties": {"name": "Mozambique"}, "geometry": {"type": "Point", "coordinates": [35.529564, -18.665695]}},
120 | {"type": "Feature", "id": 115, "properties": {"name": "Namibia"}, "geometry": {"type": "Point", "coordinates": [18.4904, -22.9576]}},
121 | {"type": "Feature", "id": 116, "properties": {"name": "Nepal"}, "geometry": {"type": "Point", "coordinates": [84.25, 28.1667]}},
122 | {"type": "Feature", "id": 117, "properties": {"name": "Netherlands"}, "geometry": {"type": "Point", "coordinates": [5.2913, 52.1326]}},
123 | {"type": "Feature", "id": 118, "properties": {"name": "New Zealand"}, "geometry": {"type": "Point", "coordinates": [174.886, -40.9006]}},
124 | {"type": "Feature", "id": 119, "properties": {"name": "Nicaragua"}, "geometry": {"type": "Point", "coordinates": [-85.20723, 12.865416]}},
125 | {"type": "Feature", "id": 120, "properties": {"name": "Niger"}, "geometry": {"type": "Point", "coordinates": [8.081666, 17.607788]}},
126 | {"type": "Feature", "id": 121, "properties": {"name": "Nigeria"}, "geometry": {"type": "Point", "coordinates": [8.6753, 9.082]}},
127 | {"type": "Feature", "id": 122, "properties": {"name": "North Macedonia"}, "geometry": {"type": "Point", "coordinates": [21.7453, 41.6086]}},
128 | {"type": "Feature", "id": 123, "properties": {"name": "Norway"}, "geometry": {"type": "Point", "coordinates": [8.4689, 60.472]}},
129 | {"type": "Feature", "id": 124, "properties": {"name": "Oman"}, "geometry": {"type": "Point", "coordinates": [55.923256, 21.512583]}},
130 | {"type": "Feature", "id": 125, "properties": {"name": "Pakistan"}, "geometry": {"type": "Point", "coordinates": [69.3451, 30.3753]}},
131 | {"type": "Feature", "id": 126, "properties": {"name": "Panama"}, "geometry": {"type": "Point", "coordinates": [-80.7821, 8.538]}},
132 | {"type": "Feature", "id": 127, "properties": {"name": "Papua New Guinea"}, "geometry": {"type": "Point", "coordinates": [143.95555, -6.314993]}},
133 | {"type": "Feature", "id": 128, "properties": {"name": "Paraguay"}, "geometry": {"type": "Point", "coordinates": [-58.4438, -23.4425]}},
134 | {"type": "Feature", "id": 129, "properties": {"name": "Peru"}, "geometry": {"type": "Point", "coordinates": [-75.0152, -9.19]}},
135 | {"type": "Feature", "id": 130, "properties": {"name": "Philippines"}, "geometry": {"type": "Point", "coordinates": [121.77402, 12.879721]}},
136 | {"type": "Feature", "id": 131, "properties": {"name": "Poland"}, "geometry": {"type": "Point", "coordinates": [19.1451, 51.9194]}},
137 | {"type": "Feature", "id": 132, "properties": {"name": "Portugal"}, "geometry": {"type": "Point", "coordinates": [-8.2245, 39.3999]}},
138 | {"type": "Feature", "id": 133, "properties": {"name": "Qatar"}, "geometry": {"type": "Point", "coordinates": [51.1839, 25.3548]}},
139 | {"type": "Feature", "id": 134, "properties": {"name": "Romania"}, "geometry": {"type": "Point", "coordinates": [24.9668, 45.9432]}},
140 | {"type": "Feature", "id": 135, "properties": {"name": "Russia"}, "geometry": {"type": "Point", "coordinates": [105.318756, 61.52401]}},
141 | {"type": "Feature", "id": 136, "properties": {"name": "Rwanda"}, "geometry": {"type": "Point", "coordinates": [29.8739, -1.9403]}},
142 | {"type": "Feature", "id": 137, "properties": {"name": "Saint Kitts and Nevis"}, "geometry": {"type": "Point", "coordinates": [-62.782997, 17.357822]}},
143 | {"type": "Feature", "id": 138, "properties": {"name": "Saint Lucia"}, "geometry": {"type": "Point", "coordinates": [-60.9789, 13.9094]}},
144 | {"type": "Feature", "id": 139, "properties": {"name": "Saint Vincent and the Grenadines"}, "geometry": {"type": "Point", "coordinates": [-61.2872, 12.9843]}},
145 | {"type": "Feature", "id": 140, "properties": {"name": "San Marino"}, "geometry": {"type": "Point", "coordinates": [12.4578, 43.9424]}},
146 | {"type": "Feature", "id": 141, "properties": {"name": "Sao Tome and Principe"}, "geometry": {"type": "Point", "coordinates": [6.6131, 0.1864]}},
147 | {"type": "Feature", "id": 142, "properties": {"name": "Saudi Arabia"}, "geometry": {"type": "Point", "coordinates": [45.079163, 23.885942]}},
148 | {"type": "Feature", "id": 143, "properties": {"name": "Senegal"}, "geometry": {"type": "Point", "coordinates": [-14.4524, 14.4974]}},
149 | {"type": "Feature", "id": 144, "properties": {"name": "Serbia"}, "geometry": {"type": "Point", "coordinates": [21.0059, 44.0165]}},
150 | {"type": "Feature", "id": 145, "properties": {"name": "Seychelles"}, "geometry": {"type": "Point", "coordinates": [55.492, -4.6796]}},
151 | {"type": "Feature", "id": 146, "properties": {"name": "Sierra Leone"}, "geometry": {"type": "Point", "coordinates": [-11.779889, 8.460555]}},
152 | {"type": "Feature", "id": 147, "properties": {"name": "Singapore"}, "geometry": {"type": "Point", "coordinates": [103.8333, 1.2833]}},
153 | {"type": "Feature", "id": 148, "properties": {"name": "Slovakia"}, "geometry": {"type": "Point", "coordinates": [19.699, 48.669]}},
154 | {"type": "Feature", "id": 149, "properties": {"name": "Slovenia"}, "geometry": {"type": "Point", "coordinates": [14.9955, 46.1512]}},
155 | {"type": "Feature", "id": 150, "properties": {"name": "Somalia"}, "geometry": {"type": "Point", "coordinates": [46.199615, 5.152149]}},
156 | {"type": "Feature", "id": 151, "properties": {"name": "South Africa"}, "geometry": {"type": "Point", "coordinates": [22.9375, -30.5595]}},
157 | {"type": "Feature", "id": 152, "properties": {"name": "South Sudan"}, "geometry": {"type": "Point", "coordinates": [31.307, 6.877]}},
158 | {"type": "Feature", "id": 153, "properties": {"name": "Spain"}, "geometry": {"type": "Point", "coordinates": [-3.74922, 40.46367]}},
159 | {"type": "Feature", "id": 154, "properties": {"name": "Sri Lanka"}, "geometry": {"type": "Point", "coordinates": [80.7718, 7.873054]}},
160 | {"type": "Feature", "id": 155, "properties": {"name": "Sudan"}, "geometry": {"type": "Point", "coordinates": [30.2176, 12.8628]}},
161 | {"type": "Feature", "id": 156, "properties": {"name": "Suriname"}, "geometry": {"type": "Point", "coordinates": [-56.0278, 3.9193]}},
162 | {"type": "Feature", "id": 157, "properties": {"name": "Sweden"}, "geometry": {"type": "Point", "coordinates": [18.643501, 60.128162]}},
163 | {"type": "Feature", "id": 158, "properties": {"name": "Switzerland"}, "geometry": {"type": "Point", "coordinates": [8.2275, 46.8182]}},
164 | {"type": "Feature", "id": 159, "properties": {"name": "Syria"}, "geometry": {"type": "Point", "coordinates": [38.996815, 34.802074]}},
165 | {"type": "Feature", "id": 160, "properties": {"name": "Taiwan*"}, "geometry": {"type": "Point", "coordinates": [121.0, 23.7]}},
166 | {"type": "Feature", "id": 161, "properties": {"name": "Tajikistan"}, "geometry": {"type": "Point", "coordinates": [71.2761, 38.861]}},
167 | {"type": "Feature", "id": 162, "properties": {"name": "Tanzania"}, "geometry": {"type": "Point", "coordinates": [34.88882, -6.369028]}},
168 | {"type": "Feature", "id": 163, "properties": {"name": "Thailand"}, "geometry": {"type": "Point", "coordinates": [100.99254, 15.870032]}},
169 | {"type": "Feature", "id": 164, "properties": {"name": "Timor-Leste"}, "geometry": {"type": "Point", "coordinates": [125.72754, -8.874217]}},
170 | {"type": "Feature", "id": 165, "properties": {"name": "Togo"}, "geometry": {"type": "Point", "coordinates": [0.8248, 8.6195]}},
171 | {"type": "Feature", "id": 166, "properties": {"name": "Trinidad and Tobago"}, "geometry": {"type": "Point", "coordinates": [-61.2225, 10.6918]}},
172 | {"type": "Feature", "id": 167, "properties": {"name": "Tunisia"}, "geometry": {"type": "Point", "coordinates": [9.537499, 33.886917]}},
173 | {"type": "Feature", "id": 168, "properties": {"name": "Turkey"}, "geometry": {"type": "Point", "coordinates": [35.2433, 38.9637]}},
174 | {"type": "Feature", "id": 169, "properties": {"name": "Uganda"}, "geometry": {"type": "Point", "coordinates": [32.290276, 1.373333]}},
175 | {"type": "Feature", "id": 170, "properties": {"name": "Ukraine"}, "geometry": {"type": "Point", "coordinates": [31.1656, 48.3794]}},
176 | {"type": "Feature", "id": 171, "properties": {"name": "United Arab Emirates"}, "geometry": {"type": "Point", "coordinates": [53.847816, 23.424076]}},
177 | {"type": "Feature", "id": 172, "properties": {"name": "United Kingdom"}, "geometry": {"type": "Point", "coordinates": [-3.436, 55.3781]}},
178 | {"type": "Feature", "id": 173, "properties": {"name": "Uruguay"}, "geometry": {"type": "Point", "coordinates": [-55.7658, -32.5228]}},
179 | {"type": "Feature", "id": 174, "properties": {"name": "Uzbekistan"}, "geometry": {"type": "Point", "coordinates": [64.58526, 41.37749]}},
180 | {"type": "Feature", "id": 175, "properties": {"name": "Venezuela"}, "geometry": {"type": "Point", "coordinates": [-66.5897, 6.4238]}},
181 | {"type": "Feature", "id": 176, "properties": {"name": "Vietnam"}, "geometry": {"type": "Point", "coordinates": [108.2772, 14.058324]}},
182 | {"type": "Feature", "id": 177, "properties": {"name": "West Bank and Gaza"}, "geometry": {"type": "Point", "coordinates": [35.2332, 31.9522]}},
183 | {"type": "Feature", "id": 178, "properties": {"name": "Western Sahara"}, "geometry": {"type": "Point", "coordinates": [-12.8858, 24.2155]}},
184 | {"type": "Feature", "id": 179, "properties": {"name": "Yemen"}, "geometry": {"type": "Point", "coordinates": [48.516388, 15.552727]}},
185 | {"type": "Feature", "id": 180, "properties": {"name": "Zambia"}, "geometry": {"type": "Point", "coordinates": [27.849333, -13.133897]}},
186 | {"type": "Feature", "id": 181, "properties": {"name": "Zimbabwe"}, "geometry": {"type": "Point", "coordinates": [29.154858, -19.015438]}},
187 | {"type": "Feature", "id": 182, "properties": {"name": "Australia"}, "geometry": {"type": "Point", "coordinates": [133.0, -25.0]}},
188 | {"type": "Feature", "id": 183, "properties": {"name": "Canada"}, "geometry": {"type": "Point", "coordinates": [-95.0, 60.0]}},
189 | {"type": "Feature", "id": 184, "properties": {"name": "China"}, "geometry": {"type": "Point", "coordinates": [114.3055, 30.5928]}},
190 | {"type": "Feature", "id": 185, "properties": {"name": "US"}, "geometry": {"type": "Point", "coordinates": [-100.0, 40.0]}}
191 | ]
192 | }
193 | )
--------------------------------------------------------------------------------
/docker/.env:
--------------------------------------------------------------------------------
1 | POSTGRES_CONTAINER=postgres
2 | POSTGRES_HOST=localhost
3 | POSTGRES_PORT=5433
4 | POSTGRES_USER=postgres
5 | POSTGRES_PASSWORD=password
6 | POSTGRES_DBNAME=grafana
7 |
8 | INFLUX_CONTAINER=influx
9 | INFLUX_HOST=localhost
10 | INFLUX_PORT=8086
11 | INFLUX_USER=influx
12 | INFLUX_PASSWORD=password
13 | INFLUX_DBNAME=grafana
14 |
15 | GRAFANA_CONTAINER=grafana
16 | GRAFANA_HOST=localhost
17 | GRAFANA_PORT=3000
18 | GRAFANA_ADMIN_USER=admin
19 | GRAFANA_ADMIN_PASSWORD=password
--------------------------------------------------------------------------------
/docker/Makefile:
--------------------------------------------------------------------------------
1 | # Usage: make COMMAND
2 | #
3 | # Commands
4 | # help Show help message.
5 | # postgres-console Login to postgres interactive terminal.
6 | # postgres-create-db Create postgres database.
7 | # postgres-init-schema Initialize postgres schema.
8 | # postgres-copy-data Write data to postgres tables.
9 | # postgres-delete-tables Delete postgres tables.
10 | # influx-console Login to InfluxDB CLI.
11 | # influx-copy-data Write data to InfluxDB.
12 | # build Build application.
13 | # service Start up application.
14 | # data-server Serve data directory.
15 | # stop Stop running application.
16 | # clean Stop app and remove containers.
17 | # clean-all Remove app, remove containers and volumes.
18 | #
19 | include .env
20 |
21 | PSQL = PGPASSWORD=$(POSTGRES_PASSWORD) \
22 | docker exec -i $(POSTGRES_CONTAINER) \
23 | psql -h $(POSTGRES_HOST) -p 5432 -U $(POSTGRES_USER)
24 |
25 | help:
26 | @head -18 Makefile
27 |
28 | postgres-console:
29 | PGPASSWORD=$(POSTGRES_PASSWORD) \
30 | docker exec -it $(POSTGRES_CONTAINER) \
31 | psql -h $(POSTGRES_HOST) -p 5432 -U $(POSTGRES_USER) -d $(POSTGRES_DBNAME)
32 |
33 | postgres-create-db:
34 | $(PSQL) -c "CREATE DATABASE $(POSTGRES_DBNAME)"
35 |
36 | postgres-init-schema:
37 | cat ../scripts/schema.sql | $(PSQL) -d $(POSTGRES_DBNAME)
38 |
39 | postgres-copy-data:
40 | cat ../data/reference.csv | $(PSQL) -d $(POSTGRES_DBNAME) \
41 | -c "COPY covid.countries_ref FROM STDIN CSV HEADER"
42 |
43 | cat ../data/us_confirmed.csv | $(PSQL) -d $(POSTGRES_DBNAME) \
44 | -c "COPY covid.us_confirmed FROM STDIN CSV HEADER"
45 |
46 | cat ../data/countries-aggregated.csv | $(PSQL) -d $(POSTGRES_DBNAME) \
47 | -c "COPY covid.countries_aggregated FROM STDIN CSV HEADER"
48 |
49 | postgres-delete-tables:
50 | cat ../scripts/delete_tables.sql | $(PSQL) -d $(POSTGRES_DBNAME)
51 |
52 | influx-console:
53 | docker exec -it $(INFLUX_CONTAINER) influx -database '$(INFLUX_DBNAME)'
54 |
55 | influx-copy-data:
56 | python ../scripts/write_points.py
57 |
58 | build:
59 | docker-compose up -d
60 | make postgres-create-database
61 | make postgres-init-schema
62 |
63 | service:
64 | docker-compose up -d
65 |
66 | data-server:
67 | python -m http.server --directory ../data/
68 |
69 | stop:
70 | docker-compose down
71 |
72 | clean:
73 | make stop
74 | docker system prune -af
75 |
76 | clean-all:
77 | make clean
78 | docker volume prune
79 |
--------------------------------------------------------------------------------
/docker/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | services:
4 | influx:
5 | image: influxdb:latest
6 | container_name: ${INFLUX_CONTAINER}
7 | restart: always
8 | ports:
9 | - "${INFLUX_PORT}:8086"
10 | volumes:
11 | - influx:/var/lib/influxdb
12 | environment:
13 | - INFLUXDB_HOST=${INFLUX_HOST}
14 | - INFLUXDB_DB=${INFLUX_DBNAME}
15 | - INFLUXDB_ADMIN_USER=${INFLUX_USER}
16 | - INFLUXDB_ADMIN_PASSWORD=${INFLUX_PASSWORD}
17 | networks:
18 | - influx
19 |
20 | postgres:
21 | image: library/postgres:latest
22 | container_name: ${POSTGRES_CONTAINER}
23 | restart: always
24 | ports:
25 | - "${POSTGRES_PORT}:5432"
26 | environment:
27 | POSTGRES_HOST: ${POSTGRES_HOST}
28 | POSTGRES_USER: ${POSTGRES_USER}
29 | POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
30 | volumes:
31 | - postgres:/var/lib/postgresql/data
32 | networks:
33 | - postgres
34 |
35 | grafana:
36 | image: grafana/grafana:latest
37 | container_name: ${GRAFANA_CONTAINER}
38 | restart: always
39 | ports:
40 | - "${GRAFANA_PORT}:3000"
41 | environment:
42 | GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER}
43 | GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD}
44 | GF_SERVER_ROOT_URL: http://${GRAFANA_HOST}:${GRAFANA_PORT}/grafana/
45 | GF_SERVER_SERVE_FROM_SUB_PATH: "true"
46 | GF_USERS_DEFAULT_THEME: "dark"
47 | GF_INSTALL_PLUGINS: grafana-worldmap-panel, citilogics-geoloop-panel
48 | volumes:
49 | - grafana:/var/lib/grafana:rw
50 | depends_on:
51 | - influx
52 | - postgres
53 | networks:
54 | - influx
55 | - postgres
56 |
57 | networks:
58 | influx:
59 | driver: bridge
60 | postgres:
61 | driver: bridge
62 |
63 | volumes:
64 | influx:
65 | postgres:
66 | grafana:
67 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = source
9 | BUILDDIR = build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=source
11 | set BUILDDIR=build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | sphinx
2 | sphinx_rtd_theme
--------------------------------------------------------------------------------
/docs/source/conf.py:
--------------------------------------------------------------------------------
1 | #import os
2 | #import sys
3 |
4 | #sys.path.insert(0, os.path.abspath('../..'))
5 |
6 | #import sphinx_rtd_theme
7 |
8 | project = 'docker-postgres-influxdb-grafana'
9 | copyright = '2020, viktorsapozhok'
10 | author = 'viktorsapozhok'
11 | user = 'viktorsapozhok'
12 |
13 | # Add any Sphinx extension module names here, as strings. They can be
14 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
15 | # ones.
16 | extensions = [
17 | 'sphinx.ext.napoleon',
18 | 'sphinx.ext.viewcode',
19 | ]
20 |
21 | # The suffix of source filenames.
22 | source_suffix = '.rst'
23 |
24 | # The master toctree document.
25 | master_doc = 'index'
26 |
27 | # The name of the Pygments (syntax highlighting) style to use.
28 | pygments_style = 'sphinx'
29 |
30 | language = "en"
31 |
32 | # The theme to use for HTML and HTML Help pages. See the documentation for
33 | # a list of builtin themes.
34 | html_theme = 'sphinx_rtd_theme'
35 |
36 | html_context = {
37 | 'display_github': True,
38 | 'github_user': user,
39 | 'github_repo': project,
40 | 'github_version': 'master',
41 | 'conf_py_path': '/docs/source/',
42 | }
43 |
44 | # Add any paths that contain custom static files (such as style sheets) here,
45 | # relative to this directory. They are copied after the builtin static files,
46 | # so a file named "default.css" will overwrite the builtin "default.css".
47 | html_static_path = []
48 |
--------------------------------------------------------------------------------
/docs/source/images/dashboard.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viktorsapozhok/docker-postgres-influxdb-grafana/0d106dd0cf46a775d542d0990f6524f1366ff199/docs/source/images/dashboard.gif
--------------------------------------------------------------------------------
/docs/source/images/geoloop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viktorsapozhok/docker-postgres-influxdb-grafana/0d106dd0cf46a775d542d0990f6524f1366ff199/docs/source/images/geoloop.png
--------------------------------------------------------------------------------
/docs/source/images/grafana_login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viktorsapozhok/docker-postgres-influxdb-grafana/0d106dd0cf46a775d542d0990f6524f1366ff199/docs/source/images/grafana_login.png
--------------------------------------------------------------------------------
/docs/source/images/influx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viktorsapozhok/docker-postgres-influxdb-grafana/0d106dd0cf46a775d542d0990f6524f1366ff199/docs/source/images/influx.png
--------------------------------------------------------------------------------
/docs/source/images/postgres.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viktorsapozhok/docker-postgres-influxdb-grafana/0d106dd0cf46a775d542d0990f6524f1366ff199/docs/source/images/postgres.png
--------------------------------------------------------------------------------
/docs/source/images/preview.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viktorsapozhok/docker-postgres-influxdb-grafana/0d106dd0cf46a775d542d0990f6524f1366ff199/docs/source/images/preview.gif
--------------------------------------------------------------------------------
/docs/source/images/us.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viktorsapozhok/docker-postgres-influxdb-grafana/0d106dd0cf46a775d542d0990f6524f1366ff199/docs/source/images/us.png
--------------------------------------------------------------------------------
/docs/source/images/worldmap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/viktorsapozhok/docker-postgres-influxdb-grafana/0d106dd0cf46a775d542d0990f6524f1366ff199/docs/source/images/worldmap.png
--------------------------------------------------------------------------------
/docs/source/index.rst:
--------------------------------------------------------------------------------
1 | Building animated maps with Grafana
2 | ===================================
3 |
4 | .. meta::
5 | :description lang=en:
6 | How to install Grafana, PostgreSQL and InfluxDB with docker-compose,
7 | create map overlays with Worldmap Panel, and build animated maps
8 | using GeoLoop Panel plugin.
9 | :keywords: postgresql, influxdb, grafana, geoloop panel, worldmap panel, animated map, docker-compose
10 | :google-site-verification: wkNtHJvBxvApbXh93yaO6fiT-TMEjcK6IFExr0vQ-Ng
11 |
12 | This tutorial provides a quick guide of how to install a dashboard environment
13 | from Grafana, Postgres and InfluxDB with docker-compose, create map overlays with Worldmap Panel plugin, and
14 | build animated maps using GeoLoop Panel plugin.
15 |
16 | To illustrate the process of building the animated maps with GeoLoop,
17 | we will use time series data tracking the number of people affected by COVID-19 worldwide,
18 | including confirmed cases of Coronavirus infection, the number of people died while
19 | sick with Coronavirus, and the number of people recovered from it.
20 |
21 | The data is borrowed from `“covid-19” dataset `__
22 | and stored as csv files in `data `__ directory.
23 |
24 | .. image:: /images/dashboard.gif
25 | :align: center
26 | :alt: Grafana dashboard example used Worldmap and GeoLoop Panel plugins to visualize "covid-19" data
27 |
28 | Quick Start
29 | -----------
30 |
31 | To start the application, install
32 | `docker-compose `__
33 | on the host, clone this repo and run docker-compose from the
34 | `docker `__
35 | directory.
36 |
37 | .. code-block:: bash
38 |
39 | $ cd docker && docker-compose up -d
40 |
41 | Starting influx ... done
42 | Starting postgres ... done
43 | Starting grafana ... done
44 |
45 | $ docker ps
46 |
47 | CONTAINER ID IMAGE PORTS NAMES
48 | e00c0bd0d4a5 grafana/grafana:latest 0.0.0.0:3000->3000/tcp grafana
49 | 2b33999d97b3 influxdb:latest 0.0.0.0:8086->8086/tcp influx
50 | c4453cac69eb postgres:latest 0.0.0.0:5433->5432/tcp postgres
51 |
52 | Three containers have been created and started. For the app services we expose the following ports:
53 | 3000 (grafana), 8086 (influx), 5432 (postgres). Note that we use ``HOST:CONTAINER`` mapping when specifying
54 | postgres ports in docker-compose file. Inside a docker container, postgres is running on port ``5432``,
55 | whereas the publicly exposed port outside the container is ``5433``.
56 |
57 | .. code-block:: bash
58 |
59 | version: '3'
60 |
61 | services:
62 | postgres:
63 | ports:
64 | - "5433:5432"
65 |
66 | Before we login to Grafana UI, we need to create PostgreSQL database. Note that we have already
67 | created InfluxDB database specifying ``INFLUXDB_DB`` environment variable in docker-compose file.
68 |
69 | To create postgres database we use
70 | `psql `__, postgres terminal, inside the docker container. See
71 | `Makefile `__
72 | for more details.
73 |
74 | .. code-block:: bash
75 |
76 | $ make -C docker/ postgres-create-db
77 | $ make -C docker/ postgres-init-schema
78 |
79 | Now we can login to the Grafana web UI in browser (http://localhost:3000/grafana/) with the login ``admin`` and
80 | password ``password`` and initialize data sources.
81 |
82 | .. image:: /images/grafana_login.png
83 | :align: center
84 | :alt: Grafana login
85 |
86 | Data Sources
87 | ------------
88 |
89 | Before we create a dashboard, we need to add InfluxDB and PostgreSQL data sources. Follow
90 | `this guide `__
91 | to find out how to do this.
92 |
93 | Here is the configuration parameters we use to add InfluxDB data source.
94 |
95 | .. image:: /images/influx.png
96 | :align: center
97 | :alt: Configuration parameters used to add InfluxDB data source
98 |
99 | And this is the configuration parameters we use to add PostgreSQL data source.
100 |
101 | .. image:: /images/postgres.png
102 | :align: center
103 | :alt: Configuration parameters used to add PostgreSQL data source
104 |
105 | The valid password for both data sources is ``password``. You can change the credentials in
106 | `docker/.env `__
107 | file before starting the service via ``docker-compose up``.
108 |
109 | Populating the Database
110 | -----------------------
111 |
112 | To illustrate the process of building the animated map with GeoLoop Panel plugin, we will use time series data
113 | tracking the number of people affected by COVID-19 worldwide, including confirmed cases of Coronavirus infection,
114 | the number of people died while sick with Coronavirus, the number of people recovered from it.
115 |
116 | We borrowed data from `"covid-19" dataset `__
117 | and store it as csv files in `data `__ directory:
118 |
119 | * `countries-aggregated.csv `__ - cumulative cases (confirmed, recovered, deaths) across the globe.
120 | * `us_confirmed.csv `__ - cumulative confirmed cases for US regions.
121 | * `reference.csv `__ - regions metadata, location, names.
122 |
123 | For writing this data to postgres tables we use ``COPY FROM`` command available via postgres console.
124 | See `Makefile `__
125 | for more details.
126 |
127 | .. code-block:: bash
128 |
129 | $ make -C docker/ postgres-copy-data
130 |
131 | After we have written data to the tables, we can login to terminal and view schema contents.
132 |
133 | .. code-block:: bash
134 |
135 | $ make -C docker/ postgres-console
136 |
137 | psql (12.3 (Debian 12.3-1.pgdg100+1))
138 | Type "help" for help.
139 |
140 | grafana=# \dt+ covid.*
141 | List of relations
142 | Schema | Name | Type | Owner | Size | Description
143 | --------+----------------------+-------+----------+---------+-------------
144 | covid | countries_aggregated | table | postgres | 1936 kB |
145 | covid | countries_ref | table | postgres | 496 kB |
146 | covid | us_confirmed | table | postgres | 74 MB |
147 | (3 rows)
148 |
149 | Now we calculate logarithm of the number of active cases and write it to InfluxDB database (measurement "covid").
150 | We can also login to influx database from console and view the database contents.
151 |
152 | .. code-block:: bash
153 |
154 | $ make -C docker/ influx-console
155 |
156 | Connected to http://localhost:8086 version 1.8.1
157 | InfluxDB shell version: 1.8.1
158 |
159 | > SHOW MEASUREMENTS
160 | name: measurements
161 | name
162 | ----
163 | covid
164 |
165 | > SHOW SERIES FROM covid LIMIT 5
166 | key
167 | ---
168 | covid,Country=Afghanistan
169 | covid,Country=Albania
170 | covid,Country=Algeria
171 | covid,Country=Andorra
172 | covid,Country=Angola
173 |
174 | Worldmap Panel
175 | --------------
176 |
177 | Let's visualize the number of confirmed cases across the US regions using Worldmap panel.
178 | This panel is a tile map that can be overlaid with circles representing data points from a query.
179 | It needs two sources of data: a location (latitude and longitude) and data that has link to a location.
180 |
181 | The screenshot below shows query and configuration settings we used.
182 |
183 | .. image:: /images/worldmap.png
184 | :align: center
185 | :alt: Configuring Worldmap Panel
186 |
187 | And as the result we obtain the following map.
188 |
189 | .. image:: /images/us.png
190 | :align: center
191 | :alt: Worldmap Panel example
192 |
193 | See Worldmap Panel plugin `documentation `__
194 | for more details.
195 |
196 | GeoLoop Panel
197 | -------------
198 |
199 | Now everything is ready to configure the GeoLoop panel and visualize Covid-19 growth rates.
200 | Following `this tutorial `__,
201 | we create a `GeoJSON `__
202 | with countries coordinates and wrap it up in a callback:
203 |
204 | .. code-block:: bash
205 |
206 | geo({ "type": "FeatureCollection", ... });
207 |
208 | To access geojson from grafana, we need to put it on a server somewhere. In this tutorial,
209 | we will confine ourselves to serving the local directory where geojson is stored
210 | (however, this approach is not recommended for production).
211 |
212 | .. code-block:: bash
213 |
214 | $ make -C docker/ data-server
215 |
216 | The GeoJSON URL: ``http://0.0.0.0:8000/countries.geojson``
217 |
218 | A further step is to obtain a free `MapBox API Key `__,
219 | the only thing is you need to create a mapbox account.
220 |
221 | Here is the panel configuration settings.
222 |
223 | .. image:: /images/geoloop.png
224 | :align: center
225 | :alt: Configuring GeoLoop Panel
226 |
227 | And that's how the panel looks like.
228 |
229 | .. image:: /images/preview.gif
230 | :align: center
231 | :alt: GeoLoop Panel
232 |
233 |
--------------------------------------------------------------------------------
/scripts/delete_tables.sql:
--------------------------------------------------------------------------------
1 | DROP TABLE covid.countries_aggregated;
2 | DROP TABLE covid.countries_ref;
3 | DROP TABLE covid.us_confirmed;
--------------------------------------------------------------------------------
/scripts/schema.sql:
--------------------------------------------------------------------------------
1 | CREATE SCHEMA IF NOT EXISTS covid;
2 |
3 | CREATE TABLE covid.countries_ref(
4 | uid INTEGER NOT NULL PRIMARY key,
5 | iso2 VARCHAR(2),
6 | iso3 VARCHAR(3),
7 | code3 INTEGER,
8 | fips INTEGER,
9 | admin2 VARCHAR(41),
10 | province_state VARCHAR(40),
11 | country_region VARCHAR(32),
12 | lat NUMERIC(11,8),
13 | long_ NUMERIC(13,9),
14 | combined_key VARCHAR(55),
15 | population INTEGER
16 | );
17 |
18 | CREATE TABLE covid.countries_aggregated(
19 | date DATE NOT NULL,
20 | country VARCHAR(32) NOT NULL,
21 | confirmed INTEGER,
22 | recovered INTEGER,
23 | deaths INTEGER,
24 | PRIMARY KEY(date, country)
25 | );
26 |
27 | CREATE TABLE covid.us_confirmed(
28 | uid INTEGER NOT NULL,
29 | iso2 VARCHAR(2),
30 | iso3 VARCHAR(3),
31 | code3 INTEGER,
32 | fips NUMERIC(7,1),
33 | admin2 VARCHAR(41),
34 | lat NUMERIC(19,15),
35 | combined_key VARCHAR(55),
36 | date DATE NOT NULL,
37 | confirmed INTEGER,
38 | long_ NUMERIC(18,14),
39 | country_region VARCHAR(32),
40 | province_state VARCHAR(40),
41 | PRIMARY KEY (uid, date)
42 | );
--------------------------------------------------------------------------------
/scripts/write_points.py:
--------------------------------------------------------------------------------
1 | from configparser import ConfigParser
2 | import os
3 |
4 | from influxdb import DataFrameClient
5 | import numpy as np
6 | import pandas as pd
7 |
8 | root_dir = os.path.dirname(os.path.abspath(os.path.join(__file__, '..')))
9 |
10 | # get connection parameters
11 | config = ConfigParser()
12 | with open(os.path.join(root_dir, 'docker', '.env')) as file:
13 | config.read_string('[top]\n' + file.read())
14 | config = {s: dict(config.items(s)) for s in config.sections()}['top']
15 |
16 | # init influx client
17 | client = DataFrameClient(
18 | host=config['influx_host'], port=config['influx_port'],
19 | username=config['influx_user'], password=config['influx_password'],
20 | database=config['influx_dbname'])
21 |
22 | # read data
23 | df = pd.read_csv(os.path.join(root_dir, 'data', 'countries-aggregated.csv'))
24 | df['date'] = pd.to_datetime(df['Date'], format='%Y-%m-%d', utc=True)
25 | df['active'] = df['Confirmed'] - df['Recovered'] - df['Deaths']
26 | df['active_log'] = np.log(1 + 0.0001 * df['active'])
27 |
28 | # import to influx
29 | client.write_points(
30 | dataframe=df.set_index('date'), measurement='covid',
31 | tag_columns=['Country'], field_columns=['active_log'], protocol='line')
32 |
--------------------------------------------------------------------------------