├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo128.png
├── logo24.png
├── logo512.png
├── manifest.json
├── robots.txt
└── styles.css
└── src
├── App.js
├── App.module.css
├── App.test.js
├── assets
└── images
│ ├── analytical.gif
│ ├── anger.gif
│ ├── confidence.gif
│ ├── fear.gif
│ ├── image.png
│ ├── joy.gif
│ ├── neutral.png
│ ├── sad.gif
│ ├── testS.jpg
│ └── twitter.jpg
├── component
├── Date
│ ├── Date.jsx
│ └── Date.module.css
├── Header
│ ├── Header.jsx
│ └── Header.module.css
├── Home
│ ├── Home.jsx
│ └── Home.module.scss
├── Navbar
│ ├── Navbar.jsx
│ └── Navbar.module.css
├── Overall
│ ├── Overall.jsx
│ └── Overall.module.css
├── TestModel
│ ├── TestModel.jsx
│ └── TestModel.module.scss
├── Tracker
│ ├── Cards
│ │ ├── Cards.jsx
│ │ └── Cards.module.css
│ ├── Chart
│ │ ├── Chart.jsx
│ │ └── Chart.module.css
│ ├── CountryPicker
│ │ ├── CountryPicker.jsx
│ │ └── CountryPicker.module.css
│ ├── Tracker.jsx
│ └── Tracker.module.css
├── charts
│ ├── BarChart
│ │ ├── BarChart.jsx
│ │ └── BarChart.module.css
│ ├── LineChart
│ │ ├── LineChart.jsx
│ │ └── LineChart.module.css
│ └── PieChart
│ │ ├── PieChart.jsx
│ │ └── PieChart.module.css
└── ui
│ └── Cards
│ └── SimpleCard.jsx
├── index.js
├── root.js
├── serviceWorker.js
├── services
├── api
│ └── index.js
├── frequency.js
└── utilities.js
├── setupTests.js
└── theme.scss
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | #firebase
4 | .firebase
5 | .firebaserc
6 | firebase.json
7 | src/services/firebase.js
8 |
9 | # dependencies
10 | /node_modules
11 | /.pnp
12 | .pnp.js
13 |
14 | # testing
15 | /coverage
16 |
17 | # production
18 | /build
19 |
20 | # misc
21 | .DS_Store
22 | .env.local
23 | .env.development.local
24 | .env.test.local
25 | .env.production.local
26 |
27 | npm-debug.log*
28 | yarn-debug.log*
29 | yarn-error.log*
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Sentiment-Analysis-of-COVID-19-Tweets-Visualization-Dashboard
2 | ### Link
3 | https://tourist-bot-hilapp.web.app
4 | ### Overview
5 | Twitter sentiment analysis Machine learning model, which can find the sentiment score based on the tweets data. We are finding sentiment scores and emotion for 5000 tweets data everyday using machine learning models and analyzing it with various data analysis like frequency count ,monthly and weekly data analysis . Based on the sentiment score of everyday and of different #tags ,we can analyze the sentiments ,variation of sentiments in public.
6 | ### Tech stack
7 | 1. Language - Python ,JS,HTML ,CSS
8 | 2. ML - Text Blob IBM Tone Analyzer ,Google BERT Model
9 | 3. Libraries - NLTK ,GelOldTweet3 ,Wordnet ,Stopword, D3.js ,Material Ui, React-Bootstrap
10 | 4. Frameworks - Flask,Reactjs ,Node
11 | 5. Database - Firebase
12 | 4. Deployment - Pythonanywhere ,Firebase Hosting
13 | 5. Other - Google colab ,Jupyter notebook ,Kaggle Notebook
14 | ### Images
15 |
16 | #### Daily Sentiment Dashboard
17 | 
18 |
19 | #### Overall Sentiment Dashboard
20 | 
21 |
22 | #### Sentimet Beyond Positive and Negative
23 | 
24 |
25 | #### Test Model
26 | 
27 | #### Covid19 Tracker
28 | 
29 |
30 | ### PPt link
31 | https://drive.google.com/file/d/1J7olMz38UN7yhn-OM6BXZ6Odppm1tLy3/view?usp=sharing
32 | ### Video link
33 | https://drive.google.com/file/d/14XcvLROC6G_SiDr90tGSqYcrtj9fmmxl/view?usp=sharing
34 | ### Source code
35 | All code(data Cleaning to Machine Learning) is under DataSciencr Folder and Dashboard Source code is on main screen ,For detailed source code change branch to.
36 | ###### PS:
37 | It is version 1 of our project .According to reviews and feedbacks we will update it and add more salient features in next version.As we covered most of the key features of our project and made a Minimal Viable Product,and some features kept for version 2 - like Respnsive ,Mobile App etc.
38 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dashboard",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@material-ui/core": "^4.11.0",
7 | "@material-ui/icons": "^4.9.1",
8 | "@testing-library/jest-dom": "^4.2.4",
9 | "@testing-library/react": "^9.5.0",
10 | "@testing-library/user-event": "^7.2.1",
11 | "axios": "^0.21.1",
12 | "chart.js": "^2.9.3",
13 | "classnames": "^2.2.6",
14 | "firebase": "^7.15.5",
15 | "node-sass": "^4.14.1",
16 | "react": "^16.13.1",
17 | "react-bootstrap": "^1.2.1",
18 | "react-chartjs-2": "^2.9.0",
19 | "react-countup": "^4.3.3",
20 | "react-dom": "^16.13.1",
21 | "react-router-dom": "^5.2.0",
22 | "react-scripts": "3.4.1"
23 | },
24 | "scripts": {
25 | "start": "react-scripts start",
26 | "build": "react-scripts build",
27 | "test": "react-scripts test",
28 | "eject": "react-scripts eject"
29 | },
30 | "eslintConfig": {
31 | "extends": "react-app"
32 | },
33 | "browserslist": {
34 | "production": [
35 | ">0.2%",
36 | "not dead",
37 | "not op_mini all"
38 | ],
39 | "development": [
40 | "last 1 chrome version",
41 | "last 1 firefox version",
42 | "last 1 safari version"
43 | ]
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsinghindra/dashboard/1e6038bada0f763eb35583680250ba7c94c0c8c5/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
25 |
26 | covid-19 Dashboard
27 |
28 |
29 |
30 | You need to enable JavaScript to run this app.
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/logo128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsinghindra/dashboard/1e6038bada0f763eb35583680250ba7c94c0c8c5/public/logo128.png
--------------------------------------------------------------------------------
/public/logo24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsinghindra/dashboard/1e6038bada0f763eb35583680250ba7c94c0c8c5/public/logo24.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsinghindra/dashboard/1e6038bada0f763eb35583680250ba7c94c0c8c5/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "covid-19 Dashboard",
3 | "name": "A dashboard for sentiment analysis of covid-19 tweets",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo128.png",
12 | "type": "image/png",
13 | "sizes": "128x128"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/public/styles.css:
--------------------------------------------------------------------------------
1 | @import url("https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;700&display=swap");
2 |
3 | body,
4 | html {
5 | margin: 0 0;
6 | height: 100vh;
7 | display: flex;
8 | flex-flow: column;
9 | font-family: "Quicksand", sans-serif;
10 | /* dangerous property */
11 | /* overflow-x: hidden; */
12 | width: 100%;
13 | scroll-behavior: smooth;
14 | }
15 |
16 | #root {
17 | display: flex;
18 | flex-flow: column;
19 | flex: 1;
20 | }
21 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from 'react';
2 | import styles from './App.module.css';
3 | import Header from './component/Header/Header';
4 | import Navbar from './component/Navbar/Navbar';
5 | import Date from "./component/Date/Date";
6 | import Overall from "./component/Overall/Overall";
7 | import Tracker from "./component/Tracker/Tracker";
8 | import cloudDB, { collectionName } from "./services/firebase";
9 |
10 | function App() {
11 | const isCancelled = useRef(false);//prevent memory leaks performs only api calls when component is loaded to dom
12 | const [render, setRender] = useState("Date");
13 | const [data, setData] = useState([]);
14 | const fetchData = async () => {
15 | let sentimentData = [];
16 | if (!isCancelled.current)
17 | try {
18 | await cloudDB.collection(collectionName).get().then((querySnapshot) => {
19 | querySnapshot.forEach((doc) => {
20 | sentimentData.push(
21 | {
22 | date: doc.id,
23 | value: doc.data()
24 | }
25 | );
26 | });
27 | });
28 | setData(sentimentData);
29 | } catch (error) {
30 | console.log(error);
31 |
32 | }
33 | }
34 | useEffect(() => {
35 | fetchData();
36 | return () => {
37 | isCancelled.current = true;
38 | };
39 | }, []);
40 |
41 | // console.log(data, 'app');
42 |
43 | function onSelect(tab) {
44 | setRender(tab);
45 | }
46 | let show;
47 | switch (render) {
48 | case "Overall": show = ; break;
49 | case "Tracker": show = ; break;
50 | default: show = data[data.length - 1 - idx])} />; break;
51 | }
52 | return (
53 |
54 |
55 |
56 | {show}
57 |
58 |
59 | );
60 | }
61 |
62 | export default App;
63 |
--------------------------------------------------------------------------------
/src/App.module.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --background: #e2e1e0;
3 |
4 | /* // border radius */
5 | --radius: 4px;
6 |
7 | /* //Text */
8 | --heading: #424242;
9 | --text: #1b1b1b;
10 | --sub-text: #6d6d6d;
11 |
12 | /* // Color */
13 | --happy: #fddb22; /*/use as overall*/
14 | --fear: #3d3d3d; /*/use as hashtal*/
15 | --sad: #3333ff; /*/use as today*/
16 | --anger: #ff1f1f;
17 |
18 | /* //Box Shadow */
19 | --card: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
20 | --card-transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
21 | --card-hover: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);
22 | --rest: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
23 | }
24 |
25 | .App {
26 | display: flex;
27 | flex: 1;
28 | flex-flow: column;
29 | }
30 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import App from './App';
4 |
5 | test('renders learn react link', () => {
6 | const { getByText } = render( );
7 | const linkElement = getByText(/learn react/i);
8 | expect(linkElement).toBeInTheDocument();
9 | });
10 |
--------------------------------------------------------------------------------
/src/assets/images/analytical.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsinghindra/dashboard/1e6038bada0f763eb35583680250ba7c94c0c8c5/src/assets/images/analytical.gif
--------------------------------------------------------------------------------
/src/assets/images/anger.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsinghindra/dashboard/1e6038bada0f763eb35583680250ba7c94c0c8c5/src/assets/images/anger.gif
--------------------------------------------------------------------------------
/src/assets/images/confidence.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsinghindra/dashboard/1e6038bada0f763eb35583680250ba7c94c0c8c5/src/assets/images/confidence.gif
--------------------------------------------------------------------------------
/src/assets/images/fear.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsinghindra/dashboard/1e6038bada0f763eb35583680250ba7c94c0c8c5/src/assets/images/fear.gif
--------------------------------------------------------------------------------
/src/assets/images/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsinghindra/dashboard/1e6038bada0f763eb35583680250ba7c94c0c8c5/src/assets/images/image.png
--------------------------------------------------------------------------------
/src/assets/images/joy.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsinghindra/dashboard/1e6038bada0f763eb35583680250ba7c94c0c8c5/src/assets/images/joy.gif
--------------------------------------------------------------------------------
/src/assets/images/neutral.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsinghindra/dashboard/1e6038bada0f763eb35583680250ba7c94c0c8c5/src/assets/images/neutral.png
--------------------------------------------------------------------------------
/src/assets/images/sad.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsinghindra/dashboard/1e6038bada0f763eb35583680250ba7c94c0c8c5/src/assets/images/sad.gif
--------------------------------------------------------------------------------
/src/assets/images/testS.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsinghindra/dashboard/1e6038bada0f763eb35583680250ba7c94c0c8c5/src/assets/images/testS.jpg
--------------------------------------------------------------------------------
/src/assets/images/twitter.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsinghindra/dashboard/1e6038bada0f763eb35583680250ba7c94c0c8c5/src/assets/images/twitter.jpg
--------------------------------------------------------------------------------
/src/component/Date/Date.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { NativeSelect, FormControl } from "@material-ui/core";
3 | import styles from "./Date.module.css";
4 | import PieChart from "../charts/PieChart/PieChart";
5 | import { ScoreBarChart } from "../charts/BarChart/BarChart";
6 | import { CircularProgress } from "@material-ui/core";
7 | import { storageRef, storagePath } from "../../services/firebase";
8 | import SimpleCard from "../ui/Cards/SimpleCard";
9 |
10 | const text = "Analyze emotion , Score of each and every day of lockdown individually with ML generated Word Cloud. Use date picker to change date.";
11 | const why = "Sentiment analysis of tweets provides exciting opportunities. Being able to analyze tweets in real-time, and determine the sentiment that underlies each message, adds a new dimension to social media monitoring.";
12 |
13 | function Date(props) {
14 | const [date, setDate] = useState({});
15 | const [imgUrl, setImgUrl] = useState("");
16 | // console.log(props.data, 'date');
17 | const initializeDate = () => {
18 | if (props.data.length !== 0) {
19 | // console.log("in if");
20 | setDate(props.data[0]);
21 | }
22 | }
23 |
24 | const getImageUrl = async () => {
25 | //if date has object i.e date
26 | if (Object.keys(date).length !== 0) {
27 | try {
28 | // console.log(date.date, "intry");
29 | await storageRef.ref().child(storagePath + date.date + ".png").getDownloadURL().then(function (url) {
30 | // console.log(url, "url");
31 | setImgUrl(url);
32 | });
33 | } catch (error) {
34 | console.log(error);
35 | }
36 | }
37 | }
38 |
39 | useEffect(() => {
40 | initializeDate();
41 | getImageUrl();
42 | }, [props.data.length])
43 |
44 | getImageUrl();
45 |
46 | function handleDate(d) {
47 | // console.log(d, 'indatecomponent');
48 | setImgUrl("");
49 | let tempDate = props.data.filter((val, index) => { return val.date === d });
50 | // console.log(tempDate);
51 | setDate(tempDate[0]);
52 | // getImageUrl();
53 | }
54 | // console.log(date, "date");
55 | return (
56 |
57 |
58 | {text}
59 |
Why
60 | {why}
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
Select Date
69 |
70 |
71 |
72 |
73 |
74 |
Emotion
75 | {(Object.keys(date).length !== 0) ?
:
}
76 |
77 |
78 |
Score
79 | {(Object.keys(date).length !== 0) ? : }
80 |
81 |
82 |
Word Cloud
83 | {imgUrl !== "" ?
:
}
84 |
85 | {/*
86 |
Select Date
87 |
88 | */}
89 |
90 |
91 | );
92 | }
93 |
94 |
95 | function DatePicker(props) {
96 | return (
97 |
98 | props.handleDate(e.target.value)} className={styles.Select}>
99 | {/* Today */}
100 | {props.data.map((d, index) => { return {d.date} ; })}
101 |
102 |
103 | );
104 | }
105 | export default Date;
--------------------------------------------------------------------------------
/src/component/Date/Date.module.css:
--------------------------------------------------------------------------------
1 | .Container {
2 | flex: 1;
3 | background-color: #f2f2f2;
4 | justify-content: space-around;
5 | align-items: flex-start;
6 | display: grid;
7 | /* grid-template-columns: 1fr 1fr 1fr auto; */
8 | grid-template-rows: auto auto auto;
9 | grid-template-columns: 100%;
10 | grid-column-gap: 10px;
11 | grid-row-gap: 5%;
12 | }
13 |
14 | .Text {
15 | margin: 0 50px;
16 | padding: 10px 10px;
17 | box-sizing: border-box;
18 | margin-top: 2%;
19 | }
20 |
21 | .Text h1 {
22 | margin: 5px 0;
23 | font-size: 1.2em;
24 | }
25 |
26 | .Text span {
27 | font-size: 1.5rem;
28 | font-size: 1.2em;
29 | }
30 | .Card {
31 | display: grid;
32 | padding: 0 50px;
33 | grid-column-gap: 2%;
34 | grid-template-columns: repeat(4, 13%) auto;
35 | justify-content: center;
36 | }
37 |
38 | .Group {
39 | display: grid;
40 | grid-template-columns: repeat(3, 32%);
41 | width: 100%;
42 | grid-column-gap: 1%;
43 | margin-bottom: 4%;
44 | justify-content: center;
45 | }
46 |
47 | .Emotion {
48 | text-align: center;
49 | box-sizing: border-box;
50 | background: white;
51 | border-radius: 5px;
52 | box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
53 | margin-bottom: 4%;
54 | }
55 |
56 | .Emotion h1 {
57 | margin: 0 0;
58 | }
59 |
60 | .Score {
61 | text-align: center;
62 | box-sizing: border-box;
63 | height: fit-content;
64 | background: white;
65 | border-radius: 5px;
66 | box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
67 | }
68 |
69 | .Score h1 {
70 | margin: 0 0;
71 | }
72 |
73 | .WordCloud {
74 | height: 480px;
75 | width: fit-content;
76 | text-align: center;
77 | box-sizing: border-box;
78 | background: white;
79 | border-radius: 5px;
80 | box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
81 | }
82 |
83 | .WordCloud h1 {
84 | margin: 0 0;
85 | }
86 |
87 | .WordCloud img {
88 | padding: 10px 10px;
89 | height: 400px;
90 | width: 385px;
91 | }
92 |
93 | .Picker {
94 | grid-area: Picker;
95 | box-sizing: border-box;
96 | box-shadow: var(--card);
97 | }
98 |
99 | .Select {
100 | padding: 2px 10px;
101 | }
102 |
103 | /* Mobile */
104 |
105 | @media screen and (max-width: 480px),
106 | (max-height: 480px) and (orientation: landscape) {
107 | .Container {
108 | display: grid;
109 | /* grid-template-columns: 1fr 1fr 1fr auto; */
110 | grid-template-rows: auto auto auto;
111 | grid-template-columns: 100%;
112 | grid-column-gap: 10px;
113 | grid-row-gap: 5%;
114 | }
115 | .Card {
116 | display: grid;
117 | padding: 0 50px;
118 | grid-column-gap: 2%;
119 | grid-row-gap: 2%;
120 | grid-template-columns: repeat(2, 53%);
121 | grid-template-rows: repeat(3, 43%);
122 | text-align: center;
123 | }
124 |
125 | .Group {
126 | display: flex;
127 | flex-flow: column;
128 | /* width: 100%; */
129 | margin-bottom: 4%;
130 | justify-content: space-between;
131 | }
132 |
133 | .Score h1 {
134 | margin: 0 0;
135 | }
136 |
137 | .WordCloud {
138 | height: 480px;
139 | width: 100%;
140 | margin: 10px 0;
141 | }
142 |
143 | .WordCloud h1 {
144 | margin: 0 0;
145 | }
146 |
147 | .WordCloud img {
148 | padding: 10px 10px;
149 | height: 400px;
150 | width: 90vw;
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/component/Header/Header.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { NavLink } from "react-router-dom";
3 | import { Dashboard } from "@material-ui/icons";
4 |
5 | import styles from "./Header.module.css";
6 |
7 | function Header(props) {
8 | return (
9 | <>
10 |
11 |
12 |
13 | DashBoard
14 |
15 |
16 | >
17 | );
18 | }
19 |
20 | export default Header;
--------------------------------------------------------------------------------
/src/component/Header/Header.module.css:
--------------------------------------------------------------------------------
1 | .Container {
2 | color: white;
3 | margin: 0 0;
4 | padding: 0 0;
5 | background-color: #191919;
6 | }
7 |
8 | .Container h1 {
9 | padding: 0 10px;
10 | margin: 5px 0;
11 | }
12 |
13 | .Container h1:hover {
14 | cursor: pointer;
15 | }
16 |
17 | .NavItem {
18 | color: white;
19 | padding: 0 10px;
20 | display: flex;
21 | align-items: center;
22 | background-color: #004f7c;
23 | text-decoration: none;
24 | }
25 |
--------------------------------------------------------------------------------
/src/component/Home/Home.jsx:
--------------------------------------------------------------------------------
1 | // Don't re-invent the wheel - Best software developer tip
2 |
3 | // Use react material ui and bootstrap for designing
4 | import React from 'react';
5 | import styles from './Home.module.scss';
6 | import { Link } from "react-router-dom";
7 | import Jumbotron from 'react-bootstrap/Jumbotron'
8 | import Container from 'react-bootstrap/Container'
9 | import Typography from '@material-ui/core/Typography'
10 | import Button from '@material-ui/core/Button';
11 | import { Dashboard, DeveloperMode } from "@material-ui/icons";
12 |
13 | const overview = `Twitter sentiment analysis Machine learning model, which can find the sentiment score based
14 | on the tweets data. We are finding sentiment scores and emotion for 5000 tweets data everyday
15 | using machine learning models and analyzing it with various data analysis like frequency count
16 | ,monthly and weekly data analysis . Based on the sentiment score of everyday and
17 | ,we can analyze the sentiments ,variation in sentiments of public.`;
18 |
19 | const purpose = `Sentiment analysis is extremely useful in social media monitoring as it allows us to gain an
20 | overview of the wider public opinion behind certain topics. Social media websites like Twitte,
21 | Facebook make that process quicker and easier than ever before, thanks to real-time
22 | monitoring capabilities.The human language is complex. Teaching a machine to analyse the various grammatical
23 | nuances, cultural variations, slang and misspellings that occur in online mentions is a difficult
24 | process. Teaching a machine to understand how context can affect tone is even more difficult
25 | The Corona Virus endangers our physical health indeed, but alongside, social distancing also
26 | poses a threat to our emotional stability. Thus, it is crucial to understand public sentiments under COVID-19.`;
27 |
28 |
29 | function Home() {
30 | // Add flexbox and style and content
31 | return (
32 |
33 |
34 |
35 |
36 |
37 |
38 | Covid-19 Dashboard
39 |
40 |
41 | Sentiment Analysis of COVID-19 Tweets – Visualization Dashboard
42 |
43 | {/* */}
44 |
45 |
46 | Go to DashBoard
47 |
48 |
49 |
50 | Test Model
51 |
52 |
53 |
54 |
55 |
70 |
71 | );
72 | }
73 |
74 | export default Home;
--------------------------------------------------------------------------------
/src/component/Home/Home.module.scss:
--------------------------------------------------------------------------------
1 | .grid {
2 | display: grid;
3 | grid-template-rows: 40% auto;
4 | grid-template-columns: 100%;
5 | height: 100%;
6 | .child_1 {
7 | background-image: url("./../../assets/images/twitter.jpg");
8 | background-repeat: no-repeat;
9 | background-position: center center;
10 | background-size: cover;
11 | width: 100%;
12 | .jumbotron {
13 | margin: 6%;
14 | }
15 | .title {
16 | font-size: 4em;
17 | color: #1f7bac;
18 | }
19 | .subtitle {
20 | font-size: 1.1em;
21 | color: #93dcff;
22 | }
23 | .button {
24 | color: white;
25 | border: 1px solid white;
26 | margin-top: 2%;
27 | .link {
28 | padding: 0 10px;
29 | color: white;
30 | text-decoration: none;
31 | }
32 | margin-left: 2%;
33 | }
34 | }
35 | .child_2 {
36 | display: grid;
37 | grid-template-columns: 20% auto 20%;
38 | .summary {
39 | grid-column: 2/3;
40 | margin-top: 5%;
41 | padding: 10px 0;
42 | h1 {
43 | margin: 0 0;
44 | color: #1f7bac;
45 | }
46 | .text {
47 | padding: 10px 0;
48 | color: #1b1b1b;
49 | line-height: 1.5em;
50 | }
51 | }
52 | }
53 | }
54 |
55 | @media (max-width: 480px), (max-height: 480px) and (orientation: landscape) {
56 | .grid {
57 | .button {
58 | background-color: #1b1b1b;
59 | }
60 | .child_2 {
61 | display: flex;
62 | padding: 10px 20px;
63 | flex-flow: column;
64 | align-items: center;
65 | .summary {
66 | margin-top: 5%;
67 | h1 {
68 | margin: 0 0;
69 | }
70 | .text {
71 | padding: 10px 0;
72 | color: #1b1b1b;
73 | font-size: 1.2rem;
74 | }
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/component/Navbar/Navbar.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { DateRange, ShowChart, Assessment } from "@material-ui/icons";
3 | import styles from "./Navbar.module.css";
4 |
5 | function Navbar(props) {
6 | return (
7 |
8 |
props.onSelect("Date")}>
9 |
10 |
Date
11 |
12 |
props.onSelect("Overall")}>
13 |
14 |
Overall
15 |
16 |
props.onSelect("Tracker")}>
17 |
18 |
Tracker
19 |
20 |
21 | );
22 | }
23 |
24 | export default Navbar;
--------------------------------------------------------------------------------
/src/component/Navbar/Navbar.module.css:
--------------------------------------------------------------------------------
1 | .Container {
2 | display: grid;
3 | grid-template-columns: 1fr 1fr 1fr;
4 | color: white;
5 | background-color: #191919;
6 | text-align: center;
7 | background-color: #1f7bac;
8 | }
9 |
10 | .Item {
11 | border: 1px solid white;
12 | display: flex;
13 | justify-content: center;
14 | align-items: center;
15 | }
16 |
17 | .Item h1 {
18 | margin: 3px 10px;
19 | font-size: 1.5rem;
20 | padding: 0 0;
21 | }
22 |
23 | .Item:hover {
24 | background-color: #004f7c;
25 | cursor: pointer;
26 | }
27 |
--------------------------------------------------------------------------------
/src/component/Overall/Overall.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import styles from "./Overall.module.css";
3 | import LineChart, { DualLineChart, MultiLineChart } from "../charts/LineChart/LineChart";
4 | import BarChart, { ScoreBarChart, FrequencyBarChart, MultiBarChart, MultiFrequencyBarChart } from "../charts/BarChart/BarChart";
5 | import { getWeekData, getMonthData } from "../../services/utilities";
6 | import { NativeSelect, FormControl, CircularProgress } from "@material-ui/core";
7 | import * as freq from "../../services/frequency";
8 | import SimpleCard from "../ui/Cards/SimpleCard";
9 |
10 | const spinner = ;
11 | const text = "Analyze overall sentiment score,emotion analysis generated from our custom ML model.";
12 | const why = "Subjectivity analyzes expression ,opinion feeling of text and Polarity refer overall orientation of emotion in text.Also we analyzed happy,sad,angaer,fear which show emotion.These all help in better understanding public sentiment";
13 |
14 |
15 | function Overall(props) {
16 | const [tabTitle, setTabTitle] = useState("Emotions"); //to display selected emotion on selected tab
17 | const [scoreType, setScoreType] = useState("Monthly"); //monthly or weekly for score
18 | const [scoreFrequency, setScoreFrequency] = useState("Subjectivity"); //frequency for score
19 | const [emotionType, setEmotionType] = useState("Monthly"); //monthly or weekly for emotion
20 | const [emotionFrequency, setEmotionFrequency] = useState("Overall"); //frequency for emotion
21 |
22 | function onSelect(tabName) {
23 | setTabTitle(tabName);
24 | }
25 |
26 | // console.log(props.data, "overall");
27 | let weekData = [], monthData = [];
28 | if (props.data.length !== 0) {
29 | monthData = getMonthData(props.data);
30 | weekData = getWeekData(props.data);
31 | // console.log(monthData, "month");
32 | // console.log(weekData, "week");
33 | }
34 |
35 | function handleScorePicker(what) {
36 | // console.log(what);
37 | setScoreType(what);
38 | }
39 |
40 | function handleEmotionPicker(what) {
41 | // console.log(what);
42 | // console.log(tabTitle, "emottionpicker");
43 | setEmotionType(what);
44 | }
45 |
46 | function handleScoreFrequency(what) {
47 | // console.log(what);
48 | setScoreFrequency(what);
49 | }
50 |
51 | function handleEmotionFrequency(what) {
52 | // console.log(what);
53 | setEmotionFrequency(what);
54 | }
55 |
56 | function freqEmotionAll(tabName) {
57 | // console.log(tabName, tabTitle);
58 | let o = {};
59 | switch (tabName) {
60 | case "Sad": o = freq.freqSad(props.data); break;
61 | case "Fear": o = freq.freqFear(props.data); break;
62 | case "Anger": o = freq.freqAnger(props.data); break;
63 | default: o = freq.freqJoy(props.data);
64 | }
65 | return o;
66 | }
67 |
68 | //get freq10 of all 4 emotions
69 | function freq10All() {
70 | let emo = ["Joy", "Sad", "Anger", "Fear"];
71 | //array of object with all emotion freq 10;
72 | let res = [];
73 | for (let i = 0; i < emo.length; i++) {
74 | res.push(freq.freq10(props.data, emo[i]));
75 | }
76 | return res;
77 | }
78 | // console.log(props.data, "hereoverall")
79 | return (
80 |
81 |
82 | {text}
83 |
Why
84 | {why}
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
Score Daily
95 |
96 | {props.data.length !== 0 ?
: spinner}
97 |
98 |
99 |
100 |
{scoreType}
101 |
102 |
103 | {scoreType === "Monthly" && props.data.length !== 0 &&
}
104 | {scoreType === "Weekly" && props.data.length !== 0 &&
}
105 |
106 |
107 |
108 |
Frequency
109 |
110 |
111 | {(props.data.length !== 0 && scoreFrequency === "Subjectivity") &&
}
112 | {(props.data.length !== 0 && scoreFrequency === "Polarity") &&
}
113 |
114 | {/* Emotions section here */}
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
{tabTitle + " Daily"}
125 |
126 | {props.data.length === 0 && spinner}
127 | {props.data.length !== 0 && tabTitle === "Emotions" &&
}
128 | {props.data.length !== 0 && tabTitle !== "Emotions" &&
}
129 |
130 |
131 |
132 |
{emotionType}
133 |
134 |
135 |
136 | {emotionType === "Monthly" && props.data.length !== 0 && tabTitle === "Emotions" &&
}
137 | {emotionType === "Weekly" && props.data.length !== 0 && tabTitle === "Emotions" &&
}
138 | {emotionType === "Monthly" && props.data.length !== 0 && tabTitle !== "Emotions" &&
}
139 | {emotionType === "Weekly" && props.data.length !== 0 && tabTitle !== "Emotions" &&
}
140 |
141 |
142 |
143 |
Frequency
144 | {tabTitle !== "Emotions" &&
}
145 |
146 | {(props.data.length !== 0 && tabTitle === "Emotions" && emotionFrequency === "Overall") &&
}
147 | {(props.data.length !== 0 && tabTitle !== "Emotions" && emotionFrequency === "Overall") &&
}
148 | {(props.data.length !== 0 && tabTitle !== "Emotions" && emotionFrequency === "Details") &&
}
149 |
150 |
151 | );
152 | }
153 |
154 | function Tab(props) {
155 | return (
156 | props.onSelect(props.title)}>
157 |
{props.title}
158 |
159 | );
160 | }
161 |
162 | function Picker(props) {
163 | return (
164 |
165 | props.handlePicker(e.target.value)} className={styles.Select}>
166 | {props.option1}
167 | {props.option2}
168 |
169 |
170 | );
171 | }
172 |
173 | export default Overall;
--------------------------------------------------------------------------------
/src/component/Overall/Overall.module.css:
--------------------------------------------------------------------------------
1 | .Container {
2 | flex: 1;
3 | padding: 10px 10px;
4 | display: grid;
5 | grid-template-columns: 1fr 1fr;
6 | grid-template-rows: auto auto 2 2fr 0.5fr 2 2fr;
7 | grid-column-gap: 10px;
8 | grid-row-gap: 50px;
9 | grid-template-areas:
10 | "Text Text"
11 | "Card Card"
12 | "Score Score"
13 | "Monthly Frequency"
14 | "Tabs Tabs"
15 | "TabsDaily TabsDaily"
16 | "TabsMonthly TabsFrequency";
17 | background-color: #f2f2f2;
18 | }
19 |
20 | .Text {
21 | grid-area: Text;
22 | margin: 0 50px;
23 | padding: 10px 10px;
24 | }
25 |
26 | .Text h1 {
27 | margin: 5px 0;
28 | font-size: 1.2em;
29 | }
30 |
31 | .Text span {
32 | font-size: 1.2em;
33 | }
34 |
35 | .Card {
36 | grid-area: Card;
37 | display: grid;
38 | padding: 0 50px;
39 | grid-column-gap: 2%;
40 | grid-template-columns: repeat(4, 13%);
41 | justify-content: center;
42 | }
43 |
44 | .Score {
45 | padding: 10px 10px;
46 | grid-area: Score;
47 | display: flex;
48 | flex-flow: column;
49 | background: white;
50 | border-radius: 5px;
51 | box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
52 | }
53 |
54 | .Monthly {
55 | grid-area: Monthly;
56 | display: flex;
57 | flex-flow: column;
58 | margin: 10px 10px;
59 | padding: 10px 10px;
60 | background: white;
61 | border-radius: 5px;
62 | box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
63 | }
64 |
65 | .TabsMonthly {
66 | grid-area: TabsMonthly;
67 | display: flex;
68 | flex-flow: column;
69 | margin: 10px 10px;
70 | padding: 10px 10px;
71 | background: white;
72 | border-radius: 5px;
73 | box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
74 | }
75 |
76 | .Heading {
77 | text-align: center;
78 | display: flex;
79 | align-items: center;
80 | justify-content: space-around;
81 | }
82 |
83 | .Heading h1 {
84 | margin: 0 0;
85 | }
86 |
87 | .Frequency {
88 | grid-area: Frequency;
89 | margin: 10px 10px;
90 | padding: 10px 10px;
91 | background: white;
92 | border-radius: 5px;
93 | box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
94 | }
95 |
96 | .TabsFrequency {
97 | grid-area: TabsFrequency;
98 | margin: 10px 10px;
99 | padding: 10px 10px;
100 | background: white;
101 | border-radius: 5px;
102 | box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
103 | }
104 |
105 | .Tabs {
106 | grid-area: Tabs;
107 | text-align: center;
108 | height: fit-content;
109 | display: grid;
110 | grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
111 | }
112 |
113 | .TabsDaily {
114 | padding: 40px 10px;
115 | grid-area: TabsDaily;
116 | display: flex;
117 | flex-flow: column;
118 | align-content: center;
119 | background: white;
120 | border-radius: 5px;
121 | box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
122 | }
123 |
124 | .Tab {
125 | background-color: #1f7bac;
126 | margin: 0 5px;
127 | border: 1px solid white;
128 | color: white;
129 | }
130 |
131 | .Tab h1 {
132 | margin: 3px 0;
133 | font-size: 1.5rem;
134 | }
135 |
136 | .Tab:hover {
137 | background-color: #004f7c;
138 | cursor: pointer;
139 | }
140 |
141 | .Picker {
142 | box-sizing: border-box;
143 | box-shadow: var(--card);
144 | }
145 |
146 | .Select {
147 | padding: 2px 10px;
148 | }
149 |
150 | /* Mobile */
151 | @media (max-width: 480px), (max-height: 480px) and (orientation: landscape) {
152 | .Container {
153 | flex: 1;
154 | padding: 10px 10px;
155 | display: flex;
156 | flex-flow: column;
157 | justify-content: space-between;
158 | }
159 | .Card {
160 | grid-row-gap: 2%;
161 | grid-template-columns: repeat(2, 53%);
162 | grid-template-rows: repeat(2, 53%);
163 | margin-bottom: 40px;
164 | }
165 |
166 | .Tab {
167 | background-color: #1f7bac;
168 | margin: 0 0 10px;
169 | }
170 |
171 | .Tab h1 {
172 | margin: 3px 0;
173 | font-size: 1rem;
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/src/component/TestModel/TestModel.jsx:
--------------------------------------------------------------------------------
1 | // Don't re-invent the wheel - Best software developer tip
2 |
3 | // Use react material ui and bootstrap for designing
4 | import React, { useState } from 'react';
5 | import styles from './TestModel.module.scss';
6 | import Jumbotron from 'react-bootstrap/Jumbotron'
7 | import Container from 'react-bootstrap/Container'
8 | import Typography from '@material-ui/core/Typography'
9 | import Button from '@material-ui/core/Button';
10 | import ArrowForwardIcon from '@material-ui/icons/ArrowForwardIos';
11 | import TextField from '@material-ui/core/TextField';
12 | import { makeStyles } from '@material-ui/core/styles';
13 | import { NavLink } from "react-router-dom";
14 | import { Home } from "@material-ui/icons";
15 | import axios from "axios";
16 | import { CircularProgress } from "@material-ui/core";
17 |
18 | //emotion images
19 | import analyticalImg from "../../assets/images/analytical.gif";
20 | import angerImg from "../../assets/images/anger.gif";
21 | import fearImg from "../../assets/images/fear.gif";
22 | import joyImg from "../../assets/images/joy.gif";
23 | import neutralImg from "../../assets/images/neutral.png";
24 | import sadImg from "../../assets/images/sad.gif";
25 | import confidenceImg from "../../assets/images/confidence.gif";
26 |
27 | const useStyles = makeStyles((theme) => ({
28 | root: {
29 | display: 'flex',
30 | flexWrap: 'wrap',
31 | },
32 | textField: {
33 | width: '100%',
34 | height: '100%'
35 | },
36 | input: {
37 | height: '90%'
38 | },
39 | notchedOutline: {
40 | borderColor: '#1f7bac !important',
41 | }
42 | }));
43 |
44 | const scoreAPI = "https://mkk23051999.pythonanywhere.com/score/?text=";
45 | const emotionAPI = "https://nameless-bayou-63665.herokuapp.com/emotion?text=";
46 |
47 | const spinner = ;
48 |
49 | function TestModel() {
50 | const classes = useStyles();
51 | // const classes = useStyles();
52 | // Add flexbox and style and content
53 | const [inputText, setInputText] = useState("");//for storing input text
54 | const [emotion, setEmotion] = useState(""); //for storing emotion from emotionApi
55 | const [score, setScore] = useState({}); //for stroing score from scoreApi
56 | const [imgSource, setImgSource] = useState(""); //for storing emoji
57 | const [showSpinner, setShowSpinner] = useState(false); //for showing spinner
58 | function handleInput(val) {
59 | // console.log(val);
60 | setInputText(val);
61 | }
62 | function getImageSource(what) {
63 | // console.log(what, "what");
64 | switch (what) {
65 | case "Confident": return confidenceImg;
66 | case "Anger": return angerImg;
67 | case "Sadness": return sadImg;
68 | case "Fear": return fearImg;
69 | case "Analytical": return analyticalImg;
70 | case "Joy": return joyImg;
71 | default: return neutralImg;
72 | }
73 | }
74 | const getScore = async () => {
75 | try {
76 | // console.log(inputText, "intry");
77 | // axios.get(emotionAPI + inputText).then(function (data) {
78 | // console.log(data.data, "tehn");
79 | // }).catch(function (error) {
80 | // console.log(error, "axios");
81 | // });
82 | //getting emotion
83 | setShowSpinner(true);
84 | const emotionData = await axios.get(emotionAPI + inputText);
85 | if (emotionData.data.length === 0) {
86 | setEmotion("Neutral");
87 | setImgSource(getImageSource("Neutral"));
88 | } else {
89 | try {
90 | // console.log(emotionData.data[0]);
91 | setEmotion(emotionData.data[0].tone_name);
92 | setImgSource(getImageSource(emotionData.data[0].tone_name));
93 | } catch (error) {
94 | console.log(error, "in setemotion of tryblock");
95 | setEmotion("Some Error");
96 | }
97 | }
98 | const scoreData = await axios.get(scoreAPI + inputText);
99 | if (Object.keys(scoreData).length === 0) {
100 | console.log("empty object from score api");
101 | } else {
102 | // console.log(scoreData.data);
103 | setScore(scoreData.data);
104 | }
105 | setShowSpinner(false);
106 | } catch (error) {
107 | console.log(error, "incatch");
108 | }
109 | setShowSpinner(false);
110 | }
111 |
112 | function handleSubmit() {
113 | getScore();
114 | }
115 |
116 | return (
117 |
118 |
119 | Back to Home
120 |
121 |
122 |
123 | Analyze text
124 |
125 |
126 | Sentiment analysis and Emotion Anlaysis ML Model
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 | Check and Analyse Emotion and Score with our custom made ML model.We have used Text Blob
135 | for finding sentiment score and IBM Tone Analyzer & BERT Model for emotion analysis.
136 |
137 |
138 |
139 | handleInput(e.target.value)}
151 | />
152 |
153 |
}
158 | onClick={handleSubmit}
159 | >Check
160 |
{/* store output here */}
161 |
Subjectivity : {showSpinner ? spinner : (Object.keys(score).length !== 0 && score.Subjectivity.toFixed(2))}
162 |
Polarity : {showSpinner ? spinner : (Object.keys(score).length !== 0 && score.Polarity.toFixed(2))}
163 |
Emotion : {showSpinner ? spinner : emotion}
164 |
Emoji : {showSpinner ? spinner : (imgSource !== "" &&
)}
165 |
166 |
167 |
168 | );
169 | }
170 |
171 | export default TestModel;
--------------------------------------------------------------------------------
/src/component/TestModel/TestModel.module.scss:
--------------------------------------------------------------------------------
1 | .grid {
2 | display: grid;
3 | grid-template-rows: 40% auto;
4 | grid-template-columns: 100%;
5 | grid-row-gap: 10px;
6 | height: 100%;
7 | .child_1 {
8 | background-image: url("./../../assets/images/testS.jpg");
9 | background-repeat: no-repeat;
10 | width: 100%;
11 | height: 100%;
12 | background-position: center center;
13 | background-size: cover;
14 | .jumbotron {
15 | margin: 6%;
16 | }
17 | .Link {
18 | text-decoration: none;
19 | display: flex;
20 | align-items: center;
21 | color: white;
22 | padding: 10px 10px;
23 | }
24 | .Link h2 {
25 | margin: 0 0;
26 | padding: 5px 5px;
27 | font-size: 1em;
28 | }
29 | .title {
30 | font-size: 4em;
31 | color: #1f7bac;
32 | }
33 | .subtitle {
34 | font-size: 1.1em;
35 | color: #1f7bacbd;
36 | }
37 | }
38 | .child_2 {
39 | display: grid;
40 | grid-template-columns: 20% auto 20%;
41 | grid-template-rows: 40% 30% 15% auto;
42 | grid-row-gap: 10px;
43 | .summary {
44 | grid-column: 2/3;
45 | margin-top: 5%;
46 | .text {
47 | color: #1b1b1b;
48 | line-height: 1.5em;
49 | }
50 | }
51 | .input {
52 | grid-column: 2/3;
53 | width: 70%;
54 | height: 100%;
55 | min-height: fit-content;
56 | }
57 | .button {
58 | grid-column: 2/3;
59 | width: fit-content;
60 | height: 60%;
61 | margin: 10px 0;
62 | border: 1px solid #1f7bac;
63 | color: #1f7bac;
64 | background-color: white;
65 | &:hover {
66 | background-color: #1f7bac;
67 | color: white;
68 | border: none;
69 | }
70 | }
71 | .output {
72 | display: grid;
73 | grid-template-rows: auto auto auto;
74 | grid-template-columns: auto auto;
75 | grid-row-gap: 10px;
76 | grid-column: 2/3;
77 | margin-bottom: 8%;
78 | margin-top: 3%;
79 | .subject {
80 | grid-row: 1/2;
81 | grid-column: 1/2;
82 | font-weight: bold;
83 | color: #1f7bac;
84 | display: grid;
85 | grid-template-columns: 50% auto;
86 | span {
87 | color: black;
88 | font-size: 1.5rem;
89 | font-weight: normal;
90 | margin-right: 5%;
91 | }
92 | }
93 | .polar {
94 | grid-row: 2/3;
95 | grid-column: 1/2;
96 | font-weight: bold;
97 | color: #1f7bac;
98 | display: grid;
99 | grid-template-columns: 50% auto;
100 | span {
101 | color: black;
102 | font-size: 1.5rem;
103 | font-weight: normal;
104 | margin-right: 5%;
105 | }
106 | }
107 | .emotion {
108 | grid-row: 3/4;
109 | grid-column: 1/2;
110 | font-weight: bold;
111 | color: #1f7bac;
112 | display: grid;
113 | grid-template-columns: 50% auto;
114 | span {
115 | color: black;
116 | font-size: 1.5rem;
117 | font-weight: normal;
118 | margin-right: 5%;
119 | }
120 | }
121 | .emoji {
122 | display: flex;
123 | align-items: center;
124 | grid-row: 1/3;
125 | grid-column: 2/3;
126 | }
127 | }
128 | }
129 | }
130 |
131 | @media (max-width: 480px), (max-height: 480px) and (orientation: landscape) {
132 | .grid {
133 | .child_2 {
134 | display: flex;
135 | padding: 10px 20px;
136 | flex-flow: column;
137 | align-items: center;
138 | .output {
139 | width: 90%;
140 | display: flex;
141 | flex-flow: column;
142 | justify-content: space-between;
143 | margin-bottom: 8%;
144 | margin-top: 3%;
145 | .subject {
146 | display: flex;
147 | align-items: center;
148 | justify-content: space-between;
149 | span {
150 | font-size: 1rem;
151 | }
152 | }
153 | .polar {
154 | display: flex;
155 | align-items: center;
156 | justify-content: space-between;
157 | span {
158 | font-size: 1rem;
159 | }
160 | }
161 | .emotion {
162 | display: flex;
163 | align-items: center;
164 | justify-content: space-between;
165 | span {
166 | font-size: 1rem;
167 | }
168 | }
169 | .emoji {
170 | display: flex;
171 | align-items: center;
172 | justify-content: space-between;
173 | span {
174 | font-size: 1rem;
175 | }
176 | img {
177 | height: 50px;
178 | width: 50px;
179 | }
180 | }
181 | }
182 | .summary {
183 | margin-top: 5%;
184 | .text {
185 | color: #1b1b1b;
186 | font-size: 1.2rem;
187 | }
188 | }
189 | }
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/src/component/Tracker/Cards/Cards.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Card, CardContent, Typography, Grid } from "@material-ui/core";
3 | import styles from "./Cards.module.css";
4 | import CountUp from "react-countup";
5 | import cx from "classnames";
6 |
7 | function Cards({ data: { confirmed, recovered, deaths, lastUpdate } }) {
8 | // console.log(data);
9 | if (!confirmed) {
10 | return "Loading.....";
11 | }
12 | return (
13 |
14 |
15 |
16 |
17 | Infected
18 |
19 |
20 |
21 | {new Date(lastUpdate).toLocaleDateString()}
22 | Number of active Cases of Covid-19
23 |
24 |
25 |
26 |
27 | Recoveries
28 |
29 |
30 |
31 | {new Date(lastUpdate).toLocaleDateString()}
32 | Number of recoveries from Covid-19
33 |
34 |
35 |
36 |
37 | Deaths
38 |
39 |
40 |
41 | {new Date(lastUpdate).toLocaleDateString()}
42 | Number of deaths caused by Covid-19
43 |
44 |
45 |
46 |
47 | );
48 | }
49 |
50 | export default Cards;
--------------------------------------------------------------------------------
/src/component/Tracker/Cards/Cards.module.css:
--------------------------------------------------------------------------------
1 | .container{
2 | margin: 50px 0;
3 |
4 | }
5 |
6 | .card{
7 | margin: 0 2% !important;
8 | }
9 |
10 | .infected{
11 | border-bottom: 10px solid rgba(0,0 , 255, 0.75);
12 | }
13 |
14 | .recovered{
15 | border-bottom: 10px solid rgba(0,255 , 0, 0.75);
16 | }
17 |
18 | .deaths{
19 | border-bottom: 10px solid rgba(255,0 , 0, 0.75);
20 | }
21 |
22 | @media (max-width: 770px){
23 | .card{
24 | margin: 2% 0 !important;
25 | }
26 | }
--------------------------------------------------------------------------------
/src/component/Tracker/Chart/Chart.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from "react";
2 | import { fetchDailyData } from "../../../services/api";
3 | import { Line, Bar } from "react-chartjs-2";
4 | import styles from "./Chart.module.css";
5 |
6 | function Chart({ data: { confirmed, recovered, deaths }, country }) {
7 | const [dailyData, setDailyData] = useState([]);
8 | const isCancelled = useRef(false);//prevent memory leaks performs only api calls when component is loaded to dom
9 |
10 | useEffect(() => {
11 | const fetchAPI = async () => {
12 | setDailyData(await fetchDailyData());
13 | }
14 | if (!isCancelled.current)
15 | fetchAPI();
16 | return () => {
17 | isCancelled.current = true;
18 | }
19 | // console.log(dailyData);
20 | }, []);
21 |
22 | const lineChart = (
23 | dailyData.length !== 0 ? (
24 | date),
27 | datasets: [{
28 | data: dailyData.map(({ confirmed }) => confirmed),
29 | label: "Infected",
30 | borderColor: "#3333ff",
31 | fill: true,
32 | }, {
33 | data: dailyData.map(({ deaths }) => deaths),
34 | label: "Deaths",
35 | borderColor: "#red",
36 | backgroundColor: "rgba(255,0,0,0.5)",
37 | fill: true,
38 | }],
39 | }}
40 | />) : null
41 | );
42 |
43 | const barChart = (
44 | confirmed ? (
45 |
63 | ) : null
64 | );
65 |
66 | return (
67 |
68 | {country ? barChart : lineChart}
69 |
70 | );
71 | }
72 |
73 | export default Chart;
--------------------------------------------------------------------------------
/src/component/Tracker/Chart/Chart.module.css:
--------------------------------------------------------------------------------
1 | .container{
2 | display: flex;
3 | justify-content: center;
4 | width: 85%;
5 | }
6 |
7 | @media (max-width: 770px){
8 | .container{
9 | width: 100%;
10 | }
11 | }
--------------------------------------------------------------------------------
/src/component/Tracker/CountryPicker/CountryPicker.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from "react";
2 | import { NativeSelect, FormControl } from "@material-ui/core";
3 | import styles from "./CountryPicker.module.css";
4 | import { fetchCountries } from "../../../services/api";
5 |
6 | function CountryPicker({ handleCountryChange }) {
7 | const isCancelled = useRef(false);//prevent memory leaks performs only api calls when component is loaded to dom
8 | const [fetchedCountries, setFetchedCountries] = useState([]);
9 |
10 | useEffect(() => {
11 | const fetchAPI = async () => {
12 | setFetchedCountries(await fetchCountries());
13 | }
14 | if (!isCancelled.current)
15 | fetchAPI();
16 | return () => {
17 | isCancelled.current = true;
18 | }
19 | }, [setFetchedCountries]);
20 |
21 | // console.log(fetchedCountries);
22 |
23 | return (
24 |
25 | { handleCountryChange(e.target.value) }}>
26 | Global
27 | {fetchedCountries.map((country, index) => {country} )}
28 |
29 |
30 |
31 | );
32 | }
33 |
34 | export default CountryPicker;
--------------------------------------------------------------------------------
/src/component/Tracker/CountryPicker/CountryPicker.module.css:
--------------------------------------------------------------------------------
1 | .formControl{
2 | width: 30%;
3 | margin-bottom: 30px !important;
4 | }
--------------------------------------------------------------------------------
/src/component/Tracker/Tracker.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Cards from "./Cards/Cards";
3 | import Chart from "./Chart/Chart";
4 | import CountryPicker from "./CountryPicker/CountryPicker";
5 | import styles from "./Tracker.module.css";
6 | import { fetchData } from "../../services/api";
7 | import covidImage from "../../assets/images/image.png";
8 |
9 | class Tracker extends React.Component {
10 |
11 | state = {
12 | data: {},
13 | country: ""
14 | }
15 |
16 | async componentDidMount() {
17 | const fetchedData = await fetchData();
18 | console.log(fetchedData);
19 | this.setState({ data: fetchedData });
20 | }
21 |
22 | handleCountryChange = async (country) => {
23 | const fetchedData = await fetchData(country);
24 | // console.log(fetchedData);
25 | this.setState({ data: fetchedData, country: country });
26 | }
27 |
28 | render() {
29 | const { data, country } = this.state;
30 | return (
31 |
32 |
33 |
34 |
35 |
36 |
37 | );
38 | }
39 | }
40 |
41 | export default Tracker;
--------------------------------------------------------------------------------
/src/component/Tracker/Tracker.module.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: rgb(250, 250, 250);
3 | }
4 |
5 | .container {
6 | display: flex;
7 | justify-content: center;
8 | align-items: center;
9 | flex-direction: column;
10 | }
11 |
12 | .image {
13 | width: 370px;
14 | margin-top: 50px;
15 | }
16 |
17 | @media (max-width: 770px) {
18 | .container {
19 | margin: 0 10%;
20 | }
21 |
22 | .image {
23 | width: 100%;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/component/charts/BarChart/BarChart.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Bar } from "react-chartjs-2";
3 |
4 | import styles from "./BarChart.module.css";
5 |
6 | const colors = {
7 | joy: "#fddb22",
8 | anger: "#ff1f1f",
9 | sad: "#3333ff",
10 | fear: "#3d3d3d",
11 | subjectivity: "#0047fc",
12 | polarity: "#1f7bac"
13 | }
14 |
15 |
16 | function BarChart(props) {
17 | let monthly = props.monthly;
18 | const stateBar = props.sentiment.length !== 0 ? {
19 | labels: props.sentiment.map(d => {
20 | if (d.week)
21 | return d.week;
22 | if (d.Month)
23 | return d.Month;
24 | if (d.date)
25 | return d.date;
26 | return d;
27 | }),
28 | datasets: [{
29 | label: "Percentage " + props.title,
30 | fill: false,
31 | barThickness: 12,
32 | backgroundColor: colors[props.title],
33 | borderWidth: 2,
34 | data: props.sentiment.map(d => (d[props.title].toFixed(2)))
35 | }
36 | ]
37 | } : null;
38 |
39 | const bar = stateBar !== null ? ( ) : null;
72 |
73 | return (
74 | <>
75 |
76 |
77 |
78 | {bar}
79 |
80 |
81 |
82 | >
83 | );
84 | }
85 |
86 |
87 | function MultiBarChart(props) {
88 | let monthly = props.monthly;
89 | const stateBar = props.sentiment.length !== 0 ? {
90 | labels: props.sentiment.map(d => {
91 | if (d.week)
92 | return d.week;
93 | if (d.Month)
94 | return d.Month;
95 | if (d.date)
96 | return d.date;
97 | return d;
98 | }),
99 | datasets: [{
100 | label: "Joy",
101 | fill: false,
102 | barThickness: 12,
103 | backgroundColor: colors.joy,
104 | borderWidth: 2,
105 | data: props.sentiment.map(d => (d.joy.toFixed(2)))
106 | }, {
107 | label: "Sad",
108 | fill: false,
109 | barThickness: 12,
110 | backgroundColor: colors.sad,
111 | borderWidth: 2,
112 | data: props.sentiment.map(d => (d.sad.toFixed(2)))
113 | }, {
114 | label: "Anger",
115 | fill: false,
116 | barThickness: 12,
117 | backgroundColor: colors.anger,
118 | borderWidth: 2,
119 | data: props.sentiment.map(d => (d.anger.toFixed(2)))
120 | }, {
121 | label: "Fear",
122 | fill: false,
123 | barThickness: 12,
124 | backgroundColor: colors.fear,
125 | borderWidth: 2,
126 | data: props.sentiment.map(d => (d.fear.toFixed(2)))
127 | }
128 | ]
129 | } : null;
130 |
131 | const bar = stateBar !== null ? ( ) : null;
165 |
166 | return (
167 | <>
168 |
169 |
170 |
171 | {bar}
172 |
173 |
174 |
175 | >
176 | );
177 | }
178 |
179 | function FrequencyBarChart(props) {
180 | //here prop is object
181 | let score = props.score;
182 | const stateBar = props.sentiment.length !== 0 ? {
183 | labels: Object.keys(props.sentiment),
184 | datasets: [{
185 | label: "Frequency " + props.title,
186 | fill: false,
187 | barThickness: 12,
188 | backgroundColor: colors[props.title.toLowerCase()],
189 | borderWidth: 2,
190 | data: Object.values(props.sentiment)
191 | }
192 | ]
193 | } : null;
194 |
195 | const bar = stateBar !== null ? ( ) : null;
228 |
229 | return (
230 | <>
231 |
232 |
233 |
234 | {bar}
235 |
236 |
237 |
238 | >
239 | );
240 | }
241 |
242 | function MultiFrequencyBarChart(props) {
243 | //here prop is array of object of all emotions
244 | const stateBar = props.sentiment.length !== 0 ? {
245 | labels: Object.keys(props.sentiment[0]),
246 | datasets: [{
247 | label: "Joy",
248 | fill: false,
249 | barThickness: 12,
250 | backgroundColor: colors.joy,
251 | borderWidth: 2,
252 | data: Object.values(props.sentiment[0])
253 | }, {
254 | label: "Sad",
255 | fill: false,
256 | barThickness: 12,
257 | backgroundColor: colors.sad,
258 | borderWidth: 2,
259 | data: Object.values(props.sentiment[1])
260 | }, {
261 | label: "Anger",
262 | fill: false,
263 | barThickness: 12,
264 | backgroundColor: colors.anger,
265 | borderWidth: 2,
266 | data: Object.values(props.sentiment[2])
267 | }, {
268 | label: "Fear",
269 | fill: false,
270 | barThickness: 12,
271 | backgroundColor: colors.fear,
272 | borderWidth: 2,
273 | data: Object.values(props.sentiment[3])
274 | }
275 | ]
276 | } : null;
277 |
278 | const bar = stateBar !== null ? ( ) : null;
311 |
312 | return (
313 | <>
314 |
315 |
316 |
317 | {bar}
318 |
319 |
320 |
321 | >
322 | );
323 | }
324 |
325 | function ScoreBarChart(props) {
326 | let monthly = props.monthly;
327 | const stateBar = props.sentiment.length !== 0 ? {
328 | labels: props.sentiment.map(d => {
329 | if (d.week)
330 | return d.week;
331 | if (d.Month)
332 | return d.Month;
333 | if (d.date)
334 | return d.date;
335 | return "";
336 | }),
337 | datasets: [{
338 | label: "Subjectivity",
339 | fill: false,
340 | barThickness: 12,
341 | backgroundColor: 'orange',
342 | borderWidth: 2,
343 | data: props.sentiment.map(d => d.subjectivity.toFixed(2))
344 | }, {
345 | label: "Polarity",
346 | fill: false,
347 | barThickness: 12,
348 | backgroundColor: 'lightgreen',
349 | borderWidth: 2,
350 | data: props.sentiment.map(d => d.polarity.toFixed(2))
351 | }
352 | ]
353 | } : null;
354 |
355 | const bar = stateBar !== null ? ( ) : null;
388 |
389 | return (
390 | <>
391 |
392 |
393 |
394 | {bar}
395 |
396 |
397 |
398 | >
399 | );
400 | }
401 |
402 | export default BarChart;
403 | export { ScoreBarChart, FrequencyBarChart, MultiBarChart, MultiFrequencyBarChart };
--------------------------------------------------------------------------------
/src/component/charts/BarChart/BarChart.module.css:
--------------------------------------------------------------------------------
1 | .Container {
2 | display: flex;
3 | flex-flow: column;
4 | flex: 1;
5 | justify-content: space-between;
6 | align-items: center;
7 | }
8 |
9 | .Chart {
10 | /* height: 80%; */
11 | height: fit-content;
12 | width: 70%;
13 | padding: 20px 20px;
14 | /* overflow-x: scroll; */
15 | }
16 |
17 | .ChartElement {
18 | height: 400px;
19 | /* width: 2000px; */
20 | /* background-color: lightgreen; */
21 | }
22 |
23 | .MultiBar {
24 | overflow-x: scroll;
25 | width: 600px;
26 | }
27 |
28 | /* Mobile */
29 |
30 | @media (max-width: 480px) {
31 | .Chart {
32 | overflow-x: scroll;
33 | }
34 |
35 | .MultiBar {
36 | overflow-x: scroll;
37 | width: 70%;
38 | }
39 | .ChartElement {
40 | width: fit-content;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/component/charts/LineChart/LineChart.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Line } from "react-chartjs-2";
3 |
4 | import styles from "./LineChart.module.css";
5 |
6 |
7 | const colors = {
8 | joy: "#fddb22",
9 | anger: "#ff1f1f",
10 | sad: "#3333ff",
11 | fear: "#3d3d3d"
12 | }
13 |
14 | function LineChart(props) {
15 | const stateLine = props.sentiment.length !== 0 ? {
16 | labels: props.sentiment.map(d =>
17 | d.date),
18 | datasets: [{
19 | label: "Percentage Score " + props.title,
20 | fill: false,
21 | backgroundColor: 'black',
22 | lineTension: .5,
23 | borderColor: colors[props.title.toLowerCase()],
24 | borderWidth: 2,
25 | data: props.sentiment.map(d => (d.value[props.title].toFixed(2)))
26 | }]
27 | } : null;
28 |
29 | const line = stateLine !== null ? ( ) : null;
67 |
68 | return (
69 | <>
70 |
71 |
72 |
73 | {line}
74 |
75 |
76 |
77 | >
78 | );
79 | }
80 |
81 | function DualLineChart(props) {
82 | const stateLine = props.sentiment.length !== 0 ? {
83 | labels: props.sentiment.map(d =>
84 | d.date),
85 | datasets: [{
86 | label: "Percentage Score " + props.title1,
87 | fill: false,
88 | backgroundColor: 'black',
89 | lineTension: .5,
90 | borderColor: 'rgba(144,238,144,10)',
91 | borderWidth: 2,
92 | data: props.sentiment.map(d => (d.value[props.title1].toFixed(2))),
93 | yAxisID: "polarity"
94 | },
95 | {
96 | label: "Percentage Score " + props.title2,
97 | fill: false,
98 | backgroundColor: 'black',
99 | lineTension: .5,
100 | borderColor: 'rgba(255,165,0,10)',
101 | borderWidth: 2,
102 | data: props.sentiment.map(d => (d.value[props.title2].toFixed(2))),
103 | yAxisID: "subjectivity"
104 | }]
105 | } : null;
106 |
107 | const line = stateLine !== null ? ( ) : null;
159 |
160 | return (
161 | <>
162 |
163 |
164 |
165 | {line}
166 |
167 |
168 |
169 | >
170 | );
171 | }
172 |
173 |
174 | function MultiLineChart(props) {
175 | const stateLine = props.sentiment.length !== 0 ? {
176 | labels: props.sentiment.map(d =>
177 | d.date),
178 | datasets: [{
179 | label: "Percentage Joy",
180 | fill: false,
181 | backgroundColor: 'black',
182 | lineTension: .5,
183 | borderColor: colors.joy,
184 | borderWidth: 2,
185 | data: props.sentiment.map(d => (d.value.joy.toFixed(2)))
186 | }, {
187 | label: "Percentage Sad",
188 | fill: false,
189 | backgroundColor: 'black',
190 | lineTension: .5,
191 | borderColor: colors.sad,
192 | borderWidth: 2,
193 | data: props.sentiment.map(d => (d.value.sad.toFixed(2)))
194 | }, {
195 | label: "Percentage Anger",
196 | fill: false,
197 | backgroundColor: 'black',
198 | lineTension: .5,
199 | borderColor: colors.anger,
200 | borderWidth: 2,
201 | data: props.sentiment.map(d => (d.value.anger.toFixed(2)))
202 | }, {
203 | label: "Percentage Fear",
204 | fill: false,
205 | backgroundColor: 'black',
206 | lineTension: .5,
207 | borderColor: colors.fear,
208 | borderWidth: 2,
209 | data: props.sentiment.map(d => (d.value.fear.toFixed(2)))
210 | }]
211 | } : null;
212 |
213 | const line = stateLine !== null ? ( ) : null;
251 |
252 | return (
253 | <>
254 |
255 |
256 |
257 | {line}
258 |
259 |
260 |
261 | >
262 | );
263 | }
264 |
265 |
266 | export default LineChart;
267 | export { DualLineChart, MultiLineChart };
--------------------------------------------------------------------------------
/src/component/charts/LineChart/LineChart.module.css:
--------------------------------------------------------------------------------
1 | .Container {
2 | display: flex;
3 | flex-flow: column;
4 | flex: 1;
5 | height: fit-content;
6 | justify-content: space-between;
7 | align-items: center;
8 | }
9 |
10 | .Chart {
11 | /* height: 80%; */
12 | height: fit-content;
13 | width: 70%;
14 | padding: 20px 20px;
15 | overflow-x: scroll;
16 | }
17 |
18 | .ChartElement {
19 | height: 400px;
20 | /* width: 1000px; */
21 | /* background-color: rgb(251, 90, 41); */
22 | }
23 |
24 | @media (max-width: 480px) {
25 | .ChartElement {
26 | width: 1000px;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/component/charts/PieChart/PieChart.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Doughnut } from 'react-chartjs-2';
3 |
4 | import styles from "./PieChart.module.css";
5 |
6 | const colors = {
7 | joy: "#fddb22",
8 | anger: "#ff1f1f",
9 | sad: "#3333ff",
10 | fear: "#3d3d3d"
11 | }
12 |
13 | function PieChart(props) {
14 |
15 | const statePie = props.sentiment.length !== 0 ? {
16 | labels: Object.keys(colors),
17 | datasets: [{
18 | borderColor: 'rgba(255,255,255,10)',
19 | borderWidth: 2,
20 | data: props.sentiment.map(d => +d.toFixed(2)),
21 | backgroundColor: Object.values(colors),
22 | hoverBackgroundColor: Object.values(colors),
23 | },
24 | ],
25 | } : null;
26 |
27 | const pie = statePie !== null ? ( ) : null;;
45 | return (
46 | <>
47 |
48 |
49 |
50 | {pie}
51 |
52 |
53 |
54 | >
55 | );
56 |
57 | }
58 |
59 | export default PieChart;
--------------------------------------------------------------------------------
/src/component/charts/PieChart/PieChart.module.css:
--------------------------------------------------------------------------------
1 | .Container {
2 | display: flex;
3 | flex-flow: column;
4 | flex: 1;
5 | justify-content: space-between;
6 | align-items: center;
7 | }
8 |
9 | .Chart {
10 | /* height: 80%;
11 | width: 70%; */
12 | padding: 20px 0;
13 | /* overflow-x: scroll; */
14 | }
15 |
16 | .ChartElement {
17 | padding: 0 0;
18 | margin: 0 0;
19 | min-width: fit-content;
20 | min-height: fit-content;
21 | height: 400px;
22 | width: 400px;
23 | }
24 |
--------------------------------------------------------------------------------
/src/component/ui/Cards/SimpleCard.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { makeStyles } from '@material-ui/core/styles';
3 | import Card from '@material-ui/core/Card';
4 | import CardContent from '@material-ui/core/CardContent';
5 | import Typography from '@material-ui/core/Typography';
6 |
7 | import CountUp from "react-countup";
8 |
9 | const useStyles = makeStyles({
10 | root:{
11 | borderRadius : "5px",
12 | boxShadow: "0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23)"
13 | },
14 | bullet: {
15 | display: 'inline-block',
16 | margin: '0 2px',
17 | transform: 'scale(0.8)',
18 | },
19 | title: {
20 | fontSize: 14,
21 | },
22 | pos: {
23 | marginBottom: 12,
24 | },
25 | });
26 |
27 | export default function SimpleCard(props) {
28 | const classes = useStyles();
29 |
30 | return (
31 |
32 |
33 |
34 |
35 |
36 |
37 | {props.content}
38 |
39 |
40 |
41 | );
42 | }
43 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { BrowserRouter as Router } from 'react-router-dom';
4 | import Root from "./root";
5 | import * as serviceWorker from './serviceWorker';
6 |
7 | ReactDOM.render(
8 |
9 |
10 |
11 |
12 | ,
13 | document.getElementById('root')
14 | );
15 |
16 | // If you want your app to work offline and load faster, you can change
17 | // unregister() to register() below. Note this comes with some pitfalls.
18 | // Learn more about service workers: https://bit.ly/CRA-PWA
19 | serviceWorker.unregister();
20 |
--------------------------------------------------------------------------------
/src/root.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import App from "./App";
3 | import Home from "./component/Home/Home";
4 | import TestModel from "./component/TestModel/TestModel";
5 | import { Route } from "react-router-dom";
6 |
7 | function Root() {
8 | return (
9 | <>
10 |
11 |
12 |
13 | >
14 | );
15 | }
16 |
17 | export default Root;
--------------------------------------------------------------------------------
/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.0/8 are considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl, {
104 | headers: { 'Service-Worker': 'script' },
105 | })
106 | .then(response => {
107 | // Ensure service worker exists, and that we really are getting a JS file.
108 | const contentType = response.headers.get('content-type');
109 | if (
110 | response.status === 404 ||
111 | (contentType != null && contentType.indexOf('javascript') === -1)
112 | ) {
113 | // No service worker found. Probably a different app. Reload the page.
114 | navigator.serviceWorker.ready.then(registration => {
115 | registration.unregister().then(() => {
116 | window.location.reload();
117 | });
118 | });
119 | } else {
120 | // Service worker found. Proceed as normal.
121 | registerValidSW(swUrl, config);
122 | }
123 | })
124 | .catch(() => {
125 | console.log(
126 | 'No internet connection found. App is running in offline mode.'
127 | );
128 | });
129 | }
130 |
131 | export function unregister() {
132 | if ('serviceWorker' in navigator) {
133 | navigator.serviceWorker.ready
134 | .then(registration => {
135 | registration.unregister();
136 | })
137 | .catch(error => {
138 | console.error(error.message);
139 | });
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/src/services/api/index.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | const url = "https://covid19.mathdro.id/api";
4 |
5 | export const fetchData = async (country) => {
6 | let changeableUrl = url;
7 | if (country) {
8 | changeableUrl = url + "/countries/" + country;
9 | }
10 | try {
11 | const { data: { confirmed, recovered, deaths, lastUpdate } } = await axios.get(changeableUrl);
12 | return { confirmed, recovered, deaths, lastUpdate };
13 | } catch (error) {
14 | console.log(error);
15 | }
16 | }
17 |
18 | export const fetchDailyData = async () => {
19 | try {
20 | const { data } = await axios.get(url + "/daily");
21 | const modifiedData = data.map((dailyData) => ({
22 | confirmed: dailyData.confirmed.total,
23 | deaths: dailyData.deaths.total,
24 | date: dailyData.reportDate,
25 | }));
26 | return modifiedData;
27 | } catch (error) {
28 | console.log(error);
29 | }
30 | }
31 |
32 | export const fetchCountries = async () => {
33 | try {
34 | const { data: { countries } } = await axios.get(url + "/countries");
35 | return countries.map((country) => country.name);
36 | } catch (error) {
37 | console.log(error);
38 | }
39 | }
--------------------------------------------------------------------------------
/src/services/frequency.js:
--------------------------------------------------------------------------------
1 | // Anger Frequency -------------
2 | const freqAnger = (sentimentData) => {
3 | let out = new Array(6).fill(0); // Initializing an array of constant length with 0
4 | sentimentData.forEach(elem => {
5 | let element = elem.value.anger;
6 | if (element < 8) out[0]++;
7 | else if (element >= 8 && element < 10) out[1]++;
8 | else if (element >= 10 && element < 12) out[2]++;
9 | else if (element >= 12 && element < 14) out[3]++;
10 | else if (element >= 14 && element < 16) out[4]++;
11 | else out[5]++;
12 | })
13 | let outObj = {
14 | "<8": out[0],
15 | "8-10": out[1],
16 | "10-12": out[2],
17 | "12-14": out[3],
18 | "14-16": out[4],
19 | ">16": out[5],
20 | }
21 | return outObj;
22 | }
23 |
24 | const freqSad = (sentimentData) => {
25 | let out = new Array(5).fill(0); // Initializing an array of constant length with 0
26 | sentimentData.forEach(elem => {
27 | let element = elem.value.sad;
28 | if (element < 25) out[0]++;
29 | else if (element >= 25 && element < 30) out[1]++;
30 | else if (element >= 30 && element < 35) out[2]++;
31 | else if (element >= 35 && element < 40) out[3]++;
32 | else out[4]++;
33 | })
34 | let outObj = {
35 | "<25": out[0],
36 | "25-30": out[1],
37 | "30-35": out[2],
38 | "35-40": out[3],
39 | ">40": out[4],
40 | }
41 | return outObj;
42 | }
43 |
44 | const freqJoy = (sentimentData) => {
45 | let out = new Array(6).fill(0); // Initializing an array of constant length with 0
46 | sentimentData.forEach(elem => {
47 | let element = elem.value.joy;
48 | if (element < 35) out[0]++;
49 | else if (element >= 35 && element < 40) out[1]++;
50 | else if (element >= 40 && element < 45) out[2]++;
51 | else if (element >= 45 && element < 50) out[3]++;
52 | else if (element >= 50 && element < 55) out[4]++;
53 | else out[5]++;
54 | })
55 | let outObj = {
56 | "<35": out[0],
57 | "35-40": out[1],
58 | "40-45": out[2],
59 | "45-50": out[3],
60 | "50-55": out[4],
61 | ">55": out[5],
62 | }
63 | return outObj;
64 | }
65 |
66 | const freqFear = (sentimentData) => {
67 | let out = new Array(9).fill(0); // Initializing an array of constant length with 0
68 | sentimentData.forEach(elem => {
69 | let element = elem.value.fear;
70 | if (element < 6) out[0]++;
71 | else if (element >= 6 && element < 7) out[1]++;
72 | else if (element >= 7 && element < 8) out[2]++;
73 | else if (element >= 8 && element < 9) out[3]++;
74 | else if (element >= 9 && element < 10) out[4]++;
75 | else if (element >= 10 && element < 11) out[5]++;
76 | else if (element >= 11 && element < 12) out[6]++;
77 | else if (element >= 12 && element < 13) out[7]++;
78 | else out[8]++;
79 | })
80 | let outObj = {
81 | "<6": out[0],
82 | "6-7": out[1],
83 | "7-8": out[2],
84 | "8-9": out[3],
85 | "9-10": out[4],
86 | "10-11": out[5],
87 | "11-12": out[6],
88 | "12-13": out[7],
89 | ">13": out[8],
90 | }
91 | return outObj;
92 | }
93 |
94 | const freqSubjectivity = (sentimentData) => {
95 | let out = new Array(7).fill(0); // Initializing an array of constant length with 0
96 | sentimentData.forEach(elem => {
97 | let element = elem.value.subjectivity;
98 | if (element < 0.33) out[0]++;
99 | else if (element >= 0.33 && element < 0.35) out[1]++;
100 | else if (element >= 0.35 && element < 0.36) out[2]++;
101 | else if (element >= 0.36 && element < 0.37) out[3]++;
102 | else if (element >= 0.37 && element < 0.38) out[4]++;
103 | else if (element >= 0.38 && element < 0.39) out[5]++;
104 | else out[6]++;
105 | })
106 | let outObj = {
107 | "<0.33": out[0],
108 | "0.33-0.35": out[1],
109 | "0.35-0.36": out[2],
110 | "0.36-0.37": out[3],
111 | "0.37-0.38": out[4],
112 | "0.38-0.39": out[5],
113 | ">0.39": out[6]
114 | }
115 | return outObj;
116 | }
117 |
118 | const freqPolarity = (sentimentData) => {
119 | let out = new Array(7).fill(0); // Initializing an array of constant length with 0
120 | sentimentData.forEach(elem => {
121 | let element = elem.value.polarity;
122 | if (element < 0.07) out[0]++;
123 | else if (element >= 0.07 && element < 0.08) out[1]++;
124 | else if (element >= 0.08 && element < 0.09) out[2]++;
125 | else if (element >= 0.09 && element < 0.10) out[3]++;
126 | else if (element >= 0.10 && element < 0.11) out[4]++;
127 | else if (element >= 0.11 && element < 0.15) out[5]++;
128 | else out[6]++;
129 | })
130 | let outObj = {
131 | "<0.07": out[0],
132 | "0.07-0.08": out[1],
133 | "0.08-0.09": out[2],
134 | "0.09-0.10": out[3],
135 | "0.10-0.11": out[4],
136 | "0.11-0.15": out[5],
137 | ">0.15": out[6]
138 | }
139 | return outObj;
140 | }
141 |
142 | // Anger Frequency -------------
143 | const freq10 = (sentimentData, type) => {
144 | let out = new Array(10).fill(0); // Initializing an array of constant length with 0
145 | sentimentData.forEach(elem => {
146 | let element;
147 | if (type === "Joy") element = elem.value.joy;
148 | else if (type === "Sad") element = elem.value.sad;
149 | else if (type === "Anger") element = elem.value.anger;
150 | else element = elem.value.fear;
151 |
152 | if (element < 10) out[0]++;
153 | else if (element >= 10 && element < 20) out[1]++;
154 | else if (element >= 20 && element < 30) out[2]++;
155 | else if (element >= 30 && element < 40) out[3]++;
156 | else if (element >= 40 && element < 50) out[4]++;
157 | else if (element >= 50 && element < 60) out[5]++;
158 | else if (element >= 60 && element < 70) out[6]++;
159 | else if (element >= 70 && element < 80) out[7]++;
160 | else if (element >= 80 && element < 90) out[8]++;
161 | else out[9]++;
162 | })
163 | let outObj = {
164 | "<10": out[0],
165 | "10-20": out[1],
166 | "20-30": out[2],
167 | "30-40": out[3],
168 | "40-50": out[4],
169 | "50-60": out[5],
170 | "60-70": out[6],
171 | "70-80": out[7],
172 | "80-90": out[8],
173 | "90-100": out[9],
174 | }
175 | return outObj;
176 | }
177 |
178 |
179 | // exporting each fn
180 | export { freq10, freqAnger, freqSubjectivity, freqSad, freqPolarity, freqJoy, freqFear };
--------------------------------------------------------------------------------
/src/services/utilities.js:
--------------------------------------------------------------------------------
1 | //utilitis function
2 |
3 | // Weekly Data Output
4 | function getWeekData(sentimentData) {
5 | let weekData = [];
6 | let week = 1;
7 | for (let i = 0; i < sentimentData.length; i = i + 7) {
8 | let fear = 0, anger = 0, sad = 0, joy = 0, subjectivity = 0, polarity = 0;
9 |
10 | for (let j = i; j < i + 7 && j < sentimentData.length; j++) {
11 | fear = fear + sentimentData[j].value.fear;
12 | anger = anger + sentimentData[j].value.anger;
13 | sad = sad + sentimentData[j].value.sad;
14 | joy = joy + sentimentData[j].value.joy;
15 | subjectivity = subjectivity + sentimentData[j].value.subjectivity;
16 | polarity = polarity + sentimentData[j].value.polarity;
17 | }
18 | let x = {
19 | "week": week,
20 | "anger": anger / 7,
21 | "sad": sad / 7,
22 | "joy": joy / 7,
23 | "fear": fear / 7,
24 | "subjectivity": subjectivity / 7,
25 | "polarity": polarity / 7
26 | }
27 | week++;
28 | weekData.push(x);
29 | }
30 | return weekData; // Output the data
31 | }
32 |
33 | // Monthly Data output
34 | function getMonthData(sentimentData) {
35 | let monthData = [];
36 | let months = ["March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
37 |
38 | let month = 0;
39 | // //Storing 'March' Data
40 | let fear = 0, anger = 0, sad = 0, joy = 0, subjectivity = 0, polarity = 0;
41 | for (let i = 0; i < 9; i++) {
42 | fear = fear + sentimentData[i].value.fear;
43 | anger = anger + sentimentData[i].value.anger;
44 | sad = sad + sentimentData[i].value.sad;
45 | joy = joy + sentimentData[i].value.joy;
46 | subjectivity = subjectivity + sentimentData[i].value.subjectivity;
47 | polarity = polarity + sentimentData[i].value.polarity;
48 | };
49 | monthData.push({
50 | "Month": months[month],
51 | "anger": anger / 9,
52 | "sad": sad / 9,
53 | "joy": joy / 9,
54 | "fear": fear / 9,
55 | "subjectivity": subjectivity / 9,
56 | "polarity": polarity / 9
57 | });
58 | month++;
59 | // Storing Rest Month in 30,31 order--------
60 | let check = true; // 0 for 30day month ,1 for 31 day month
61 | for (let i = 9; i < sentimentData.length;) {
62 | let fear = 0, anger = 0, sad = 0, joy = 0, subjectivity = 0, polarity = 0;
63 |
64 | if (check) { // Mean 30 day month
65 | for (let j = i; j < i + 30 && j < sentimentData.length; j++) {
66 | fear = fear + sentimentData[j].value.fear;
67 | anger = anger + sentimentData[j].value.anger;
68 | sad = sad + sentimentData[j].value.sad;
69 | joy = joy + sentimentData[j].value.joy;
70 | subjectivity = subjectivity + sentimentData[j].value.subjectivity;
71 | polarity = polarity + sentimentData[j].value.polarity;
72 | }
73 | monthData.push({
74 | "Month": months[month],
75 | "anger": anger / 30,
76 | "sad": sad / 30,
77 | "joy": joy / 30,
78 | "fear": fear / 30,
79 | "subjectivity": subjectivity / 30,
80 | "polarity": polarity / 30
81 | })
82 | i = i + 30;
83 | month++;
84 | check = false;
85 | }
86 | else { // Mean month is of 31
87 | for (let j = i; j < i + 31 && j < sentimentData.length; j++) {
88 | fear = fear + sentimentData[j].value.fear;
89 | anger = anger + sentimentData[j].value.anger;
90 | sad = sad + sentimentData[j].value.sad;
91 | joy = joy + sentimentData[j].value.joy;
92 | subjectivity = subjectivity + sentimentData[j].value.subjectivity;
93 | polarity = polarity + sentimentData[j].value.polarity;
94 | }
95 | monthData.push({
96 | "Month": months[month],
97 | "anger": anger / 31,
98 | "sad": sad / 31,
99 | "joy": joy / 31,
100 | "fear": fear / 31,
101 | "subjectivity": subjectivity / 31,
102 | "polarity": polarity / 31
103 | });
104 | i = i + 31;
105 | month++;
106 | check = true;
107 | }
108 | };
109 | return monthData;
110 | }
111 |
112 | // function getEmotionFrequencyData(sentimentData){
113 | // let frequency=[];
114 | // for(let i=0;i<10;i++){
115 | // frequency.push({
116 | // joy:0,
117 | // fear:0,
118 | // anger:0,
119 | // sad:0
120 | // });
121 | // }
122 | // //getting frequency of emotion in ranges of 10 percentage
123 |
124 | // for(let i=0;i