diff --git a/.idea/dengue-singapore.iml b/.idea/dengue-singapore.iml
index 2bfa945..f7c20ac 100644
--- a/.idea/dengue-singapore.iml
+++ b/.idea/dengue-singapore.iml
@@ -7,7 +7,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 24eb271..cd18038 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,4 +3,5 @@
+
\ No newline at end of file
diff --git a/package.json b/package.json
index 8d598b7..1df37e3 100644
--- a/package.json
+++ b/package.json
@@ -11,9 +11,11 @@
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"autoprefixer": "^9.8.6",
+ "chart.js": "^2.9.3",
"leaflet": "^1.6.0",
"postcss-cli": "^7.1.1",
"react": "^16.13.1",
+ "react-chartjs-2": "^2.10.0",
"react-dom": "^16.13.1",
"react-helmet": "^6.1.0",
"react-leaflet": "^2.7.0",
diff --git a/python/download_dengue_data.py b/python/download_dengue_data.py
index f82ed15..9d93b83 100644
--- a/python/download_dengue_data.py
+++ b/python/download_dengue_data.py
@@ -22,7 +22,7 @@
z = zipfile.ZipFile(io.BytesIO(r.content))
file = z.open("dengue-clusters-kml.kml")
-soup = Soup(file.read(), 'lxml') # Parse as XML
+soup = Soup(file.read(), 'lxml') # Parse as XML
place_marks = soup.find_all('placemark')
@@ -30,7 +30,9 @@
for place_mark in place_marks:
- location_name = place_mark.find('td').string.split("(")[0].split("[")[0].split(",")[0].split("/")[0].strip()
+ location_name = \
+ place_mark.find('td').string.split("(")[0].split("[")[0].split(",")[0].split("/")[
+ 0].strip()
number_cases = int(place_mark.find('simpledata', {"name": "CASE_SIZE"}).string)
coordinates = place_mark.find('coordinates')
@@ -66,4 +68,4 @@
with open(save_dir, 'w') as fp:
json.dump(dict_to_export, fp)
-print("data correctly downloaded")
\ No newline at end of file
+print("data correctly downloaded")
diff --git a/python/download_infectious_disease.py b/python/download_infectious_disease.py
new file mode 100644
index 0000000..a153499
--- /dev/null
+++ b/python/download_infectious_disease.py
@@ -0,0 +1,73 @@
+import json
+from bs4 import BeautifulSoup as Soup
+import pandas as pd
+import requests
+import zipfile
+import io
+import os
+import numpy as np
+
+
+class NpEncoder(json.JSONEncoder):
+ def default(self, obj):
+ if isinstance(obj, np.integer):
+ return int(obj)
+ elif isinstance(obj, np.floating):
+ return float(obj)
+ elif isinstance(obj, np.ndarray):
+ return obj.tolist()
+ else:
+ return super(NpEncoder, self).default(obj)
+
+
+data_gov = "https://data.gov.sg/dataset/weekly-infectious-disease-bulletin-cases"
+data_gov = "https://data.gov.sg/api/action/datastore_search?resource_id=ef7e44f1-9b14-4680-a60a-37d2c9dda390&q=dengue"
+
+html_text = requests.get(data_gov).text
+soup = Soup(html_text, 'html.parser')
+
+data_id = soup.find('a', {"class": "ga-dataset-download"}).get("href")
+
+url_data = f"https://data.gov.sg{data_id}"
+
+r = requests.get(url_data, stream=True)
+z = zipfile.ZipFile(io.BytesIO(r.content))
+file = z.open("weekly-infectious-disease-bulletin-cases.csv")
+
+df = pd.read_csv(file)
+
+df_dengue = df[df.disease.isin(['Dengue Fever'])].copy()
+
+df_dengue[["year", "week"]] = df_dengue["epi_week"].str.split("-", expand=True)
+
+dict_to_export = {}
+
+color = ["#2ca02c", "#1f77b4", "#fcc105", "#ff7f0e", "#d62728", "#9467bd", "#800000",
+ "#2ca02c", "#1f77b4", "#fcc105", "#ff7f0e", "#d62728", "#9467bd"]
+
+for ix, year in enumerate(df_dengue["year"].unique()):
+
+ # if int(year) > 2016:
+
+ dict_to_export[year] = {}
+ dict_to_export[year]['cases'] = list(
+ df_dengue[df_dengue['year'] == year]['no._of_cases'].values)
+ dict_to_export[year]['color'] = color[ix]
+
+ # df_year = df_dengue[df_dengue['year'] == year]['no._of_cases'].values
+ #
+ # for week in df_dengue["week"].unique():
+ #
+ # df_week = df_dengue[df_dengue['week'] == week]
+ # dict_to_export[year][week] = df_week[["disease", "no._of_cases"]].set_index(
+ # "disease").to_dict()
+
+save_dir = os.path.join(os.path.dirname(os.getcwd()), "src", "Data",
+ "infectious_disease.json")
+
+save_dir = os.path.join('C:\\Users\\sbbfti\\Desktop\\github-projects\\dengue-singapore', "src", "Data", "infectious_disease.json")
+
+with open(save_dir, 'w') as fp:
+ json.dump(dict_to_export, fp, cls=NpEncoder)
+
+print("data correctly downloaded")
diff --git a/python/requirements.txt b/python/requirements.txt
index d9a1b63..06c5828 100644
--- a/python/requirements.txt
+++ b/python/requirements.txt
@@ -1,2 +1,3 @@
lxml==4.5.2
-beautifulsoup4==4.9.1
\ No newline at end of file
+beautifulsoup4==4.9.1
+pandas
\ No newline at end of file
diff --git a/src/Components/BarChartWeeklyDengue.js b/src/Components/BarChartWeeklyDengue.js
new file mode 100644
index 0000000..7abbbf2
--- /dev/null
+++ b/src/Components/BarChartWeeklyDengue.js
@@ -0,0 +1,129 @@
+import React from "react";
+
+import { Line } from "react-chartjs-2";
+
+function BarChartWeeklyDengue() {
+ const { innerWidth: width } = window;
+
+ let chartHeight;
+ if (width > 500) {
+ chartHeight = 250;
+ } else {
+ chartHeight = 350;
+ }
+
+ let weekly_disease = require("../Data/infectious_disease.json");
+
+ const data = {
+ labels: [
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ "10",
+ "11",
+ "12",
+ "13",
+ "14",
+ "15",
+ "16",
+ "17",
+ "18",
+ "19",
+ "20",
+ "21",
+ "22",
+ "23",
+ "24",
+ "25",
+ "26",
+ "27",
+ "28",
+ "29",
+ "30",
+ "31",
+ "32",
+ "33",
+ "34",
+ "35",
+ "36",
+ "37",
+ "38",
+ "39",
+ "40",
+ "41",
+ "42",
+ "43",
+ "44",
+ "45",
+ "46",
+ "47",
+ "48",
+ "49",
+ "50",
+ "51",
+ "52",
+ ],
+ datasets: [],
+ };
+
+ Object.keys(weekly_disease).map((year) => {
+ data.datasets.push({
+ label: year,
+ backgroundColor: "rgba(0, 0, 0, 0)",
+ borderColor: weekly_disease[year].color,
+ borderWidth: 1,
+ hoverBackgroundColor: weekly_disease[year].color,
+ hoverBorderColor: weekly_disease[year].color,
+ data: weekly_disease[year].cases,
+ yAxisID: "y1",
+ });
+ });
+
+ return (
+
+ );
+}
+
+export default BarChartWeeklyDengue;
diff --git a/src/Components/HomeView.js b/src/Components/HomeView.js
index c8ff0c4..4aa05f7 100644
--- a/src/Components/HomeView.js
+++ b/src/Components/HomeView.js
@@ -2,6 +2,7 @@ import React from "react";
import { Map, Polygon, Popup, TileLayer } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import TableCases from "./TableCases";
+import BarChartWeeklyDengue from "./BarChartWeeklyDengue";
function HomeView() {
const position = [1.35, 103.825];
@@ -44,11 +45,30 @@ function HomeView() {
))}
-
-
- Click on the cluster to learn more about the number of people that were
- infected.
+ {" "}
+
+ Click on each cluster to learn more about the number of cases since
+ start of that cluster.
+
+
+ This website uses data provided by the{" "}
+
+ Singaporean government.
+ {" "}
+ Data is updated on a daly basis at 1 am.{" "}
+
+
+ A dengue cluster is a locality where two or more cases have onset
+ within 14 days and are located within 150m of each other. While NEA
+ categorizes clusters in three alert levels: red (high risk with more
+ than 10 cases); yellow (high risk with less than 10 cases), and; green
+ (no new cases but under surveillance for 21 days). This website uses
+ another color legend to better distinguish between dengue's clusters.
+ See legend over the map for more information.
+
+
+
);
}
diff --git a/src/Data/infectious_disease.json b/src/Data/infectious_disease.json
new file mode 100644
index 0000000..fa94001
--- /dev/null
+++ b/src/Data/infectious_disease.json
@@ -0,0 +1,498 @@
+{
+ "2012": {
+ "cases": [
+ 74,
+ 64,
+ 60,
+ 50,
+ 84,
+ 87,
+ 65,
+ 50,
+ 55,
+ 45,
+ 64,
+ 72,
+ 48,
+ 52,
+ 81,
+ 77,
+ 64,
+ 86,
+ 96,
+ 80,
+ 80,
+ 81,
+ 99,
+ 87,
+ 128,
+ 151,
+ 140,
+ 131,
+ 124,
+ 110,
+ 94,
+ 127,
+ 115,
+ 92,
+ 102,
+ 75,
+ 73,
+ 72,
+ 99,
+ 103,
+ 122,
+ 105,
+ 84,
+ 104,
+ 99,
+ 87,
+ 99,
+ 80,
+ 78,
+ 104,
+ 92,
+ 111
+ ],
+ "color": "#2ca02c"
+ },
+ "2013": {
+ "cases": [
+ 132,
+ 204,
+ 219,
+ 264,
+ 292,
+ 322,
+ 246,
+ 294,
+ 247,
+ 272,
+ 307,
+ 305,
+ 314,
+ 402,
+ 491,
+ 505,
+ 536,
+ 547,
+ 556,
+ 611,
+ 637,
+ 742,
+ 813,
+ 805,
+ 838,
+ 802,
+ 676,
+ 540,
+ 389,
+ 305,
+ 288,
+ 255,
+ 378,
+ 338,
+ 382,
+ 449,
+ 337,
+ 370,
+ 402,
+ 439,
+ 435,
+ 371,
+ 495,
+ 457,
+ 401,
+ 442,
+ 365,
+ 372,
+ 347,
+ 380,
+ 371,
+ 414
+ ],
+ "color": "#1f77b4"
+ },
+ "2014": {
+ "cases": [
+ 436,
+ 479,
+ 401,
+ 336,
+ 234,
+ 273,
+ 369,
+ 193,
+ 186,
+ 209,
+ 224,
+ 210,
+ 225,
+ 240,
+ 244,
+ 235,
+ 282,
+ 251,
+ 261,
+ 291,
+ 427,
+ 456,
+ 458,
+ 506,
+ 550,
+ 671,
+ 888,
+ 818,
+ 744,
+ 633,
+ 484,
+ 545,
+ 438,
+ 418,
+ 367,
+ 339,
+ 362,
+ 396,
+ 344,
+ 339,
+ 278,
+ 297,
+ 213,
+ 186,
+ 168,
+ 158,
+ 149,
+ 162,
+ 212,
+ 177,
+ 198,
+ 188,
+ 158
+ ],
+ "color": "#fcc105"
+ },
+ "2015": {
+ "cases": [
+ 256,
+ 228,
+ 237,
+ 259,
+ 212,
+ 173,
+ 99,
+ 172,
+ 189,
+ 110,
+ 91,
+ 129,
+ 90,
+ 107,
+ 137,
+ 113,
+ 120,
+ 135,
+ 157,
+ 109,
+ 178,
+ 151,
+ 192,
+ 207,
+ 240,
+ 242,
+ 272,
+ 263,
+ 293,
+ 250,
+ 226,
+ 221,
+ 250,
+ 225,
+ 246,
+ 217,
+ 303,
+ 214,
+ 257,
+ 235,
+ 235,
+ 224,
+ 246,
+ 266,
+ 198,
+ 254,
+ 285,
+ 259,
+ 356,
+ 333,
+ 372,
+ 458
+ ],
+ "color": "#ff7f0e"
+ },
+ "2016": {
+ "cases": [
+ 549,
+ 628,
+ 635,
+ 629,
+ 528,
+ 420,
+ 592,
+ 508,
+ 412,
+ 396,
+ 373,
+ 306,
+ 376,
+ 290,
+ 225,
+ 231,
+ 244,
+ 181,
+ 217,
+ 212,
+ 198,
+ 219,
+ 159,
+ 192,
+ 215,
+ 234,
+ 246,
+ 223,
+ 266,
+ 221,
+ 211,
+ 197,
+ 221,
+ 274,
+ 310,
+ 242,
+ 174,
+ 173,
+ 138,
+ 125,
+ 94,
+ 108,
+ 84,
+ 85,
+ 84,
+ 72,
+ 74,
+ 86,
+ 59,
+ 81,
+ 72,
+ 64
+ ],
+ "color": "#d62728"
+ },
+ "2017": {
+ "cases": [
+ 70,
+ 90,
+ 74,
+ 66,
+ 62,
+ 77,
+ 51,
+ 54,
+ 41,
+ 32,
+ 34,
+ 32,
+ 49,
+ 37,
+ 32,
+ 51,
+ 37,
+ 42,
+ 48,
+ 48,
+ 50,
+ 66,
+ 62,
+ 79,
+ 73,
+ 75,
+ 63,
+ 53,
+ 51,
+ 66,
+ 60,
+ 56,
+ 52,
+ 51,
+ 33,
+ 40,
+ 53,
+ 58,
+ 39,
+ 51,
+ 55,
+ 62,
+ 77,
+ 62,
+ 44,
+ 50,
+ 24,
+ 37,
+ 33,
+ 40,
+ 51,
+ 66
+ ],
+ "color": "#9467bd"
+ },
+ "2018": {
+ "cases": [
+ 83,
+ 68,
+ 54,
+ 45,
+ 48,
+ 50,
+ 28,
+ 38,
+ 51,
+ 37,
+ 37,
+ 36,
+ 24,
+ 38,
+ 38,
+ 56,
+ 55,
+ 74,
+ 62,
+ 63,
+ 64,
+ 52,
+ 75,
+ 55,
+ 59,
+ 75,
+ 56,
+ 44,
+ 41,
+ 56,
+ 50,
+ 59,
+ 42,
+ 66,
+ 75,
+ 75,
+ 49,
+ 63,
+ 40,
+ 51,
+ 51,
+ 60,
+ 78,
+ 75,
+ 71,
+ 78,
+ 97,
+ 109,
+ 114,
+ 107,
+ 127,
+ 160
+ ],
+ "color": "#800000"
+ },
+ "2019": {
+ "cases": [
+ 205,
+ 245,
+ 207,
+ 221,
+ 179,
+ 135,
+ 232,
+ 181,
+ 156,
+ 133,
+ 109,
+ 96,
+ 99,
+ 108,
+ 125,
+ 134,
+ 156,
+ 192,
+ 287,
+ 307,
+ 376,
+ 400,
+ 396,
+ 464,
+ 430,
+ 492,
+ 591,
+ 661,
+ 644,
+ 601,
+ 597,
+ 521,
+ 522,
+ 474,
+ 412,
+ 326,
+ 314,
+ 299,
+ 258,
+ 243,
+ 226,
+ 239,
+ 241,
+ 306,
+ 321,
+ 372,
+ 329,
+ 295,
+ 280,
+ 257,
+ 226,
+ 290
+ ],
+ "color": "#2ca02c"
+ },
+ "2020": {
+ "cases": [
+ 302,
+ 342,
+ 402,
+ 307,
+ 370,
+ 400,
+ 378,
+ 380,
+ 373,
+ 375,
+ 389,
+ 367,
+ 377,
+ 315,
+ 341,
+ 360,
+ 399,
+ 390,
+ 502,
+ 527,
+ 622,
+ 732,
+ 870,
+ 1156,
+ 1373,
+ 1465,
+ 1449,
+ 1669,
+ 1729,
+ 1792,
+ 1379,
+ 1667,
+ 1339,
+ 1288
+ ],
+ "color": "#1f77b4"
+ }
+}
diff --git a/yarn.lock b/yarn.lock
index 6fdc680..91ea0d1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2968,6 +2968,29 @@ chardet@^0.7.0:
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
+chart.js@^2.9.3:
+ version "2.9.3"
+ resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.3.tgz#ae3884114dafd381bc600f5b35a189138aac1ef7"
+ integrity sha512-+2jlOobSk52c1VU6fzkh3UwqHMdSlgH1xFv9FKMqHiNCpXsGPQa/+81AFa+i3jZ253Mq9aAycPwDjnn1XbRNNw==
+ dependencies:
+ chartjs-color "^2.1.0"
+ moment "^2.10.2"
+
+chartjs-color-string@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz#1df096621c0e70720a64f4135ea171d051402f71"
+ integrity sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==
+ dependencies:
+ color-name "^1.0.0"
+
+chartjs-color@^2.1.0:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/chartjs-color/-/chartjs-color-2.4.1.tgz#6118bba202fe1ea79dd7f7c0f9da93467296c3b0"
+ integrity sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==
+ dependencies:
+ chartjs-color-string "^0.6.0"
+ color-convert "^1.9.3"
+
chokidar@^2.0.2, chokidar@^2.1.8:
version "2.1.8"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
@@ -3121,7 +3144,7 @@ collection-visit@^1.0.0:
map-visit "^1.0.0"
object-visit "^1.0.0"
-color-convert@^1.9.0, color-convert@^1.9.1:
+color-convert@^1.9.0, color-convert@^1.9.1, color-convert@^1.9.3:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
@@ -7153,6 +7176,11 @@ mkdirp@^0.5.5:
dependencies:
minimist "^1.2.5"
+moment@^2.10.2:
+ version "2.27.0"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.27.0.tgz#8bff4e3e26a236220dfe3e36de756b6ebaa0105d"
+ integrity sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==
+
move-concurrently@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
@@ -8985,6 +9013,14 @@ react-app-polyfill@^1.0.6:
regenerator-runtime "^0.13.3"
whatwg-fetch "^3.0.0"
+react-chartjs-2@^2.10.0:
+ version "2.10.0"
+ resolved "https://registry.yarnpkg.com/react-chartjs-2/-/react-chartjs-2-2.10.0.tgz#857e7f4788cae27e872624ba7826d53cf82f1ee6"
+ integrity sha512-1MjWEkUn8LLFf6GVyYUOrruJTW3yVU5hlEJOwGj3MiokuC+jH/BahjWVGAMonbe9UYbEIUbd2Rn36iVlC0Hb7w==
+ dependencies:
+ lodash "^4.17.19"
+ prop-types "^15.7.2"
+
react-dev-utils@^10.2.1:
version "10.2.1"
resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-10.2.1.tgz#f6de325ae25fa4d546d09df4bb1befdc6dd19c19"