├── .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 | ![alt text](https://firebasestorage.googleapis.com/v0/b/tourist-bot-hilapp.appspot.com/o/Dashboard_images%2F2.PNG?alt=media&token=31835a5c-39b9-410c-8dbf-d022692d442a) 18 | 19 | #### Overall Sentiment Dashboard 20 | ![alt text](https://firebasestorage.googleapis.com/v0/b/tourist-bot-hilapp.appspot.com/o/Dashboard_images%2F3.PNG?alt=media&token=7a3e751e-6238-4e6e-9eb3-9e6f8a4d592a) 21 | 22 | #### Sentimet Beyond Positive and Negative 23 | ![alt text](https://firebasestorage.googleapis.com/v0/b/tourist-bot-hilapp.appspot.com/o/Dashboard_images%2F4.PNG?alt=media&token=88bbc0d8-15b7-4d90-8f2d-f86f7c731fe1) 24 | 25 | #### Test Model 26 | ![alt text](https://firebasestorage.googleapis.com/v0/b/tourist-bot-hilapp.appspot.com/o/Dashboard_images%2F7.PNG?alt=media&token=a15d50ce-cb20-4bb4-8e65-726b4b502048) 27 | #### Covid19 Tracker 28 | ![alt text](https://firebasestorage.googleapis.com/v0/b/tourist-bot-hilapp.appspot.com/o/Dashboard_images%2F8.PNG?alt=media&token=0a873a6a-2295-425c-97cc-fec167f5a8b8) 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 | 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 !== "" ? wordcloud : } 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 | {/* */} 100 | {props.data.map((d, index) => { return ; })} 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 | 48 | 52 | 53 | 54 |
55 |
56 |
57 |

Overview

58 |
59 | 60 | {overview} 61 | 62 |

Purpose

63 |
64 | 65 | {purpose} 66 | For more Information, Click Here. 67 | 68 |
69 |
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 | 167 | 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 | 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 !== "" && Emotion)}
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 | 27 | {fetchedCountries.map((country, index) => )} 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 | covid19 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