From b31aef9c957ce01aa3efcd87acbb3eac91b876f6 Mon Sep 17 00:00:00 2001 From: mishaaaaaaa Date: Thu, 20 Oct 2022 15:29:13 +0300 Subject: [PATCH 1/8] downloaded articles and changed download scripts --- scripts/download_articles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/download_articles.py b/scripts/download_articles.py index cc61c17..e60d5df 100644 --- a/scripts/download_articles.py +++ b/scripts/download_articles.py @@ -65,7 +65,7 @@ def get_text(article): @transaction.atomic -def download(start_date='2019-1-1', end_date=str(datetime.now().date())): +def download(start_date='2010-1-1', end_date='2019-1-1'): print('downloading articles...') for date in pd.period_range(start_date, end_date, freq='M'): articles = fetch_articles(date.year, date.month) From 2d383f586c42acfb676ff457e090ad6208c7423d Mon Sep 17 00:00:00 2001 From: mishaaaaaaa Date: Thu, 20 Oct 2022 17:02:47 +0300 Subject: [PATCH 2/8] refactir fetch to usefetch hook&created folder for custome hooks; added loader --- frontend/src/App.js | 60 +++++++++++++++++------------ frontend/src/components/HomePage.js | 28 -------------- frontend/src/hooks/useFetch.js | 51 ++++++++++++++++++++++++ frontend/src/index.js | 7 ++-- 4 files changed, 90 insertions(+), 56 deletions(-) delete mode 100644 frontend/src/components/HomePage.js create mode 100644 frontend/src/hooks/useFetch.js diff --git a/frontend/src/App.js b/frontend/src/App.js index 2a878ec..ef3c02c 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,43 +1,46 @@ import React, { useState, useEffect } from "react"; -import { Grid, Container, Typography, Button } from "@mui/material/"; +import { Grid, Container, Typography, Box } from "@mui/material/"; import RangeDatePicker from "./components/RangeDatePicker"; import LineChart from "./components/LineChart"; +import CircularProgress from "@mui/material/CircularProgress"; import "../src/App.css"; +import useFetch from "./hooks/useFetch"; export default function App() { const [fetchData, setFetchData] = useState([]); const [sentiData, setSentiData] = useState({}); + const { get, post, loading } = useFetch(`/api?keyword=`); + console.log(loading); function handleGenerateClick(fromDate, toDate, word) { setFetchData([fromDate, toDate, word]); } useEffect(() => { - const url = `/api?keyword=${fetchData[2]}&start-date=${fetchData[0]}&end-date=${fetchData[1]}`; if (typeof fetchData[0] == "string") { - fetch(url) - .then((response) => response.json()) - .then((json) => { - console.log(json); - setSentiData({ - labels: json.map((uniqYear) => uniqYear.date), - datasets: [ - { - label: "sentiment to the word according to New York Times", - data: json.map((uniqYear) => uniqYear.sentiment), - backgroundColor: [ - "rgba(75,192,192,1)", - "#ecf0f1", - "#50AF95", - "#f3ba2f", - "#2a71d0", - ], - borderColor: "black", - borderWidth: 2, - }, - ], - }); + get( + `${fetchData[2]}&start-date=${fetchData[0]}&end-date=${fetchData[1]}` + ).then((json) => { + console.log(json); + setSentiData({ + labels: json.map((uniqYear) => uniqYear.date), + datasets: [ + { + label: "sentiment to the word according to New York Times", + data: json.map((uniqYear) => uniqYear.sentiment), + backgroundColor: [ + "rgba(75,192,192,1)", + "#ecf0f1", + "#50AF95", + "#f3ba2f", + "#2a71d0", + ], + borderColor: "black", + borderWidth: 2, + }, + ], }); + }); } }, [fetchData]); @@ -56,6 +59,15 @@ export default function App() { ) : ( )} + + {loading && } + diff --git a/frontend/src/components/HomePage.js b/frontend/src/components/HomePage.js deleted file mode 100644 index 3bbb4ac..0000000 --- a/frontend/src/components/HomePage.js +++ /dev/null @@ -1,28 +0,0 @@ -import React, { Component } from 'react'; -import { render } from "react-dom"; - -export default class HomePage extends Component { - constructor(props) { - super(props); - } - - render() { - return ( -
-

This is the homepage

-
- - -

- - -

- - -

- -
-
- ); - } -} \ No newline at end of file diff --git a/frontend/src/hooks/useFetch.js b/frontend/src/hooks/useFetch.js new file mode 100644 index 0000000..2749b79 --- /dev/null +++ b/frontend/src/hooks/useFetch.js @@ -0,0 +1,51 @@ +import { useState } from "react"; + +export default function useFetch(baseUrl) { + const [loading, setLoading] = useState(false); + + function get(url) { + setLoading(true); + return new Promise((resolve, reject) => { + fetch(baseUrl + url) + .then((response) => response.json()) + .then((data) => { + if (!data) { + return reject(data); + } + + resolve(data); + }) + .catch((error) => { + reject(error); + }) + .finally(() => setLoading(false)); + }); + } + + function post(url, body) { + return new Promise((resolve, reject) => { + fetch(baseUrl + url, { + method: "post", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }) + .then((response) => response.json()) + .then((data) => { + if (!data) { + setLoading(false); + return reject(data); + } + setLoading(false); + resolve(data); + }) + .catch((error) => { + setLoading(false); + reject(error); + }); + }); + } + + return { get, post, loading }; +} diff --git a/frontend/src/index.js b/frontend/src/index.js index ba03b4c..a97f5c6 100644 --- a/frontend/src/index.js +++ b/frontend/src/index.js @@ -1,6 +1,5 @@ -import App from "./App"; import React from "react"; -import { render } from "react-dom"; +import { createRoot } from "react-dom/client"; +import App from "./App"; -const appDiv = document.getElementById("app"); -render(, appDiv); +createRoot(document.querySelector("#app")).render(); From ca0956c712161958947a9099dd073b2d9ce24ea1 Mon Sep 17 00:00:00 2001 From: mishaaaaaaa Date: Thu, 20 Oct 2022 18:48:44 +0300 Subject: [PATCH 3/8] refactor chart component; decimation (now don work); tried to optimize chart building --- frontend/src/App.js | 11 ----------- frontend/src/components/LineChart.js | 29 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/frontend/src/App.js b/frontend/src/App.js index ef3c02c..7876536 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -10,7 +10,6 @@ export default function App() { const [fetchData, setFetchData] = useState([]); const [sentiData, setSentiData] = useState({}); const { get, post, loading } = useFetch(`/api?keyword=`); - console.log(loading); function handleGenerateClick(fromDate, toDate, word) { setFetchData([fromDate, toDate, word]); @@ -21,22 +20,12 @@ export default function App() { get( `${fetchData[2]}&start-date=${fetchData[0]}&end-date=${fetchData[1]}` ).then((json) => { - console.log(json); setSentiData({ labels: json.map((uniqYear) => uniqYear.date), datasets: [ { label: "sentiment to the word according to New York Times", data: json.map((uniqYear) => uniqYear.sentiment), - backgroundColor: [ - "rgba(75,192,192,1)", - "#ecf0f1", - "#50AF95", - "#f3ba2f", - "#2a71d0", - ], - borderColor: "black", - borderWidth: 2, }, ], }); diff --git a/frontend/src/components/LineChart.js b/frontend/src/components/LineChart.js index bbbda5f..dac0c2e 100644 --- a/frontend/src/components/LineChart.js +++ b/frontend/src/components/LineChart.js @@ -2,8 +2,35 @@ import React from "react"; import { Line } from "react-chartjs-2"; import { Chart as ChartJS } from "chart.js/auto"; +const decimation = { + enabled: false, + algorithm: "lttb", +}; + +const options = { + backgroundColor: [ + "rgba(75,192,192,1)", + "#ecf0f1", + "#50AF95", + "#f3ba2f", + "#2a71d0", + ], + borderColor: "black", + borderWidth: 2, + tension: 0.2, + normalized: true, + // plugins: { + // decimation: decimation, + // }, + // scales: { + // x: { + // type: "time", + // }, + // }, +}; + function LineChart({ chartData }) { - return ; + return ; } export default LineChart; From 138a764bed1619e1bb18a752caa3b474749ccb8b Mon Sep 17 00:00:00 2001 From: mishaaaaaaa Date: Thu, 20 Oct 2022 18:50:45 +0300 Subject: [PATCH 4/8] added loader --- frontend/src/components/LineChart.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/LineChart.js b/frontend/src/components/LineChart.js index dac0c2e..475f9cf 100644 --- a/frontend/src/components/LineChart.js +++ b/frontend/src/components/LineChart.js @@ -19,14 +19,15 @@ const options = { borderWidth: 2, tension: 0.2, normalized: true, - // plugins: { - // decimation: decimation, - // }, - // scales: { - // x: { - // type: "time", - // }, - // }, + plugins: { + //dont work for now + decimation: decimation, + }, + scales: { + x: { + type: "time", + }, + }, }; function LineChart({ chartData }) { From 440f43f292553d71af132a2de884de4a3a578cf8 Mon Sep 17 00:00:00 2001 From: mishaaaaaaa Date: Fri, 28 Oct 2022 17:22:01 +0300 Subject: [PATCH 5/8] added test component; solving scaling certain dates for futher fetching --- frontend/package-lock.json | 133 ++++++++++++------------ frontend/package.json | 2 + frontend/src/App.js | 12 ++- frontend/src/components/LineChart.js | 48 ++++++--- frontend/src/components/TestBarChart.js | 25 +++++ frontend/src/components/TestData.js | 2 +- frontend/templates/frontend/index.html | 2 +- frontend/webpack.config.js | 2 +- 8 files changed, 140 insertions(+), 86 deletions(-) create mode 100644 frontend/src/components/TestBarChart.js diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 22f8b18..97ef74b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -16,6 +16,8 @@ "@mui/material": "^5.10.9", "@mui/x-date-pickers": "^5.0.4", "chart.js": "^3.9.1", + "chartjs-adapter-date-fns": "^2.0.0", + "date-fns": "^2.29.3", "dayjs": "^1.11.5", "react-chartjs-2": "^4.3.1", "react-router-dom": "^6.4.0" @@ -36,7 +38,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.1.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -49,7 +50,6 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.0.0", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -73,7 +73,6 @@ "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.0.tgz", "integrity": "sha512-y5rqgTTPTmaF5e2nVhOxw+Ur9HDJLsWb6U/KpgUzRZEdPfE6VOubXBKLdbcUTijzRptednSBDQbYZBOSqJxpJw==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -82,7 +81,6 @@ "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz", "integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==", - "dev": true, "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", @@ -149,7 +147,6 @@ "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.0.tgz", "integrity": "sha512-Ai5bNWXIvwDvWM7njqsG3feMlL9hCVQsPYXodsZyLwshYkZVJt59Gftau4VrE8S9IT9asd2uSP1hG6wCNw+sXA==", - "dev": true, "dependencies": { "@babel/compat-data": "^7.19.0", "@babel/helper-validator-option": "^7.18.6", @@ -285,7 +282,6 @@ "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", - "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", @@ -356,7 +352,6 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "dev": true, "dependencies": { "@babel/types": "^7.18.6" }, @@ -407,7 +402,6 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -431,7 +425,6 @@ "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", - "dev": true, "dependencies": { "@babel/template": "^7.18.10", "@babel/traverse": "^7.19.0", @@ -2740,7 +2733,6 @@ "version": "4.21.3", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -2795,7 +2787,6 @@ "version": "1.0.30001399", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001399.tgz", "integrity": "sha512-4vQ90tMKS+FkvuVWS5/QY1+d805ODxZiKFzsU8o/RsVJz49ZSRR8EjykLJbqhzdPgadbX6wB538wOzle3JniRA==", - "dev": true, "funding": [ { "type": "opencollective", @@ -2844,6 +2835,14 @@ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz", "integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==" }, + "node_modules/chartjs-adapter-date-fns": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-2.0.0.tgz", + "integrity": "sha512-rmZINGLe+9IiiEB0kb57vH3UugAtYw33anRiw5kS2Tu87agpetDDoouquycWc9pRsKtQo5j+vLsYHyr8etAvFw==", + "peerDependencies": { + "chart.js": "^3.0.0" + } + }, "node_modules/chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", @@ -3019,6 +3018,18 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, + "node_modules/date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/dayjs": { "version": "1.11.5", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.5.tgz", @@ -3068,8 +3079,7 @@ "node_modules/electron-to-chromium": { "version": "1.4.249", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.249.tgz", - "integrity": "sha512-GMCxR3p2HQvIw47A599crTKYZprqihoBL4lDSAUmr7IYekXFK5t/WgEBrGJDCa2HWIZFQEkGuMqPCi05ceYqPQ==", - "dev": true + "integrity": "sha512-GMCxR3p2HQvIw47A599crTKYZprqihoBL4lDSAUmr7IYekXFK5t/WgEBrGJDCa2HWIZFQEkGuMqPCi05ceYqPQ==" }, "node_modules/emojis-list": { "version": "3.0.0", @@ -3123,7 +3133,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, "engines": { "node": ">=6" } @@ -3262,7 +3271,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -3509,7 +3517,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true, "bin": { "json5": "lib/cli.js" }, @@ -3663,8 +3670,7 @@ "node_modules/node-releases": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "dev": true + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" }, "node_modules/object-assign": { "version": "4.1.1", @@ -3799,8 +3805,7 @@ "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/pkg-dir": { "version": "4.2.0", @@ -3953,7 +3958,6 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -3974,7 +3978,6 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" @@ -4189,7 +4192,6 @@ "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0" } @@ -4216,7 +4218,6 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, "bin": { "semver": "bin/semver.js" } @@ -4435,7 +4436,6 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -4651,7 +4651,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, "requires": { "@jridgewell/gen-mapping": "^0.1.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -4661,7 +4660,6 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, "requires": { "@jridgewell/set-array": "^1.0.0", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -4680,14 +4678,12 @@ "@babel/compat-data": { "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.0.tgz", - "integrity": "sha512-y5rqgTTPTmaF5e2nVhOxw+Ur9HDJLsWb6U/KpgUzRZEdPfE6VOubXBKLdbcUTijzRptednSBDQbYZBOSqJxpJw==", - "dev": true + "integrity": "sha512-y5rqgTTPTmaF5e2nVhOxw+Ur9HDJLsWb6U/KpgUzRZEdPfE6VOubXBKLdbcUTijzRptednSBDQbYZBOSqJxpJw==" }, "@babel/core": { "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz", "integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==", - "dev": true, "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", @@ -4738,7 +4734,6 @@ "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.0.tgz", "integrity": "sha512-Ai5bNWXIvwDvWM7njqsG3feMlL9hCVQsPYXodsZyLwshYkZVJt59Gftau4VrE8S9IT9asd2uSP1hG6wCNw+sXA==", - "dev": true, "requires": { "@babel/compat-data": "^7.19.0", "@babel/helper-validator-option": "^7.18.6", @@ -4835,7 +4830,6 @@ "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", - "dev": true, "requires": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", @@ -4888,7 +4882,6 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "dev": true, "requires": { "@babel/types": "^7.18.6" } @@ -4923,8 +4916,7 @@ "@babel/helper-validator-option": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" }, "@babel/helper-wrap-function": { "version": "7.19.0", @@ -4942,7 +4934,6 @@ "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", - "dev": true, "requires": { "@babel/template": "^7.18.10", "@babel/traverse": "^7.19.0", @@ -5955,7 +5946,8 @@ "@emotion/use-insertion-effect-with-fallbacks": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", - "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==" + "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==", + "requires": {} }, "@emotion/utils": { "version": "1.2.0", @@ -6094,7 +6086,8 @@ "@mui/types": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.0.tgz", - "integrity": "sha512-lGXtFKe5lp3UxTBGqKI1l7G8sE2xBik8qCfrLHD5olwP/YU0/ReWoWT7Lp1//ri32dK39oPMrJN8TgbkCSbsNA==" + "integrity": "sha512-lGXtFKe5lp3UxTBGqKI1l7G8sE2xBik8qCfrLHD5olwP/YU0/ReWoWT7Lp1//ri32dK39oPMrJN8TgbkCSbsNA==", + "requires": {} }, "@mui/utils": { "version": "5.10.9", @@ -6366,7 +6359,8 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", - "dev": true + "dev": true, + "requires": {} }, "@webpack-cli/info": { "version": "1.5.0", @@ -6381,7 +6375,8 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", - "dev": true + "dev": true, + "requires": {} }, "@xtuc/ieee754": { "version": "1.2.0", @@ -6405,7 +6400,8 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true + "dev": true, + "requires": {} }, "ajv": { "version": "6.12.6", @@ -6423,7 +6419,8 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true + "dev": true, + "requires": {} }, "ansi-styles": { "version": "3.2.1", @@ -6517,7 +6514,6 @@ "version": "4.21.3", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", - "dev": true, "requires": { "caniuse-lite": "^1.0.30001370", "electron-to-chromium": "^1.4.202", @@ -6549,8 +6545,7 @@ "caniuse-lite": { "version": "1.0.30001399", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001399.tgz", - "integrity": "sha512-4vQ90tMKS+FkvuVWS5/QY1+d805ODxZiKFzsU8o/RsVJz49ZSRR8EjykLJbqhzdPgadbX6wB538wOzle3JniRA==", - "dev": true + "integrity": "sha512-4vQ90tMKS+FkvuVWS5/QY1+d805ODxZiKFzsU8o/RsVJz49ZSRR8EjykLJbqhzdPgadbX6wB538wOzle3JniRA==" }, "chalk": { "version": "2.4.2", @@ -6582,6 +6577,12 @@ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz", "integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==" }, + "chartjs-adapter-date-fns": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-2.0.0.tgz", + "integrity": "sha512-rmZINGLe+9IiiEB0kb57vH3UugAtYw33anRiw5kS2Tu87agpetDDoouquycWc9pRsKtQo5j+vLsYHyr8etAvFw==", + "requires": {} + }, "chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", @@ -6720,6 +6721,11 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, + "date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==" + }, "dayjs": { "version": "1.11.5", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.5.tgz", @@ -6755,8 +6761,7 @@ "electron-to-chromium": { "version": "1.4.249", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.249.tgz", - "integrity": "sha512-GMCxR3p2HQvIw47A599crTKYZprqihoBL4lDSAUmr7IYekXFK5t/WgEBrGJDCa2HWIZFQEkGuMqPCi05ceYqPQ==", - "dev": true + "integrity": "sha512-GMCxR3p2HQvIw47A599crTKYZprqihoBL4lDSAUmr7IYekXFK5t/WgEBrGJDCa2HWIZFQEkGuMqPCi05ceYqPQ==" }, "emojis-list": { "version": "3.0.0", @@ -6797,8 +6802,7 @@ "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" }, "escape-string-regexp": { "version": "1.0.5", @@ -6902,8 +6906,7 @@ "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" }, "get-intrinsic": { "version": "1.1.3", @@ -6981,7 +6984,8 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true + "dev": true, + "requires": {} }, "import-fresh": { "version": "3.3.0", @@ -7084,8 +7088,7 @@ "json5": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" }, "kind-of": { "version": "6.0.3", @@ -7197,8 +7200,7 @@ "node-releases": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "dev": true + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" }, "object-assign": { "version": "4.1.1", @@ -7291,8 +7293,7 @@ "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "pkg-dir": { "version": "4.2.0", @@ -7318,7 +7319,8 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "dev": true + "dev": true, + "requires": {} }, "postcss-modules-local-by-default": { "version": "4.0.0", @@ -7401,7 +7403,6 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dev": true, "requires": { "loose-envify": "^1.1.0" } @@ -7409,13 +7410,13 @@ "react-chartjs-2": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-4.3.1.tgz", - "integrity": "sha512-5i3mjP6tU7QSn0jvb8I4hudTzHJqS8l00ORJnVwI2sYu0ihpj83Lv2YzfxunfxTZkscKvZu2F2w9LkwNBhj6xA==" + "integrity": "sha512-5i3mjP6tU7QSn0jvb8I4hudTzHJqS8l00ORJnVwI2sYu0ihpj83Lv2YzfxunfxTZkscKvZu2F2w9LkwNBhj6xA==", + "requires": {} }, "react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dev": true, "requires": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" @@ -7556,7 +7557,8 @@ "rifm": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/rifm/-/rifm-0.12.1.tgz", - "integrity": "sha512-OGA1Bitg/dSJtI/c4dh90svzaUPt228kzFsUkJbtA2c964IqEAwWXeL9ZJi86xWv3j5SMqRvGULl7bA6cK0Bvg==" + "integrity": "sha512-OGA1Bitg/dSJtI/c4dh90svzaUPt228kzFsUkJbtA2c964IqEAwWXeL9ZJi86xWv3j5SMqRvGULl7bA6cK0Bvg==", + "requires": {} }, "safe-buffer": { "version": "5.2.1", @@ -7568,7 +7570,6 @@ "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dev": true, "requires": { "loose-envify": "^1.1.0" } @@ -7587,8 +7588,7 @@ "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" }, "serialize-javascript": { "version": "6.0.0", @@ -7732,7 +7732,6 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", - "dev": true, "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" diff --git a/frontend/package.json b/frontend/package.json index cdd3226..3a1c02f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -30,6 +30,8 @@ "@mui/material": "^5.10.9", "@mui/x-date-pickers": "^5.0.4", "chart.js": "^3.9.1", + "chartjs-adapter-date-fns": "^2.0.0", + "date-fns": "^2.29.3", "dayjs": "^1.11.5", "react-chartjs-2": "^4.3.1", "react-router-dom": "^6.4.0" diff --git a/frontend/src/App.js b/frontend/src/App.js index 7876536..a33a9df 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,20 +1,26 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useRef } from "react"; import { Grid, Container, Typography, Box } from "@mui/material/"; import RangeDatePicker from "./components/RangeDatePicker"; import LineChart from "./components/LineChart"; import CircularProgress from "@mui/material/CircularProgress"; import "../src/App.css"; import useFetch from "./hooks/useFetch"; +import { getDatasetAtEvent } from "react-chartjs-2"; export default function App() { const [fetchData, setFetchData] = useState([]); const [sentiData, setSentiData] = useState({}); const { get, post, loading } = useFetch(`/api?keyword=`); + // const chartRef = useRef(); function handleGenerateClick(fromDate, toDate, word) { setFetchData([fromDate, toDate, word]); } + function handlePointDate(event) { + console.log(getDatasetAtEvent(chartRef.current, event)); + } + useEffect(() => { if (typeof fetchData[0] == "string") { get( @@ -43,10 +49,10 @@ export default function App() { {Object.keys(sentiData).length === 0 && sentiData.constructor === Object ? ( - Choose dates and word you are looking for + Choose dates and word you are looking for! ) : ( - + )} ; +function LineChart(props) { + const chartRef = useRef(); + const onClick = (event) => { + console.log(getDatasetAtEvent(chartRef.current, event)); + }; + + return ( + + ); } export default LineChart; + +// я думаю нужно переформатировать под time cartesian для того, чтобы информация по Х-оси была в дате, а не в значении + +//для этого нужно date переделать под формат [{x:...,y:...}] diff --git a/frontend/src/components/TestBarChart.js b/frontend/src/components/TestBarChart.js new file mode 100644 index 0000000..6207c7f --- /dev/null +++ b/frontend/src/components/TestBarChart.js @@ -0,0 +1,25 @@ +import React, { useState } from "react"; +import { UserData } from "./TestData"; +import { Bar } from "react-chartjs-2"; + +export default function TestBarChart() { + const [userData, setUserData] = useState({ + labels: UserData.map((data) => data.year), + datasets: [ + { + label: "Users Gained", + data: UserData.map((data) => data.userGain), + backgroundColor: [ + "rgba(75,192,192,1)", + "#ecf0f1", + "#50AF95", + "#f3ba2f", + "#2a71d0", + ], + borderColor: "black", + borderWidth: 2, + }, + ], + }); + return ; +} diff --git a/frontend/src/components/TestData.js b/frontend/src/components/TestData.js index 3a2d28f..2108fae 100644 --- a/frontend/src/components/TestData.js +++ b/frontend/src/components/TestData.js @@ -1,4 +1,4 @@ -export const TestData = [ +export const UserData = [ { id: 1, year: 2016, diff --git a/frontend/templates/frontend/index.html b/frontend/templates/frontend/index.html index 833c2b1..f67bfe4 100644 --- a/frontend/templates/frontend/index.html +++ b/frontend/templates/frontend/index.html @@ -16,7 +16,7 @@
- + \ No newline at end of file diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index 9b28126..55f01c9 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -5,7 +5,7 @@ module.exports = { entry: "./src/index.js", output: { path: path.resolve(__dirname, "./static/frontend"), - filename: "bundle.js", + filename: "main.js", }, module: { rules: [ From 0340a84e2ce5e07146ba086059ccdfdb292a9a4a Mon Sep 17 00:00:00 2001 From: mishaaaaaaa Date: Fri, 28 Oct 2022 17:42:00 +0300 Subject: [PATCH 6/8] refactor chart component, added nes extension --- frontend/src/App.js | 13 +++++++++---- frontend/src/components/LineChart.js | 18 ++++++++++++++++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/frontend/src/App.js b/frontend/src/App.js index a33a9df..8b4c636 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,7 +1,7 @@ import React, { useState, useEffect, useRef } from "react"; import { Grid, Container, Typography, Box } from "@mui/material/"; import RangeDatePicker from "./components/RangeDatePicker"; -import LineChart from "./components/LineChart"; +import { LineChart, FaturedLineChart } from "./components/LineChart"; import CircularProgress from "@mui/material/CircularProgress"; import "../src/App.css"; import useFetch from "./hooks/useFetch"; @@ -11,14 +11,14 @@ export default function App() { const [fetchData, setFetchData] = useState([]); const [sentiData, setSentiData] = useState({}); const { get, post, loading } = useFetch(`/api?keyword=`); - // const chartRef = useRef(); + const ref = React.createRef(); function handleGenerateClick(fromDate, toDate, word) { setFetchData([fromDate, toDate, word]); } function handlePointDate(event) { - console.log(getDatasetAtEvent(chartRef.current, event)); + console.log(getDatasetAtEvent(ref.current, event)); } useEffect(() => { @@ -52,7 +52,12 @@ export default function App() { Choose dates and word you are looking for! ) : ( - + // + )} { console.log(getDatasetAtEvent(chartRef.current, event)); @@ -52,7 +53,20 @@ function LineChart(props) { ); } -export default LineChart; +export const FaturedLineChart = React.forwardRef((props, ref) => { + const onClick = (event) => { + console.log(getDatasetAtEvent(ref.current, event)); + }; + + return ( + + ); +}); // я думаю нужно переформатировать под time cartesian для того, чтобы информация по Х-оси была в дате, а не в значении From 605024cd9d00caac39a3e209ab788b282a77b628 Mon Sep 17 00:00:00 2001 From: mishaaaaaaa Date: Mon, 31 Oct 2022 19:23:40 +0200 Subject: [PATCH 7/8] =?UTF-8?q?=D1=85=D1=83=D0=B9=D0=BD=D1=8F=20=D0=B5?= =?UTF-8?q?=D0=B1=D0=B0=D0=BD=D0=B0=D1=8F=20=D0=B1=D0=BB=D1=8F=D1=82=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/App.js | 8 ++++---- frontend/src/components/LineChart.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/src/App.js b/frontend/src/App.js index 8b4c636..f659896 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -17,9 +17,9 @@ export default function App() { setFetchData([fromDate, toDate, word]); } - function handlePointDate(event) { - console.log(getDatasetAtEvent(ref.current, event)); - } + // function handlePointDate(event) { + // console.log(getDatasetAtEvent(ref.current, event)); + // } useEffect(() => { if (typeof fetchData[0] == "string") { @@ -55,7 +55,7 @@ export default function App() { // )} diff --git a/frontend/src/components/LineChart.js b/frontend/src/components/LineChart.js index f4aa409..c9bd448 100644 --- a/frontend/src/components/LineChart.js +++ b/frontend/src/components/LineChart.js @@ -62,7 +62,7 @@ export const FaturedLineChart = React.forwardRef((props, ref) => { ); From a40f380c67833e677226088dc0cb826ae8f46d12 Mon Sep 17 00:00:00 2001 From: Bohdan Garchu Date: Wed, 2 Nov 2022 19:27:20 +0100 Subject: [PATCH 8/8] add api endpoint --- api/db/articles.py | 41 +++++++++++++++++++++++ api/db/sentiment.py | 56 +++++++++++++++++++++++++++++++ api/serializers.py | 8 +++-- api/urls.py | 6 ++-- api/views.py | 81 +++++++++++---------------------------------- frontend/test.txt | 1 - 6 files changed, 127 insertions(+), 66 deletions(-) create mode 100644 api/db/articles.py create mode 100644 api/db/sentiment.py delete mode 100644 frontend/test.txt diff --git a/api/db/articles.py b/api/db/articles.py new file mode 100644 index 0000000..d0f7f29 --- /dev/null +++ b/api/db/articles.py @@ -0,0 +1,41 @@ +from django.db import connection +from ..models import Article + + +def most_negative_articles(year, month, keyword='', results=5): + query, params = prepare_query(keyword, year, month, results) + with connection.cursor() as cursor: + cursor.execute(query, params) + rows = cursor.fetchall() + print('executing query: ', connection.queries) + return transform_qs(rows) + + +def prepare_query(keyword, year, month, limit): + keyword = f"%{keyword.upper()}%" + year = str(year) + month = month_to_str(month) + params = [year, month, keyword, limit] + query = """ + select a.text, a.date, a.sentiment, a.url + from api_article as a + where strftime('%%Y', a.date) = %s + and strftime('%%m', a.date) = %s + and UPPER(a.text) LIKE %s + order by a.sentiment + limit %s;""" + return query, params + + +# list of (year, mo, sentiment) triples +def transform_qs(queryset): + return list(map( + lambda row: Article(text=row[0], date=row[1], sentiment=row[2], url=row[3]), + queryset + )) + + +def month_to_str(month): + if month < 10: + return '0' + str(month) + return str(month) diff --git a/api/db/sentiment.py b/api/db/sentiment.py new file mode 100644 index 0000000..3f99b42 --- /dev/null +++ b/api/db/sentiment.py @@ -0,0 +1,56 @@ +from datetime import date +from django.db import connection +from ..models import DatePoint, Article + + +def get_sentiment_list(keyword, start_date=None, end_date=None): + """ + fetches a list of DatePoints which contain month, + year and average sentiment for a given keyword + """ + query, params = prepare_query(keyword, start_date, end_date) + with connection.cursor() as cursor: + cursor.execute(query, params) + rows = cursor.fetchall() + print('executing query: ', connection.queries) + # list of (year, mo, sentiment) triples + return transform_qs(rows) + + +def prepare_query(keyword, start_date, end_date): + keyword = f"%{keyword.upper()}%" + params = [keyword] + date_stmt, date_params = prepare_date_stmt(start_date, end_date) + params.extend(date_params) + # %% is used for single % + # single quotes are set automatically around parameters + query = f"""select strftime('%%Y', a.date), strftime('%%m', a.date), avg(a.sentiment) + from api_article a + where UPPER(a.text) LIKE %s {date_stmt} + group by strftime('%%Y', a.date), strftime('%%m', a.date)""" + return query, params + + +# list of (year, mo, sentiment) triples +def transform_qs(queryset): + return list(map( + lambda row: DatePoint(date=date(int(row[0]), int(row[1]), 1), sentiment=row[2]), + queryset + )) + + +def prepare_date_stmt(start_date, end_date): + date_stmt = '' + params = [] + if start_date and end_date: + date_stmt = "and a.date between %s and %s" + params.append(start_date) + params.append(end_date) + elif start_date: + date_stmt = "and a.date >= %s" + params.append(start_date) + elif end_date: + date_stmt = "and a.date <= %s" + params.append(end_date) + return date_stmt, params + diff --git a/api/serializers.py b/api/serializers.py index f95962f..6771be4 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -1,5 +1,5 @@ from rest_framework import serializers -from .models import DatePoint +from .models import DatePoint, Article class DatePointSerializer(serializers.ModelSerializer): @@ -7,4 +7,8 @@ class Meta: model = DatePoint fields = ["date", "sentiment"] - \ No newline at end of file + +class ArticleSerializer(serializers.ModelSerializer): + class Meta: + model = Article + fields = ['text', 'sentiment', 'date', 'url'] diff --git a/api/urls.py b/api/urls.py index 6777917..b0dea29 100644 --- a/api/urls.py +++ b/api/urls.py @@ -1,7 +1,9 @@ from django.urls import path -from .views import DatePointView +from .views import DatePointView, MostNegativeArticles # additional urls.py file to define urls for this api urlpatterns = [ - path('', DatePointView.as_view()) + path('', DatePointView.as_view()), + path('/most-negative-articles//', + MostNegativeArticles.as_view()) ] diff --git a/api/views.py b/api/views.py index cd9be77..0a93677 100644 --- a/api/views.py +++ b/api/views.py @@ -1,18 +1,16 @@ -from django.shortcuts import render from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status -from .models import DatePoint, Article -from .serializers import DatePointSerializer -from datetime import date -from django.db import connection -from django.db.models import Q +from .db.sentiment import get_sentiment_list +from .db.articles import most_negative_articles +from .serializers import DatePointSerializer, ArticleSerializer class DatePointView(APIView): + """/api?keyword=keyword&start-date=date&end-date=date""" def get(self, request, *args, **kwargs): data = request.GET - queryset = get_sentiment( + queryset = get_sentiment_list( data.get('keyword'), data.get('start-date'), data.get('end-date') @@ -21,59 +19,20 @@ def get(self, request, *args, **kwargs): return Response(serializer.data, status=status.HTTP_200_OK) -def get_sentiment(keyword, start_date=None, end_date=None): - query, params = prepare_query(keyword, start_date, end_date) - with connection.cursor() as cursor: - cursor.execute(query, params) - rows = cursor.fetchall() - print('executing query: ', connection.queries) - # list of (year, mo, sentiment) triples - return transform_qs(rows) - - -def prepare_query(keyword, start_date, end_date): - keyword = f"%{keyword.upper()}%" - params = [keyword] - date_stmt, date_params = prepare_date_stmt(start_date, end_date) - params.extend(date_params) - # %% is used for single % - # single quotes are set automatically around parameters - query = f"""select strftime('%%Y', a.date), strftime('%%m', a.date), avg(a.sentiment) - from api_article a - where UPPER(a.text) LIKE %s {date_stmt} - group by strftime('%%Y', a.date), strftime('%%m', a.date)""" - return query, params - - -# list of (year, mo, sentiment) triples -def transform_qs(queryset): - return list(map( - lambda row: DatePoint(date=date(int(row[0]), int(row[1]), 1), sentiment=row[2]), - queryset - )) - - -def prepare_date_stmt(start_date, end_date): - date_stmt = '' - params = [] - if start_date and end_date: - date_stmt = "and a.date between %s and %s" - params.append(start_date) - params.append(end_date) - elif start_date: - date_stmt = "and a.date >= %s" - params.append(start_date) - elif end_date: - date_stmt = "and a.date <= %s" - params.append(end_date) - return date_stmt, params +class MostNegativeArticles(APIView): + """/api/most-negative-articles/year/month?keyword=keyword&results=number""" + def get(self, request, *args, **kwargs): + # todo input validation + results = 5 + if request.GET.get('results'): + results = request.GET.get('results') + queryset = most_negative_articles( + kwargs.get('year'), + kwargs.get('month'), + keyword=request.GET.get('keyword'), + results=results + ) + serializer = ArticleSerializer(queryset, many=True) + return Response(serializer.data, status=status.HTTP_200_OK) -# def get_sentiment(keyword, start_date=None, end_date=None): -# # case insensitive -# q1 = Q(text__icontains=keyword) -# # date greater than start date -# q2 = Q(date__gte=start_date) -# # date less than end date -# q3 = Q(date_lte=end_date) -# data = Article.objects.filter(q1 & q2 & q3) diff --git a/frontend/test.txt b/frontend/test.txt deleted file mode 100644 index d9e85ea..0000000 --- a/frontend/test.txt +++ /dev/null @@ -1 +0,0 @@ -Test branch commit \ No newline at end of file