From b3b8637f0e3869d0b2de9c6f9a4e60cdc0a39fad Mon Sep 17 00:00:00 2001 From: Oleh Omelchenko Date: Mon, 2 Dec 2024 00:35:03 +0200 Subject: [PATCH 1/5] feat: dockerize app --- .gitignore | 1 + ReactTool/backend/.dockerignore | 4 + ReactTool/backend/Dockerfile | 17 +++ ReactTool/backend/app.py | 2 + ReactTool/frontend/.dockerignore | 4 + ReactTool/frontend/.gitignore | 2 + ReactTool/frontend/Dockerfile | 12 ++ ReactTool/frontend/package.json | 2 +- ReactTool/frontend/src/pages/tutorial.js | 2 +- .../frontend/src/pages/visualization_quiz.js | 2 +- docker-compose.yml | 36 +++++ mini-vlat-tree.txt | 137 ++++++++++++++++++ 12 files changed, 218 insertions(+), 3 deletions(-) create mode 100644 .gitignore create mode 100644 ReactTool/backend/.dockerignore create mode 100644 ReactTool/backend/Dockerfile create mode 100644 ReactTool/frontend/.dockerignore create mode 100644 ReactTool/frontend/Dockerfile create mode 100644 docker-compose.yml create mode 100644 mini-vlat-tree.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/ReactTool/backend/.dockerignore b/ReactTool/backend/.dockerignore new file mode 100644 index 0000000..84e0189 --- /dev/null +++ b/ReactTool/backend/.dockerignore @@ -0,0 +1,4 @@ +__pycache__ +*.pyc +.dockerignore +Dockerfile \ No newline at end of file diff --git a/ReactTool/backend/Dockerfile b/ReactTool/backend/Dockerfile new file mode 100644 index 0000000..441ca8e --- /dev/null +++ b/ReactTool/backend/Dockerfile @@ -0,0 +1,17 @@ +FROM python:3.9 + +WORKDIR /app + +COPY Pipfile Pipfile.lock ./ + +RUN pip install pipenv && \ + pipenv install --system --deploy && \ + pip install flask-cors + +# Create necessary directories for data storage +RUN mkdir -p /app/surveys/quiz + +COPY . . + +EXPOSE 5000 +CMD ["flask", "run", "--host=0.0.0.0"] \ No newline at end of file diff --git a/ReactTool/backend/app.py b/ReactTool/backend/app.py index e2960b2..c68caac 100755 --- a/ReactTool/backend/app.py +++ b/ReactTool/backend/app.py @@ -13,11 +13,13 @@ import secrets import pandas as pd import db_conf from flask import send_file +from flask_cors import CORS #from flask_mail import Mail, Message #import firebase_admin #from firebase_admin import credentials, firestore, initialize_app, firebase app = Flask(__name__, static_folder='../frontend/build', static_url_path='/') +CORS(app) # Add this line app.config['MYSQL_DATABASE_HOST'] = db_conf.host app.config['MYSQL_DATABASE_USER'] = db_conf.user app.config['MYSQL_DATABASE_PASSWORD'] = db_conf.password diff --git a/ReactTool/frontend/.dockerignore b/ReactTool/frontend/.dockerignore new file mode 100644 index 0000000..1e7c3d0 --- /dev/null +++ b/ReactTool/frontend/.dockerignore @@ -0,0 +1,4 @@ +node_modules +build +.dockerignore +Dockerfile diff --git a/ReactTool/frontend/.gitignore b/ReactTool/frontend/.gitignore index 4d29575..da17307 100644 --- a/ReactTool/frontend/.gitignore +++ b/ReactTool/frontend/.gitignore @@ -21,3 +21,5 @@ npm-debug.log* yarn-debug.log* yarn-error.log* + +*.pyc \ No newline at end of file diff --git a/ReactTool/frontend/Dockerfile b/ReactTool/frontend/Dockerfile new file mode 100644 index 0000000..8a3630c --- /dev/null +++ b/ReactTool/frontend/Dockerfile @@ -0,0 +1,12 @@ +FROM node:16 + +WORKDIR /app +COPY package*.json ./ +COPY yarn.lock ./ + +RUN yarn install + +COPY . . + +EXPOSE 3000 +CMD ["yarn", "start"] diff --git a/ReactTool/frontend/package.json b/ReactTool/frontend/package.json index c1fb691..019d794 100644 --- a/ReactTool/frontend/package.json +++ b/ReactTool/frontend/package.json @@ -59,5 +59,5 @@ "last 1 safari version" ] }, - "proxy": "http://localhost:5000" + "proxy": "http://localhost:3000" } diff --git a/ReactTool/frontend/src/pages/tutorial.js b/ReactTool/frontend/src/pages/tutorial.js index 074d438..f7912c2 100644 --- a/ReactTool/frontend/src/pages/tutorial.js +++ b/ReactTool/frontend/src/pages/tutorial.js @@ -31,7 +31,7 @@ class Tutorial extends Component { componentDidMount() { - fetch('./new_session_id', { + fetch('http://localhost:8000/new_session_id', { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, method: 'POST', body: JSON.stringify({ diff --git a/ReactTool/frontend/src/pages/visualization_quiz.js b/ReactTool/frontend/src/pages/visualization_quiz.js index e0966d4..e61586a 100644 --- a/ReactTool/frontend/src/pages/visualization_quiz.js +++ b/ReactTool/frontend/src/pages/visualization_quiz.js @@ -178,7 +178,7 @@ class VisQuiz extends Component { on_survey_click() { - fetch('./record_responses_to_db', { + fetch('http://localhost:8000/record_responses_to_db', { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, method: 'POST', body: JSON.stringify({ diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..3eb2c43 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,36 @@ +version: '3.8' + +services: + frontend: + build: + context: ./ReactTool/frontend + ports: + - "3000:3000" + volumes: + - ./ReactTool/frontend:/app + - /app/node_modules + environment: + - REACT_APP_BACKEND_URL=http://localhost:8000 + depends_on: + - backend + networks: + - app-network + + backend: + build: + context: ./ReactTool/backend + ports: + - "8000:5000" + volumes: + - ./ReactTool/backend:/app + - ./data/surveys/quiz:/app/surveys/quiz + environment: + - FLASK_APP=app.py + - FLASK_ENV=development + - PYTHONUNBUFFERED=1 + networks: + - app-network + +networks: + app-network: + driver: bridge \ No newline at end of file diff --git a/mini-vlat-tree.txt b/mini-vlat-tree.txt new file mode 100644 index 0000000..7399165 --- /dev/null +++ b/mini-vlat-tree.txt @@ -0,0 +1,137 @@ +. +├── README.md +├── ReactTool +│   ├── README.md +│   ├── backend +│   │   ├── Pipfile +│   │   ├── Pipfile.lock +│   │   ├── README.md +│   │   ├── __pycache__ +│   │   │   ├── app.cpython-39.pyc +│   │   │   └── db_conf.cpython-39.pyc +│   │   ├── app.py +│   │   ├── db_conf.py +│   │   └── surveys +│   │   └── quiz +│   │   └── 9xdbxs46sp1p5X9yqSe_uQ.txt +│   └── frontend +│   ├── README.md +│   ├── package-lock.json +│   ├── package.json +│   ├── public +│   │   ├── favicon.ico +│   │   ├── index.html +│   │   ├── logo192.png +│   │   ├── logo512.png +│   │   ├── manifest.json +│   │   └── robots.txt +│   ├── src +│   │   ├── App.css +│   │   ├── App.js +│   │   ├── App.test.js +│   │   ├── components +│   │   │   ├── areaChart-mini.js +│   │   │   ├── barChart-mini.js +│   │   │   ├── bubbleChart-mini.js +│   │   │   ├── choropleth-mini.js +│   │   │   ├── data +│   │   │   │   ├── 100StackedBarGraph.csv +│   │   │   │   ├── AreaChart-2.csv +│   │   │   │   ├── AreaChart.csv +│   │   │   │   ├── BarGraph.csv +│   │   │   │   ├── BubbleChart.csv +│   │   │   │   ├── Choropleth.csv +│   │   │   │   ├── Histogram-3-2.csv +│   │   │   │   ├── Histogram.csv +│   │   │   │   ├── Images +│   │   │   │   │   ├── 1.png +│   │   │   │   │   ├── 10.png +│   │   │   │   │   ├── 11.png +│   │   │   │   │   ├── 12.png +│   │   │   │   │   ├── 2.png +│   │   │   │   │   ├── 3.png +│   │   │   │   │   ├── 4.png +│   │   │   │   │   ├── 5.png +│   │   │   │   │   ├── 6.png +│   │   │   │   │   ├── 7.png +│   │   │   │   │   ├── 8.png +│   │   │   │   │   ├── 9.png +│   │   │   │   │   ├── RightAns.png +│   │   │   │   │   ├── WrongAns.png +│   │   │   │   │   └── skip.png +│   │   │   │   ├── LineChart.csv +│   │   │   │   ├── Mini-VLAT +│   │   │   │   │   ├── AreaChart.png +│   │   │   │   │   ├── BarChart.png +│   │   │   │   │   ├── BubbleChart.png +│   │   │   │   │   ├── Choropleth.png +│   │   │   │   │   ├── Choropleth_New.png +│   │   │   │   │   ├── Histogram.png +│   │   │   │   │   ├── LineChart.png +│   │   │   │   │   ├── PieChart.png +│   │   │   │   │   ├── Scatterplot.png +│   │   │   │   │   ├── Stacked100.png +│   │   │   │   │   ├── StackedArea.png +│   │   │   │   │   ├── StackedBar.png +│   │   │   │   │   └── TreeMap.png +│   │   │   │   ├── PieChart.csv +│   │   │   │   ├── Scatterplot.csv +│   │   │   │   ├── StackedArea.csv +│   │   │   │   ├── StackedBarGraph.csv +│   │   │   │   ├── Treemap.json +│   │   │   │   ├── USA.json +│   │   │   │   ├── VLAT-Pics +│   │   │   │   │   ├── AreaChart.png +│   │   │   │   │   ├── BarGraph.png +│   │   │   │   │   ├── BubbleChart.png +│   │   │   │   │   ├── Choropleth.png +│   │   │   │   │   ├── Histogram.png +│   │   │   │   │   ├── LineChart.png +│   │   │   │   │   ├── Pie.png +│   │   │   │   │   ├── Scatterplot.png +│   │   │   │   │   ├── StackedArea.png +│   │   │   │   │   ├── StackedBar.png +│   │   │   │   │   ├── StackedBar100.png +│   │   │   │   │   └── TreeMap.png +│   │   │   │   ├── scatter-2.csv +│   │   │   │   ├── scatter.csv +│   │   │   │   └── us.json +│   │   │   ├── histogram-mini.js +│   │   │   ├── linechart-mini.js +│   │   │   ├── pieChart-mini.js +│   │   │   ├── quiz.js +│   │   │   ├── scatterplot-mini.js +│   │   │   ├── stacked100bar-mini.js +│   │   │   ├── stackedArea-mini.js +│   │   │   ├── stackedbar-mini.js +│   │   │   └── treeMap-mini.js +│   │   ├── index.css +│   │   ├── index.js +│   │   ├── logo.svg +│   │   ├── pages +│   │   │   ├── introduction.js +│   │   │   ├── thank_you.js +│   │   │   ├── tutorial.js +│   │   │   └── visualization_quiz.js +│   │   ├── reportWebVitals.js +│   │   └── setupTests.js +│   └── yarn.lock +├── Test +│   └── Mini-VLAT(QuestionsBank)_Updated.pdf +├── VisImages +│   ├── AreaChart.png +│   ├── BarChart.png +│   ├── BubbleChart.png +│   ├── Choropleth.png +│   ├── Choropleth_New.png +│   ├── Histogram.png +│   ├── LineChart.png +│   ├── PieChart.png +│   ├── Scatterplot.png +│   ├── Stacked100.png +│   ├── StackedArea.png +│   ├── StackedBar.png +│   └── TreeMap.png +└── mini-vlat-tree.txt + +17 directories, 118 files From 62b975ab72c1b5a482c8089c7c6de91dd4a2a756 Mon Sep 17 00:00:00 2001 From: Oleh Omelchenko Date: Mon, 2 Dec 2024 01:24:46 +0200 Subject: [PATCH 2/5] prepare production dockerfiles and env --- ReactTool/backend/Dockerfile | 6 +- ReactTool/backend/app.py | 14 +++-- ReactTool/frontend/.env | 1 + ReactTool/frontend/.env.production | 1 + ReactTool/frontend/Dockerfile.prod | 14 +++++ ReactTool/frontend/src/pages/tutorial.js | 2 +- .../frontend/src/pages/visualization_quiz.js | 2 +- docker-compose.prod.yml | 61 +++++++++++++++++++ docker-compose.yml | 18 ++---- 9 files changed, 97 insertions(+), 22 deletions(-) create mode 100644 ReactTool/frontend/.env create mode 100644 ReactTool/frontend/.env.production create mode 100644 ReactTool/frontend/Dockerfile.prod create mode 100644 docker-compose.prod.yml diff --git a/ReactTool/backend/Dockerfile b/ReactTool/backend/Dockerfile index 441ca8e..944dd22 100644 --- a/ReactTool/backend/Dockerfile +++ b/ReactTool/backend/Dockerfile @@ -6,10 +6,10 @@ COPY Pipfile Pipfile.lock ./ RUN pip install pipenv && \ pipenv install --system --deploy && \ - pip install flask-cors + pip install flask-cors tinydb -# Create necessary directories for data storage -RUN mkdir -p /app/surveys/quiz +# Create directory for database +RUN mkdir -p /app/data COPY . . diff --git a/ReactTool/backend/app.py b/ReactTool/backend/app.py index c68caac..ad4900f 100755 --- a/ReactTool/backend/app.py +++ b/ReactTool/backend/app.py @@ -14,12 +14,17 @@ import pandas as pd import db_conf from flask import send_file from flask_cors import CORS +from tinydb import TinyDB #from flask_mail import Mail, Message #import firebase_admin #from firebase_admin import credentials, firestore, initialize_app, firebase app = Flask(__name__, static_folder='../frontend/build', static_url_path='/') CORS(app) # Add this line + +db = TinyDB('/app/data/responses.json') +responses_table = db.table('responses') + app.config['MYSQL_DATABASE_HOST'] = db_conf.host app.config['MYSQL_DATABASE_USER'] = db_conf.user app.config['MYSQL_DATABASE_PASSWORD'] = db_conf.password @@ -105,10 +110,11 @@ def record_responses_to_db(): # msg = Message("Quiz Response for " + str(session_id),sender='minivlat@gmail.com', recipients=['minivlat@gmail.com']) # msg.body = data_send # mail.send(msg) - fname = str(session_id)+'.txt' - fname = './surveys/quiz/' + fname - with open(fname, 'w+') as test: - test.write(json.dumps(data) + "\n") + # fname = str(session_id)+'.txt' + # fname = './surveys/quiz/' + fname + responses_table.insert(data) + # with open(fname, 'w+') as test: + # test.write(json.dumps(data) + "\n") print('TODO: Record quiz responses into a file or DB') print('Collected quiz data: ', data) diff --git a/ReactTool/frontend/.env b/ReactTool/frontend/.env new file mode 100644 index 0000000..49ffa03 --- /dev/null +++ b/ReactTool/frontend/.env @@ -0,0 +1 @@ +REACT_APP_API_URL=http://localhost:8000 diff --git a/ReactTool/frontend/.env.production b/ReactTool/frontend/.env.production new file mode 100644 index 0000000..5fdcc7d --- /dev/null +++ b/ReactTool/frontend/.env.production @@ -0,0 +1 @@ +REACT_APP_API_URL=https://mini-vlat-ua.duckdns.org/api diff --git a/ReactTool/frontend/Dockerfile.prod b/ReactTool/frontend/Dockerfile.prod new file mode 100644 index 0000000..b801352 --- /dev/null +++ b/ReactTool/frontend/Dockerfile.prod @@ -0,0 +1,14 @@ +# ReactTool/frontend/Dockerfile.prod +FROM node:16 as build + +WORKDIR /app +COPY package*.json ./ +COPY yarn.lock ./ + +RUN yarn install + +COPY . . +RUN yarn build + +FROM nginx:alpine +COPY --from=build /app/build /usr/share/nginx/html diff --git a/ReactTool/frontend/src/pages/tutorial.js b/ReactTool/frontend/src/pages/tutorial.js index f7912c2..a9ab428 100644 --- a/ReactTool/frontend/src/pages/tutorial.js +++ b/ReactTool/frontend/src/pages/tutorial.js @@ -31,7 +31,7 @@ class Tutorial extends Component { componentDidMount() { - fetch('http://localhost:8000/new_session_id', { + fetch(`${process.env.REACT_APP_API_URL}/new_session_id`, { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, method: 'POST', body: JSON.stringify({ diff --git a/ReactTool/frontend/src/pages/visualization_quiz.js b/ReactTool/frontend/src/pages/visualization_quiz.js index e61586a..bdda02e 100644 --- a/ReactTool/frontend/src/pages/visualization_quiz.js +++ b/ReactTool/frontend/src/pages/visualization_quiz.js @@ -178,7 +178,7 @@ class VisQuiz extends Component { on_survey_click() { - fetch('http://localhost:8000/record_responses_to_db', { + fetch(`${process.env.REACT_APP_API_URL}//record_responses_to_db`, { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, method: 'POST', body: JSON.stringify({ diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..d2d4865 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,61 @@ +# docker-compose.prod.yml +version: '3.8' + +services: + traefik: + image: traefik:v2.10 + command: + - "--api.insecure=false" + - "--providers.docker=true" + - "--providers.docker.exposedbydefault=false" + - "--entrypoints.web.address=:80" + - "--entrypoints.websecure.address=:443" + - "--certificatesresolvers.myresolver.acme.tlschallenge=true" + - "--certificatesresolvers.myresolver.acme.email=ptrvtch@protonmail.com" + - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" + ports: + - "80:80" + - "443:443" + volumes: + - "/var/run/docker.sock:/var/run/docker.sock:ro" + - "./letsencrypt:/letsencrypt" + networks: + - web + + frontend: + build: + context: ./ReactTool/frontend + args: + - NODE_ENV=production + labels: + - "traefik.enable=true" + - "traefik.http.routers.frontend.rule=Host(`mini-vlat-ua.duckdns.org`)" + - "traefik.http.routers.frontend.entrypoints=websecure" + - "traefik.http.routers.frontend.tls.certresolver=myresolver" + - "traefik.http.services.frontend.loadbalancer.server.port=80" + networks: + - web + depends_on: + - backend + + backend: + build: + context: ./ReactTool/backend + volumes: + - ./data/db:/app/data + environment: + - FLASK_ENV=production + labels: + - "traefik.enable=true" + - "traefik.http.routers.backend.rule=Host(`mini-vlat-ua.duckdns.org`) && PathPrefix(`/api`)" + - "traefik.http.routers.backend.entrypoints=websecure" + - "traefik.http.routers.backend.tls.certresolver=myresolver" + - "traefik.http.services.backend.loadbalancer.server.port=5000" + - "traefik.http.middlewares.backend-strip.stripprefix.prefixes=/api" + - "traefik.http.routers.backend.middlewares=backend-strip@docker" + networks: + - web + +networks: + web: + driver: bridge diff --git a/docker-compose.yml b/docker-compose.yml index 3eb2c43..1e910a8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,20 +1,20 @@ +# docker-compose.yml (development) version: '3.8' - services: frontend: build: context: ./ReactTool/frontend + args: + - NODE_ENV=development ports: - "3000:3000" volumes: - ./ReactTool/frontend:/app - /app/node_modules environment: - - REACT_APP_BACKEND_URL=http://localhost:8000 + - NODE_ENV=development depends_on: - backend - networks: - - app-network backend: build: @@ -23,14 +23,6 @@ services: - "8000:5000" volumes: - ./ReactTool/backend:/app - - ./data/surveys/quiz:/app/surveys/quiz + - ./data/db:/app/data environment: - - FLASK_APP=app.py - FLASK_ENV=development - - PYTHONUNBUFFERED=1 - networks: - - app-network - -networks: - app-network: - driver: bridge \ No newline at end of file From 7d69c673bbf5ca87f31198d1b46aa060a53d4062 Mon Sep 17 00:00:00 2001 From: Oleh Omelchenko Date: Wed, 8 Jan 2025 13:44:05 +0200 Subject: [PATCH 3/5] localize into Ukrainian --- ReactTool/frontend/src/components/quiz.js | 24 +-- ReactTool/frontend/src/pages/introduction.js | 70 +++----- ReactTool/frontend/src/pages/thank_you.js | 13 +- ReactTool/frontend/src/pages/tutorial.js | 20 ++- .../frontend/src/pages/visualization_quiz.js | 158 +++++++++++++----- 5 files changed, 171 insertions(+), 114 deletions(-) diff --git a/ReactTool/frontend/src/components/quiz.js b/ReactTool/frontend/src/components/quiz.js index 4707e78..05a67a8 100644 --- a/ReactTool/frontend/src/components/quiz.js +++ b/ReactTool/frontend/src/components/quiz.js @@ -1,6 +1,6 @@ const questions = [ { - question: "What was the price range of a barrel of oil in 2020?", + question: "Яким був ціновий діапазон бареля нафти у 2020 році?", optionA: "$16.55 - $57.52", optionB: "$19.52 - $59.00", optionC: "$23.43 - $60.72", @@ -9,7 +9,7 @@ const questions = [ }, { - question: "What is the range of the average internet speed in Asia?", + question: "Який діапазон середньої швидкості інтернету в Азії?", optionA: "5.50Mbps - 30.60Mbps", optionB: "7.00Mbps - 29.40Mbps", optionC: "6.40Mbps - 27.38Mbps", @@ -17,7 +17,7 @@ const questions = [ correctOption: "optionD", }, { - question: "What is the cost of peanuts in Las Vegas?", + question: "Яка ціна арахісу в Лас Веґасі?", optionA: "$9.0", optionB: "$6.1", optionC: "$10.3", @@ -26,7 +26,7 @@ const questions = [ }, { - question: "What is the approval rating of Republicans among the people who have the education level of Postgraduate Study?", + question: "Який рейтинг схвалення республіканців серед людей, які мають освітній рівень післядипломної освіти?", optionA: "35%", optionB: "27%", optionC: "23%", @@ -35,7 +35,7 @@ const questions = [ }, { - question: "About what is the global smartphone market share of Samsung?", + question: "Яку приблизно частку ринку смартфонів займає Samsung?", optionA: "20%", optionB: "25%", optionC: "30%", @@ -44,7 +44,7 @@ const questions = [ }, { - question: "How many people have rated the taxi between 4.2 and 4.4?", + question: "Скільки людей оцінили таксі рейтингом між 4.2 та 4.4?", optionA: "270", optionB: "190", optionC: "300", @@ -53,7 +53,7 @@ const questions = [ }, { - question: "There is a negative linear relationship between the height and the weight of the 85 males.", + question: "Існує негативна лінійна залежність між ростом і вагою 85 чоловіків.", optionA: "True", optionB: "False", optionC: "", @@ -62,7 +62,7 @@ const questions = [ }, { - question: "What was the average price of a pound of coffee beans in September 2013?", + question: "Якою була середня ціна фунту кавових бобів в вересні 2013?", optionA: "$5.15", optionB: "$6.2", optionC: "$4.8", @@ -71,7 +71,7 @@ const questions = [ }, { - question: "What was the number of girls named 'Olivia' in 2010 in the UK?", + question: "Яку кількість дівчаток назвали «Олівія» у 2010 році у Великобританії?", optionA: "2000", optionB: "2500", optionC: "1700", @@ -80,7 +80,7 @@ const questions = [ }, { - question: "What is the total length of the metro system in Beijing?", + question: "Яка загальна протяжність системи метро в Пекіні?", optionA: "525 km", optionB: "495 km", optionC: "305 km", @@ -89,7 +89,7 @@ const questions = [ }, { - question: "In 2015, the unemployment rate for Washington (WA) was higher than that of Wisconsin (WI)", + question: "У 2015 році рівень безробіття у Вашингтоні (WA) був вищим, ніж у Вісконсині (WI).", optionA: "True", optionB: "False", optionC: "", @@ -98,7 +98,7 @@ const questions = [ }, { - question: "For which website was the number of unique visitors the largest in 2010?", + question: "Для якого сайту кількість унікальних відвідувачів була найбільшою в 2010 році?", optionA: "Amazon", optionB: "Chase", optionC: "PayPal", diff --git a/ReactTool/frontend/src/pages/introduction.js b/ReactTool/frontend/src/pages/introduction.js index 1056105..9e139b6 100644 --- a/ReactTool/frontend/src/pages/introduction.js +++ b/ReactTool/frontend/src/pages/introduction.js @@ -47,58 +47,36 @@ class Intro extends Component { return ( <> -
Consent Form
+
Згода на участь в дослідженні з візуалізації даних
-

We invite you to participate in a research study being conducted by investigators from Washington University in St. Louis. You are being asked to participate in this research study because you are an English-speaking adult in the United States. The purpose of the study is to develop an instrument that measures how well people can read, understand, and use data visualizations to solve problems.

-

If you agree to participate, we would like you to questions about a series of data visualization. For each question, you will see a data visualization and a problem to solve. Choose the BEST answer to the questions. If you are unsure, Select ''Skip'' instead of guessing. You are also free to skip any questions that you prefer not to answer. In the end, you will complete a brief demographic survey.

-

We would like to use the data we are obtaining in this study for studies going on right now as well as studies that are conducted in the future.

-

These studies may provide additional information that will be helpful in developing better visual communication tools. It is unlikely that what we learn from these studies will have a direct benefit to you. There are no plans to provide financial compensation to you should this occur. By allowing us to use your data you give up any property rights you may have in the data.

-

We will share your data with other researchers. They may be doing research in areas similar to this research or in other unrelated areas. These researchers may be at Washington University, at other research centers and institutions, or industry sponsors of research. We may also share your research data with large data repositories (a repository is a database of information) for broad sharing with the research community. If your individual research data is placed in one of these repositories only qualified researchers, who have received prior approval from individuals that monitor the use of the data, will be able to look at your information.

-

Your data will be stored without your name or any other kind of link that would enable us to identify which data are yours. Therefore, it will be available indefinitely for use in future research studies without your additional consent and cannot be removed.

- {/*

Approximately 5100 people will take part in this study at Washington University.

*/} -

There are no known risks from being in this study.

-

You will not benefit personally. However, we hope that others may benefit in the future from what we learn as a result of this study. You will not have any costs for being in this research study.

-

You will be paid for being in this research study. You will receive a pay of $8 for completing this quiz. At the end of the study, copy your survey code back to Prolific to receive your payment.

-

We will keep the information you provide confidentially. This survey is completely anonymous; we will not collect any personally identifiable information. We will only have access to your Prolific ID only, which we will use solely for payment purposes.

-

Any report or article that we write will not include information that can directly identify you. The journals that publish these reports or articles require that we share the information that was collected for this study with others to make sure the results of this study are correct and help develop new ideas for research. Your information will be shared in a way that cannot directly identify you.

-

Federal regulatory agencies and Washington University, including the Washington University Institutional Review Board (a committee that reviews and approves research studies) and the Human Research Protection Office, may inspect and copy records pertaining to this research. - - Your participation in this study is completely voluntary. You may choose not to take part at all. If you decide to participate in the study, you may stop participating at any time. Any data that was collected as part of this study will remain as part of the study records and cannot be removed. If you decide not to take part in the study or if you stop participating at any time, you won’t be penalized or lose any benefits for which you otherwise qualify. +

+ Запрошуємо взяти участь в дослідженні, що проводять викладачі та студенти Київської школи економіки. Ви запрошені взяти участь у цьому дослідженні, оскільки є дорослою людиною, яка володіє українською мовою. Мета дослідження полягає в адаптації інструменту, який вимірює, наскільки добре люди можуть зчитувати, розуміти та використовувати візуалізацію даних для вирішення проблем.

-

If you do not wish to participate in this study or want to end your participation in the study, close the browser tab without answering any of the questions.

- -

We encourage you to ask questions. If you have any questions about the research study itself, please contact Saugat Pandey (p.saugat@wustl.edu). If you feel you have been harmed from being in the study, please contact Alvitta Ottley (alvitta@wustl.edu). If you have questions, concerns, or complaints about your rights as a research participant, please contact the Human Research Protection Office at 1-(800)-438-0445 or email hrpo@wustl.edu. General information about being a research participant can be found on the Human Research Protection Office website, http://hrpo.wustl.edu. To offer input about your experiences as a research participant or to speak to someone other than the research staff, call the Human Research Protection Office at the number above.

- -

Thank you very much for your consideration of this research study.

+

+ Якщо ви погоджуєтеся взяти участь, запропонуємо вам дати відповіді щодо змісту декількох візуалізацій даних. Для кожного питання ви побачите візуалізацію даних та запитання, на яке потрібно дати відповідь. Виберіть відповідь на питання, яку вважаєте НАЙТОЧНІШОЮ. Якщо ви не впевнені, виберіть «Пропустити» замість того, щоб вгадувати. Ви також можете пропустити будь-які питання, на які ви вважаєте за краще не відповідати. У кінці ми попросимо вас заповнити короткий демографічний опитувальник. +

+

+ Дані, які ми зберемо протягом цього опитування, будуть використані в поточному та подальших дослідженнях грамотності в сфері візуалізації даних. +

+ {/*

+ Ці дослідження можуть надати додаткову інформацію, яка буде корисною для розробки кращих інструментів візуальної комунікації. Скоріш за все знахідки з цих досліджень не будуть для вас прямої користі. Немає планів надавати вам фінансову компенсацію, якщо це станеться. Дозволивши нам використовувати ваші дані, ви відмовляєтеся від будь-яких прав власності, які ви можете мати на ці дані. +

*/} +

+ Зібрані дані будуть передаті іншим дослідникам, які проводитимуть дослідження в цій або суміжних сферах. Також ми можемо опублікувати зібрані дані в репозиторіях даних для широкого доступу до наукової спільноти. Якщо ваші індивідуальні дані будуть розміщені в одному з цих репозиторіїв, лише кваліфіковані дослідники, які отримали попередню згоду від осіб, які контролюють використання даних, зможуть переглядати вашу інформацію. +

+

+ Ваші дані будуть збережені без вашого імені чи будь-якої іншої інформації, яка дозволила б нам ідентифікувати вас персонально. Тому вони будуть доступні безстроково для використання в майбутніх дослідженнях без вашої додаткової згоди та не можуть бути видалені. +

+

Участь в цьому дослідженні не містить для вас жодних відомих потенційних ризиків.

+

+ Якщо ви маєте будь-які питання щодо змісту та деталей дослідження, будь-ласка напишіть Олегу Омельченко (o_omelchenko@kse.org.ua). +

+

Дякуємо за зацікавленість дослідженням!

- {/*

Taking part in this research study is completely voluntary. You may choose not to take part at all. - If you decide to be in this study, you may stop participating at any time. Any data that was collected - as part of your participation in the study will remain as part of the study records and cannot be removed. - As a part of this study: -

    -
  • We will not collect your name or any identifying information about you. It will not be possible - to link you to your responses on the survey.
  • - -
  • We will store you response to every question along with the time taken to solve every question and total score.
  • - - - {/*
  • We will store information about your mouse interaction (e.g. what you clicked) when answering the survey questions.
  • - -
  • We may allow other researchers to use the interaction data that we collect. - Researchers from other universities can request to use the data.
  • -
- - - -

-

- We encourage you to ask questions. If you have any questions about the research study itself, please contact: Alvitta Ottley (alvitta@wustl.edu). If you have questions, concerns, or complaints about your rights as a research participant, please contact the Human Research Protection Office at 660 South Euclid Avenue, Campus Box 8089, St. Louis, MO 63110, 1-(800)-438-0445 or email hrpo@wusm.wustl.edu. General information about being a research participant can be found on the Human Research Protection Office web site, http://hrpo.wustl.edu/. To offer input about your experiences as a research participant or to speak to someone other than the research staff, call the Human Research Protection Office at the number above. - Thank you very much for your consideration of this research study. -

*/}
diff --git a/ReactTool/frontend/src/pages/thank_you.js b/ReactTool/frontend/src/pages/thank_you.js index 4059f09..ae016ee 100644 --- a/ReactTool/frontend/src/pages/thank_you.js +++ b/ReactTool/frontend/src/pages/thank_you.js @@ -6,7 +6,6 @@ import { record_ques } from './visualization_quiz'; class ThankYou extends Component { - constructor(props) { super(props) } @@ -24,8 +23,8 @@ class ThankYou extends Component { - - + + @@ -33,7 +32,7 @@ class ThankYou extends Component { ))} @@ -48,17 +47,17 @@ class ThankYou extends Component { console.log("The values of the dictionary is: " + Object.values(record_ques)) if (this.props.location.state == null) { - return (

Unknown session. Please start from the consent page

) + return (

Невизначена сесія. Будь ласка поверніться на сторінку згоди

) } if (this.state == null) { - return (

Loading...

) + return (

Завантаження...

) } return ( -

You scored {score_2} out of 12. Thank you for participating in our study. Your responses have been recorded.

+

Ваш результат: {score_2} із 12. Дякую за те що взяли участь в дослідженні. Ваші відповіді були збережені.

{this.renderTable()} diff --git a/ReactTool/frontend/src/pages/tutorial.js b/ReactTool/frontend/src/pages/tutorial.js index a9ab428..87feaec 100644 --- a/ReactTool/frontend/src/pages/tutorial.js +++ b/ReactTool/frontend/src/pages/tutorial.js @@ -54,7 +54,7 @@ class Tutorial extends Component { render() { if (this.props.location.state == null) { - return (

Unknown session. Please start from the consent page

) + return (

Невизначена сесія. Будь ласка поверніться на сторінку згоди

) } return ( @@ -62,20 +62,24 @@ class Tutorial extends Component { -

Intructions

+

Інструкції

    -
  • You will be given 12 multiple-choice questions
  • -
  • Answer to the best of your ability. If you are unsure,you may skip the questions instead of guessing.
  • - {/*
  • Please do not take this test if you are color blind. Here is a link to a separate test: https://colormax.org/color-blind-test/
  • */} - {/*
  • We will store information about your mouse interaction (e.g. what you clicked) when answering the survey questions.
  • */} +
  • + Вам буде запропоновано 12 питань з вибором однієї правильної відповіді.
  • +
  • + Дайте на них відповідь, якщо ви впевнені в своїй відповіді. Якщо ви не впевнені, ви можете пропустити питання, а не вгадувати. +
-

Important: You will have 25 seconds to answer each question. Answer to the best of your ability. You may skip the questions instead of guessing if you are unsure.

+

+ Важливо: на відповідь до кожного питання ви маєте 25 секунд. + Відповідайте на кожне питання якнайкраще. Якщо ви не впевнені, ви можете пропустити питання, а не вгадувати. +

diff --git a/ReactTool/frontend/src/pages/visualization_quiz.js b/ReactTool/frontend/src/pages/visualization_quiz.js index bdda02e..a231a21 100644 --- a/ReactTool/frontend/src/pages/visualization_quiz.js +++ b/ReactTool/frontend/src/pages/visualization_quiz.js @@ -34,18 +34,94 @@ import img12 from '../components/data/VLAT-Pics/LineChart.png' let minivis = [ - { 'vis': BarChartMini, 'type': 'Bar Chart', 'question': 'What is the average internet speed in Japan?', 'options': ["42.30 Mbps", "40.51 Mbps", "35.25 Mbps", "16.16 Mbps", "Skip"], 'correct_answer': 1, 'cimage': img9 }, - { 'vis': AreaChartMini, 'type': 'Area Chart', 'question': 'What was the average price of pount of coffee beans in October 2019?', 'options': ["$0.71", "$0.90", "$0.80", "$0.63", "Skip"], 'correct_answer': 0, 'cimage': img10 }, - { 'vis': BubbleChartMini, 'type': 'Bubble Chart', 'question': 'Which city\'s metro system has the largest number of stations?', 'options': ['Beijing', 'Shanghai', 'London', 'Seoul', "Skip"], 'correct_answer': 1, 'cimage': img3 }, - { 'vis': ChoroplethMini, 'type': 'Choropleth', 'question': 'In 2020, the unemployment rate for Washington (WA) was higher than that of Wisconsin (WI).', 'options': ['True', 'False', "Skip"], 'correct_answer': 0, 'cimage': img8 }, - { 'vis': HistogramMini, 'type': 'Histogram', 'question': 'What distance have customers traveled in the taxi the most?', 'options': ["60 - 70 Km", "30 - 40 Km", "20 - 30 Km", "50 - 60 Km", "Skip"], 'correct_answer': 1, 'cimage': img6 }, - { 'vis': LineChartMini, 'type': 'Line Chart', 'question': 'What was the price of a barrel of oil in February 2020?', 'options': ["$50.54", "$47.02", "$42.34", "$42.34", "Skip"], 'correct_answer': 0, 'cimage': img12 }, - { 'vis': TreeMapMini, 'type': 'Treemap', 'question': 'eBay is nested in the Software category.', 'options': ['True', 'False', 'Skip'], 'correct_answer': 1, 'cimage': img4 }, - { 'vis': ScatterPlotMini, 'type': 'Scatterplot', 'question': 'There is a negative linear relationship between the height and the weight of the 85 males.', 'options': ['True', 'False', 'Skip'], 'correct_answer': 1, 'cimage': img1 }, - { 'vis': StackedBarChartMini, 'type': '100% Stacked Bar', 'question': 'Which country has the lowest proportion of Gold medals?', 'options': ["Great Britain", "U.S.A.", "Japan", "Australia", 'Skip'], 'correct_answer': 0, 'cimage': img5 }, - { 'vis': StackedAreaPlotMini, 'type': 'Stacked Area', 'question': 'What was the ratio of girls named \'Isla\' to girls named \'Amelia\' in 2012 in the UK?', 'options': ["1 to 1", "1 to 2", "1 to 3", "1 to 4", "Skip"], 'correct_answer': 1, 'cimage': img7 }, - { 'vis': StackedBarChart2Mini, 'type': 'Stacked Bar', 'question': 'What is the cost of peanuts in Seoul?', 'options': ["$6.1", "$5.2", "$7.5", "$4.5", "Skip"], 'correct_answer': 0, 'cimage': img2 }, - { 'vis': PieChartMini, 'type': 'Pie Chart', 'question': 'What is the approximate global smartphone market share of Samsung?', 'options': ["17.6%", "25.3%", "10.9%", "35.2%", 'Skip'], 'correct_answer': 0, 'cimage': img11 } + { + 'vis': LineChartMini, + 'type': 'Лінійна діаграма', + 'question': 'Яким був ціновий діапазон бареля нафти у 2020 році?', + 'options': ["$16.55 - $57.52", "$19.52 - $59.00", "$23.43 - $60.72", "$21.82 - $87.52", "Пропустити"], + 'correct_answer': 0, + 'cimage': img12 + }, + { + 'vis': BarChartMini, + 'type': 'Стовпчикова діаграма (Bar Chart)', + 'question': 'Який діапазон середньої швидкості інтернету в Азії?', + 'options': ["5.50Mbps - 30.60Mbps", "7.00Mbps - 29.40Mbps", "6.40Mbps - 27.38Mbps", "5.50Mbps - 28.60Mbps", "Пропустити"], + 'correct_answer': 3, + 'cimage': img9 + }, + { + 'vis': StackedBarChart2Mini, + 'type': 'Накопичувальна стовпчикова діаграма (Stacked Bar)', + 'question': 'Яка ціна арахісу в Лас Веґасі?', + 'options': ["$9.0", "$6.1", "$10.3", "$4.3", "Пропустити"], + 'correct_answer': 1, + 'cimage': img2 + }, + { + 'vis': PieChartMini, + 'type': 'Кругова діаграма (Pie Chart)', + 'question': 'Яку приблизно частку ринку смартфонів займає Samsung?', + 'options': ["20%", "25%", "30%", "15%", "Пропустити"], + 'correct_answer': 1, + 'cimage': img11 + }, + { + 'vis': HistogramMini, + 'type': 'Гістограма (Histogram)', + 'question': 'Скільки людей оцінили таксі рейтингом між 4.2 та 4.4?', + 'options': ["270", "190", "300", "290", "Пропустити"], + 'correct_answer': 1, + 'cimage': img6 + }, + { + 'vis': ScatterPlotMini, + 'type': 'Точкова діаграма (Scatterplot)', + 'question': 'Існує негативна лінійна залежність між ростом і вагою 85 чоловіків.', + 'options': ['True', 'False', "Пропустити"], + 'correct_answer': 1, + 'cimage': img1 + }, + { + 'vis': AreaChartMini, + 'type': 'Площинна діаграма (Area Chart)', + 'question': 'Якою була середня ціна фунту кавових бобів в вересні 2013?', + 'options': ["$5.15", "$6.2", "$4.8", "$4.3", "Пропустити"], + 'correct_answer': 0, + 'cimage': img10 + }, + { + 'vis': StackedAreaPlotMini, + 'type': 'Накопичувальна площинна діаграма (Stacked Area)', + 'question': 'Яку кількість дівчаток назвали «Олівія» у 2010 році у Великобританії?', + 'options': ["2000", "2500", "1700", "2400", "Пропустити"], + 'correct_answer': 2, + 'cimage': img7 + }, + { + 'vis': BubbleChartMini, + 'type': 'Бульбашкова діаграма (Bubble Chart)', + 'question': 'Яка загальна протяжність системи метро в Пекіні?', + 'options': ["525 км", "495 км", "305 км", "475 км", "Пропустити"], + 'correct_answer': 0, + 'cimage': img3 + }, + { + 'vis': ChoroplethMini, + 'type': 'Хороплетна мапа (Choropleth)', + 'question': 'У 2015 році рівень безробіття у Вашингтоні (WA) був вищим, ніж у Вісконсині (WI).', + 'options': ['Вірно', 'Невірно', "Пропустити"], + 'correct_answer': 0, + 'cimage': img8 + }, + { + 'vis': TreeMapMini, + 'type': 'Деревоподібна діаграма (Treemap)', + 'question': 'Для якого сайту кількість унікальних відвідувачів була найбільшою в 2010 році?', + 'options': ["Amazon", "Chase", "PayPal", "Citibank", "Пропустити"], + 'correct_answer': 3, + 'cimage': img4 + } ]; var record_ques = {} @@ -143,13 +219,13 @@ class VisQuiz extends Component { score_2 = this.state.mini_score if (response === minivis[this.state.current_mini_index]['options'][truth]) { - record_ques[type] = 'Correct' + record_ques[type] = '✅ Вірно' } else if (response === 'Skip') { - record_ques[type] = 'Skip' + record_ques[type] = '⏩ Пропущено' } else { - record_ques[type] = 'Wrong' + record_ques[type] = '❌ Невірно' } console.log("The dictionary is: ", record_ques) } @@ -212,7 +288,7 @@ class VisQuiz extends Component { this.props.history.push(pageType) } timeout() { - alert("Time is up! Please select 'Ok' to proceed to the next question.") + alert('Чакс вийшов! Натисніть "ОК" щоб перейти до наступного запитання.') this.setState({ current_visualization_index: this.state.current_visualization_index + 1, }) @@ -221,7 +297,7 @@ class VisQuiz extends Component { return Math.random(); } minitimeout() { - alert("Time is up! Please select 'Ok' to proceed to the next question.") + alert('Чакс вийшов! Натисніть "ОК" щоб перейти до наступного запитання.') this.setState({ current_mini_index: this.state.current_mini_index + 1, }) @@ -236,7 +312,7 @@ class VisQuiz extends Component { if (this.props.location.state == undefined) { window.location.href = "/"; - return (

Unknown session. Please start from the consent page

) + return (

Невизначена сесія. Будь ласка поверніться на сторінку згоди

) } let ages = [] for (var i = 18; i < 100; i++) { @@ -265,7 +341,7 @@ class VisQuiz extends Component {
{ - return Time Remaining: {minutes}:{seconds}; + return Залишилось часу: {minutes}:{seconds}; }} autoStart={true} key={Date.now()} onComplete={() => this.minitimeout()} /> {/* */}
@@ -295,7 +371,7 @@ class VisQuiz extends Component { - Please select your age. + Будь ласка вкажіть свій вік. {ages.map((d, i) => ( @@ -306,54 +382,54 @@ class VisQuiz extends Component {
- Please select your gender. + Будь ласка вкажіть ваш ґендер. - - - - + + + +
- Please select your highest level of completed education. + Будь ласка, оберіть ваш найвищий рівень завершеної освіти. - - - - - + + + + +
- Are you color-blind? + Чи маєте ви колірну сліпоту (дальтонізм)? - - - + + +
- Please select your familiarity with visualization. + Будь ласка опишіть ваш досвід з візуалізацією даних. - - - + + +
- Please include any additional comments below. (optional) + (опціонально) Будь ласка, залиште коментар якщо бажаєте. @@ -365,7 +441,7 @@ class VisQuiz extends Component { onClick={this.on_survey_click.bind(this)} disabled={(this.state.form_incomplete || this.state.demographics_incomplete)} id={'survey_submit-btn'}> - Submit Responses + Відправити відповіді

From d0afcee738b1393f5ede5153d0923a7ae4d5a5fb Mon Sep 17 00:00:00 2001 From: Oleh Omelchenko Date: Thu, 9 Jan 2025 18:09:27 +0200 Subject: [PATCH 4/5] remove pyc, update gitignore --- .gitignore | 2 ++ ReactTool/backend/__pycache__/app.cpython-39.pyc | Bin 2088 -> 0 bytes .../backend/__pycache__/db_conf.cpython-39.pyc | Bin 242 -> 0 bytes 3 files changed, 2 insertions(+) delete mode 100644 ReactTool/backend/__pycache__/app.cpython-39.pyc delete mode 100644 ReactTool/backend/__pycache__/db_conf.cpython-39.pyc diff --git a/.gitignore b/.gitignore index 0d20b64..2011a9c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ *.pyc + +responses.json diff --git a/ReactTool/backend/__pycache__/app.cpython-39.pyc b/ReactTool/backend/__pycache__/app.cpython-39.pyc deleted file mode 100644 index 1703f3427a5ed9399d091de58a32c44c96048b93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2088 zcmZuyOK%iM5bmDW&My117i`RPK*?c+*h!)s5@ewmmOLcD#JhkPDH_dg_u6C6i|!tb zNA}6NqWlH>nE#RAkVt*aiNC-p)x9#N5^tyTlU^Uq&x^0bT4ziM&z zv0?E8y!<xM`4;HwL*xE^CdaHCI56wfri%rsX#X9-;pAw+hq8eN);$ zCK2C}HAY{SlnYtg=6M#+_WD@XIOROfGhpkSW+a@&39S|e1AoTyOn}6nlyO4dVZU$4 z78j9-r{OG52xYQ!vMgB=7LnKrdXHX=etj4Y*T!r2)p43Pj)_8 z8;zc?Zw!NlPZYy@ft$uz{49xtbi*)>;w%iua9^9yNx3O)MkBH}Rlc5mOjz89m#b70 z=m-;htWYr?SB*F$^z~p%qzU+BMnxgJ+V@lM0D?ae>wux2-VObyoHFk7sN9T15rO%h zKcsv|DQSFdTFUDkaof13`&C2 zDT8mymdGJ!A*3{qW>mH}lY9~-rx-~yp_#OH=pNUgL;hGK5|K1wat3=1`=WyVV|?$z zxx5V%vK{Q24eWN#i_)}iso7YF7(ga?wy-bc`2>}8lSdJgT+u3+;Sfg$7MdW0*no!Wl6tHXu<=+nKIBei4a93vbp}2!*((6Ze_6(rUm3f%ByLo< z$LquOJKlzN(Nik#y`LULAcr`s-s9!W8{Vrf+|QGQP6Z|Ny$a+zo^(%bs-B9TSL9rH zyqr!cC6x4QIfn6&Z&;$`o$SWsvfWm<5y0@}XCt^;8=)lPesMJa`1g5LOP z5SRWxCcl9lR|SU*2xOy)UEIXq7%pyLb_=Ban{fUfmsSdGQCFrkatfN1CAHsC9Vp_`C`eEvlW>}6Gv^yO3tmAQSlOO+pb(5*ika&f?eXin23VnQ54yx#p#yx=}IJ zF?6PC56=Lld(OPmtfo0B6M7f^+la5ig`kg6l{4QkDVf#~=^iUPRz;3FD|*oQk0)x62*~Tnp#|9Xk;A4np>8WSmLM2a*G8bUs{}6bc>@PvADQA zzbNGvQ%cfGh9Y*L*uVrhC}NkL*>N@}IPOKNd;Nq&KTa7k%en!ayl zUZ!rCk7I~_P-Na&~H7ihfE`d~$wXnqEQWEe@O9{FKt1R6911>p=ty HBM1Tj*f~Q~ From ec4151992f3702ba564f40eadd7920b1b928e3a0 Mon Sep 17 00:00:00 2001 From: Oleh Omelchenko Date: Thu, 9 Jan 2025 18:10:25 +0200 Subject: [PATCH 5/5] localize charts into ukrainian --- .../frontend/src/components/areaChart-mini.js | 19 +- .../frontend/src/components/barChart-mini.js | 4 +- .../src/components/bubbleChart-mini.js | 10 +- .../src/components/choropleth-mini.js | 165 +----------------- .../src/components/data/AreaChart-2.csv | 48 ++--- .../frontend/src/components/data/BarGraph.csv | 28 +-- .../src/components/data/BubbleChart.csv | 22 +-- .../src/components/data/LineChart.csv | 24 +-- .../frontend/src/components/data/PieChart.csv | 2 +- .../src/components/data/StackedBarGraph.csv | 20 +-- .../frontend/src/components/data/Treemap.json | 10 +- .../frontend/src/components/histogram-mini.js | 6 +- .../frontend/src/components/linechart-mini.js | 20 ++- .../frontend/src/components/pieChart-mini.js | 4 +- .../src/components/scatterplot-mini.js | 6 +- .../src/components/stacked100bar-mini.js | 12 +- .../src/components/stackedArea-mini.js | 12 +- .../src/components/stackedbar-mini.js | 16 +- .../frontend/src/components/treeMap-mini.js | 2 +- .../frontend/src/pages/visualization_quiz.js | 2 +- 20 files changed, 146 insertions(+), 286 deletions(-) diff --git a/ReactTool/frontend/src/components/areaChart-mini.js b/ReactTool/frontend/src/components/areaChart-mini.js index e637892..bc88d84 100644 --- a/ReactTool/frontend/src/components/areaChart-mini.js +++ b/ReactTool/frontend/src/components/areaChart-mini.js @@ -6,7 +6,18 @@ import '../App.css'; import data from './data/AreaChart-2.csv'; import img10 from '../components/data/Mini-VLAT/AreaChart.png' +const ukLocale = { + "dateTime": "%A, %e %B %Y р. %X", + "date": "%d.%m.%Y", + "time": "%H:%M:%S", + "periods": ["AM", "PM"], + "days": ["неділя", "понеділок", "вівторок", "середа", "четвер", "п'ятниця", "субота"], + "shortDays": ["нд", "пн", "вт", "ср", "чт", "пт", "сб"], + "months": ["січень", "лютий", "березень", "квітень", "травень", "червень", "липень", "серпень", "вересень", "жовтень", "листопад", "грудень"], + "shortMonths": ["січ", "лют", "бер", "кві", "тра", "чер", "лип", "сер", "вер", "жов", "лис", "гру"] +}; +const formatUk = d3.timeFormatLocale(ukLocale).format("%b %Y"); class AreaChartMini extends Component { @@ -43,7 +54,7 @@ class AreaChartMini extends Component { .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") - svg.append("text").attr("class", 'bubbleTitle').text("Average Coffee Bean Price from 2013 to 2014").style("font-weight", 'bolder').attr('x', 1.2 * margin.top).attr('y', 1.2 * margin.top).style('font-size', 0.04 * height) + svg.append("text").attr("class", 'bubbleTitle').text("Середня ціна кавових бобів з 2013 по 2014").style("font-weight", 'bolder').attr('x', 1.2 * margin.top).attr('y', 1.2 * margin.top).style('font-size', 0.04 * height) var image = svg.append('image').attr('width', 1.2 * width).attr('x', 0).attr('y', margin.top * height / width).attr('xlink:href', img10).attr('height', 1.1 * height) @@ -73,7 +84,7 @@ class AreaChartMini extends Component { svg.append("g") .attr("class", "x-axis") .attr("transform", `translate(0, ${height})`) - .call(d3.axisBottom(xScale)) + .call(d3.axisBottom(xScale).tickFormat(formatUk)) var yScale = d3.scaleLinear() .domain([0.5, 0.9]) @@ -120,7 +131,7 @@ class AreaChartMini extends Component { .attr("x", 0 - (height / 1.9)) .attr("dy", "1em") .style("text-anchor", "middle") - .text("Coffee Price ($/lb)") + .text("Ціна ($/фунт)") .style("font-weight", "bold") function make_x_gridlines() { @@ -153,7 +164,7 @@ class AreaChartMini extends Component { .attr("class", "title") .attr("x", width / 3) .attr("y", -length / margin.top) // +20 to adjust position (lower) - .text("Robusta Coffee Price") + .text("Ціна кави Робуста") .attr("fill", "black") .style("font-weight", "bold") diff --git a/ReactTool/frontend/src/components/barChart-mini.js b/ReactTool/frontend/src/components/barChart-mini.js index fe03ad0..86f4f66 100644 --- a/ReactTool/frontend/src/components/barChart-mini.js +++ b/ReactTool/frontend/src/components/barChart-mini.js @@ -131,14 +131,14 @@ class BarChartMini extends Component { .attr("x", 0 - (height / 1.9)) .attr("dy", "1em") .style("text-anchor", "middle") - .text("Internet Speed (Mbps)") + .text("Швидкість інтернету (Mbps)") .style("font-weight", "bold") svg .append("text") .attr("x", width / 4) .attr("y", -3 * length / margin.top) // +20 to adjust position (lower) - .text("Global Internet Speed (Mbps)") + .text("Швидкість інтернету у світі (Mbps)") .attr("class", "title") .attr("fill", "black") .style("font-weight", "bold") diff --git a/ReactTool/frontend/src/components/bubbleChart-mini.js b/ReactTool/frontend/src/components/bubbleChart-mini.js index 74183e9..05284ce 100644 --- a/ReactTool/frontend/src/components/bubbleChart-mini.js +++ b/ReactTool/frontend/src/components/bubbleChart-mini.js @@ -191,7 +191,7 @@ class BubbleChartMini extends Component { } }) .style("font-weight", "bold") - .text("Ridership") + .text("Пасажиропотік") svg.append("text") .attr("class", "legend-title") @@ -212,7 +212,7 @@ class BubbleChartMini extends Component { } }) .style("font-weight", "bold") - .text("(bn per year)") + .text("(млрд/рік)") svg .selectAll("legend") @@ -339,7 +339,7 @@ class BubbleChartMini extends Component { .attr("x", 0 - (height / 1.9)) .attr("dy", "1em") .style("text-anchor", "middle") - .text("Total System Length (Km)") + .text("Загальна протяжність системи (км)") .style("font-weight", "bold") svg.append("text") @@ -354,14 +354,14 @@ class BubbleChartMini extends Component { }) .style("text-anchor", "middle") .style("font-weight", "bold") - .text("Number of Stations") + .text("Кількість станцій") svg .append("text") .attr("class", "title") .attr("x", width / 3) .attr("y", -length / margin.top) // +20 to adjust position (lower) - .text("Metro Systems of the World") + .text("Системи метро у світі") .attr("fill", "black") .style("font-weight", "bold") }) diff --git a/ReactTool/frontend/src/components/choropleth-mini.js b/ReactTool/frontend/src/components/choropleth-mini.js index 4b5ce74..7b79171 100644 --- a/ReactTool/frontend/src/components/choropleth-mini.js +++ b/ReactTool/frontend/src/components/choropleth-mini.js @@ -46,173 +46,10 @@ class ChoroplethMini extends Component { .attr("height", height + margin.top + margin.bottom) .append("g") - svg.append("text").attr("class", 'bubbleTitle').text("Unemployment Rates for States in 2020").style("font-weight", 'bolder').attr('x', 1.2 * margin.top).attr('y', 0.9 * margin.top).style('font-size', 0.04 * height) + svg.append("text").attr("class", 'bubbleTitle').text("Рівень безробіття в штатах США у 2020 році").style("font-weight", 'bolder').attr('x', 1.2 * margin.top).attr('y', 0.9 * margin.top).style('font-size', 0.04 * height) var image = svg.append('image').attr('width', 1.4 * width).attr('x', 0).attr('y', margin.top * height / width).attr('xlink:href', img8).attr('height', 1.1 * height) - // else { - // const margin = { top: length / 7, right: length / 7, bottom: length / 7, left: length / 7 }, - // width = length - margin.left - margin.right, - // height = length - margin.top - margin.bottom; - - // // append the svg object to the body of the page - // //d3.select("#graph_box").selectAll("svg").remove(); - // d3.select("#graph_box").select("svg").remove(); - // const svg = d3.select("#graph_box") - // .append("svg") - // .attr("width", width + margin.left + margin.right) - // .attr("height", height + margin.top + margin.bottom) - // .append("g") - // .attr("transform", `translate(${margin.left},${margin.top})`); - - // // svg.append("text").attr("class", 'bubbleTitle').text("Unemployment Rates for States in 2015").style("font-weight", 'bolder').attr('x', 1.2 * margin.top).attr('y', 1.2 * margin.top).style('font-size', 0.04 * height) - - // // var image = svg.append('image').attr('width', 1.4 * width).attr('x', 0).attr('y', margin.top * height / width).attr('xlink:href', img8).attr('height', 1.1 * height) - - // var projection = d3.geoAlbersUsa() - // .translate([width / 2, height / 2]) - // .scale(Math.min(e.clientHeight, e.clientWidth)); - - // var path = d3.geoPath() - // .projection(projection) - - // var lowColor = '#f7fbff' - // var highColor = '#084594' - - // d3.csv(data).then(function (data) { - // var names = {}; - // data.forEach(function (d) { - // d.state = d.state; - // d.value = parseFloat(d.value); - // names[d.id] = d.code; - // }) - // var dataArr = []; - // for (var d = 0; d < data.length; d++) { - // dataArr.push(parseFloat(data[d].value)) - // } - // var minVal = d3.min(dataArr); - // var maxVal = d3.max(dataArr); - // var ramp = d3.scaleLinear().domain([minVal, maxVal]).range([lowColor, highColor]) - - // for (var i = 0; i < data.length; i++) { - // var dataState = data[i].state; - // var dataVal = data[i].value; - // var usa = topojson.feature(data_usa, data_usa.objects.states).features; - // for (var j = 0; j < usa.length; j++) { - // var jsonState = usa[j].properties.name; - // if (dataState == jsonState) { - // usa[j].properties.value = dataVal; - // break; - // } - // } - // } - // // Render the U.S. by using the path generator - // svg.selectAll("path") - // .data(usa) - // .enter().append("path") - // .attr("d", path) - // .style("stroke", "#ffff") - // .style("stroke-width", "1") - // .style("fill", function (d) { - // return ramp(d.properties.value) - // }); - - // svg.selectAll("text").data(usa).enter().append("text") - // .text(function (d) { - // return names[d.id]; - // }) - // .attr("x", function (d) { - // return path.centroid(d)[0]; - // }) - // .attr("y", function (d) { - // return path.centroid(d)[1]; - // }) - // .attr("class", "state-abbr") - // .attr("text-anchor", "middle") - // .attr("fill", "black") - // .style("font-weight", "bold") - - // //var w = e.clientWidth/4, h = e.clientHeight/6; - // //d3.select("body").select("svg").remove(); - // //d3.selectAll("svg").select(".legend").remove(); - - // var legend = svg.append("defs") - // .append("svg:linearGradient") - // .attr("id", "gradient") - // .attr("x1", "0%") - // .attr("y1", "100%") - // .attr("x2", "100%") - // .attr("y2", "100%") - // .attr("spreadMethod", "pad"); - - // legend.append("stop") - // .attr("offset", "0%") - // .attr("stop-color", highColor) - // .attr("stop-opacity", 1); - - // legend.append("stop") - // .attr("offset", "100%") - // .attr("stop-color", lowColor) - // .attr("stop-opacity", 1); - - // if (width < 350) { - // svg.append("rect") - // .attr("width", length / 4) - // .attr("height", length / 5.5 - margin.top) - // .style("fill", "url(#gradient)") - // .attr("transform", "translate(0," + (length / 5.4 - margin.left / 0.8) + ")"); - - // svg.append("text").attr("x", 0).attr("y", length / 8.5 - 0.4 * margin.top).text("12%").style("font-weight", "bold").attr("class", "legend-value") - // svg.append("text").attr("x", length / 20).attr("y", length / 8.5 - 0.4 * margin.top).text("10%").style("font-weight", "bold").attr("class", "legend-value") - // svg.append("text").attr("x", length / 10).attr("y", length / 8.5 - 0.4 * margin.top).text("8%").style("font-weight", "bold").attr("class", "legend-value") - // svg.append("text").attr("x", length / 7).attr("y", length / 8.5 - 0.4 * margin.top).text("6%").style("font-weight", "bold").attr("class", "legend-value") - // svg.append("text").attr("x", length / 5).attr("y", length / 8.5 - 0.4 * margin.top).text("4%").style("font-weight", "bold").attr("class", "legend-value") - // } - // else { - // svg.append("rect") - // .attr("width", length / 4) - // .attr("height", length / 5.5 - margin.top) - // .style("fill", "url(#gradient)") - // .attr("transform", "translate(0," + (length / 5.4 - margin.left / 1) + ")"); - - // svg.append("text").attr("x", 0).attr("y", length / 6.5 - 0.4 * margin.top).text("12%").style("font-weight", "bold").attr("class", "legend-value") - // svg.append("text").attr("x", length / 20).attr("y", length / 6.5 - 0.4 * margin.top).text("10%").style("font-weight", "bold").attr("class", "legend-value") - // svg.append("text").attr("x", length / 10).attr("y", length / 6.5 - 0.4 * margin.top).text("8%").style("font-weight", "bold").attr("class", "legend-value") - // svg.append("text").attr("x", length / 7).attr("y", length / 6.5 - 0.4 * margin.top).text("6%").style("font-weight", "bold").attr("class", "legend-value") - // svg.append("text").attr("x", length / 5).attr("y", length / 6.5 - 0.4 * margin.top).text("4%").style("font-weight", "bold").attr("class", "legend-value") - // } - - - - - - // /* - // var y = d3.scaleLinear() - // .range([length/4 - length/3.3, length/4.4 - length/(margin.left/4.0)]) - // //.domain([maxVal, minVal]); - // //ar formatPercent = d3.format("%"); - // var yAxis = d3.axisBottom(y).tickValues(["12%", "11%", "10%", "9%"]); - // svg.append("g") - // //.attr("class", "axis") - // .attr("transform", "translate(" + (length/5.45-margin.left/1.1) + "," + margin.right/0.75 + ")") - // .call(yAxis) - // .style("font-weight", "bold") - // .style("font-size", 1.3*(length/margin.top)); */ - - // svg - // .append("text") - // .attr("x", width / 5.5) - // .attr("y", -length / margin.top) // +20 to adjust position (lower) - // .text("Unemployment Rate for States in 2020 ") - // .attr("class", "title") - // .attr("fill", "black") - // .style("font-weight", "bold") - - // }); - - // } - - } diff --git a/ReactTool/frontend/src/components/data/AreaChart-2.csv b/ReactTool/frontend/src/components/data/AreaChart-2.csv index fcfb7a9..688d19a 100644 --- a/ReactTool/frontend/src/components/data/AreaChart-2.csv +++ b/ReactTool/frontend/src/components/data/AreaChart-2.csv @@ -1,25 +1,25 @@ date,value -Jan-2018,88.65 -Feb-2018,89.24 -Mar-2018,88.18 -Apr-2018,88.31 -May-2018,88.74 -Jun-2018,86.07 -Jul-2018,84.42 -Aug-2018,80.74 -Sep-2018,76.70 -Oct-2018,85.32 -Nov-2018,83.52 -Dec-2018,77.57 -Jan-2019,78.24 -Feb-2019,78.65 -Mar-2019,76.96 -Apr-2019,73.28 -May-2019,71.12 -Jun-2019,74.02 -Jul-2019,73.93 -Aug-2019,70.78 -Sep-2019,70.64 -Oct-2019,68.63 -Nov-2019,73.28 -Dec-2019,73.22 \ No newline at end of file +Січ-2018,88.65 +Лют-2018,89.24 +Бер-2018,88.18 +Кві-2018,88.31 +Тра-2018,88.74 +Чер-2018,86.07 +Лип-2018,84.42 +Сер-2018,80.74 +Вер-2018,76.70 +Жов-2018,85.32 +Лис-2018,83.52 +Гру-2018,77.57 +Січ-2019,78.24 +Лют-2019,78.65 +Бер-2019,76.96 +Кві-2019,73.28 +Тра-2019,71.12 +Чер-2019,74.02 +Лип-2019,73.93 +Сер-2019,70.78 +Вер-2019,70.64 +Жов-2019,68.63 +Лис-2019,73.28 +Гру-2019,73.22 \ No newline at end of file diff --git a/ReactTool/frontend/src/components/data/BarGraph.csv b/ReactTool/frontend/src/components/data/BarGraph.csv index 20bf0a3..6827531 100644 --- a/ReactTool/frontend/src/components/data/BarGraph.csv +++ b/ReactTool/frontend/src/components/data/BarGraph.csv @@ -1,15 +1,15 @@ Country,Speed -Australia,79.24 -China,78.61 -Hong Kong,43.88 -India,13.45 -Indonesia,16.16 -Japan,40.51 -Malaysia,23.74 -New Zealand,92.05 -Singapore,68.32 -South Korea,98.93 -Sri Lanka,12.60 -Taiwan,51.67 -Thailand,31.38 -Vietnam,35.33 \ No newline at end of file +Австралія,79.24 +Китай,78.61 +Гонконг,43.88 +Індія,13.45 +Індонезія,16.16 +Японія,40.51 +Малайзія,23.74 +Нова Зеландія,92.05 +Сінгапур,68.32 +Південна Корея,98.93 +Шрі-Ланка,12.60 +Тайвань,51.67 +Тайланд,31.38 +Вʼєтнам,35.33 \ No newline at end of file diff --git a/ReactTool/frontend/src/components/data/BubbleChart.csv b/ReactTool/frontend/src/components/data/BubbleChart.csv index 0914638..8bfe02e 100644 --- a/ReactTool/frontend/src/components/data/BubbleChart.csv +++ b/ReactTool/frontend/src/components/data/BubbleChart.csv @@ -1,12 +1,12 @@ City,Length,NumberofStations,Ridership -Delhi,230,348.12,1.7 -Guangzhow,247,531.1,2.4 -Tokyo,249,316.3,3.6 -Mexico City,163,200.9,0.93 -Moscow,198,412.1,1.6 -London,317,439.2,0.335 -Seoul,436,547.9,2.7 -Paris,304,219.9,2.3 -Beijing,342,727,0.75 -Shanghai,369,743,2.8 -N.Y.C.,458,443.7,0.67 \ No newline at end of file +Делі,230,348.12,1.7 +Гуанчжоу,247,531.1,2.4 +Токіо,249,316.3,3.6 +Мехіко,163,200.9,0.93 +Москва,198,412.1,1.6 +Лондон,317,439.2,0.335 +Сеул,436,547.9,2.7 +Париж,304,219.9,2.3 +Пекін,342,727,0.75 +Шанхай,369,743,2.8 +Нью-Йорк.,458,443.7,0.67 \ No newline at end of file diff --git a/ReactTool/frontend/src/components/data/LineChart.csv b/ReactTool/frontend/src/components/data/LineChart.csv index 8d52ac4..b2402d2 100644 --- a/ReactTool/frontend/src/components/data/LineChart.csv +++ b/ReactTool/frontend/src/components/data/LineChart.csv @@ -1,13 +1,13 @@ Month,Price -Jan-2020,57.52 -Feb-2020,50.54 -Mar-2020,29.21 -Apr-2020,16.55 -May-2020,28.56 -Jun-2020,38.31 -Jul-2020,40.71 -Aug-2020,42.34 -Sep-2020,39.63 -Oct-2020,39.4 -Nov-2020,40.94 -Dec-2020,47.02 \ No newline at end of file +Січ-2020,57.52 +Лют-2020,50.54 +Бер-2020,29.21 +Кві-2020,16.55 +Тра-2020,28.56 +Чер-2020,38.31 +Лип-2020,40.71 +Сер-2020,42.34 +Вер-2020,39.63 +Жов-2020,39.4 +Лис-2020,40.94 +Гру-2020,47.02 \ No newline at end of file diff --git a/ReactTool/frontend/src/components/data/PieChart.csv b/ReactTool/frontend/src/components/data/PieChart.csv index 9334920..564825a 100644 --- a/ReactTool/frontend/src/components/data/PieChart.csv +++ b/ReactTool/frontend/src/components/data/PieChart.csv @@ -4,4 +4,4 @@ Xiaomi,16 Apple,15 Oppo,10 Vivo,10 -Others,24 \ No newline at end of file +Інші,24 \ No newline at end of file diff --git a/ReactTool/frontend/src/components/data/StackedBarGraph.csv b/ReactTool/frontend/src/components/data/StackedBarGraph.csv index 0a9b210..39c864e 100644 --- a/ReactTool/frontend/src/components/data/StackedBarGraph.csv +++ b/ReactTool/frontend/src/components/data/StackedBarGraph.csv @@ -1,11 +1,11 @@ City,Sandwich,Water,Peanut,Soda,Vodka -Helsinki,38.2,6.4,12.1,6.4,5.5 -Oslo,29.4,7.4,15.8,7.1,5.1 -Seoul,27.4,7.4,6.1,7.9,9.9 -Zurich,31.3,5.9,10.8,5.6,4.3 -Stockholm,28.4,4.1,11.3,4.9,5 -Paris,23.6,6.8,12.6,6.8,7.0 -N.Y.C.,24.2,3.9,16.8,3.9,7.1 -Singapore,19.4,5.2,14.8,6.6,6.2 -Toronto,20.8,5.4,18.2,3.4,8.0 -Copenhagen,24.3,2.8,10.8,5.0,3.7 \ No newline at end of file +Хельсінкі,38.2,6.4,12.1,6.4,5.5 +Осло,29.4,7.4,15.8,7.1,5.1 +Сеул,27.4,7.4,6.1,7.9,9.9 +Цюріх,31.3,5.9,10.8,5.6,4.3 +Стокгольм,28.4,4.1,11.3,4.9,5 +Париж,23.6,6.8,12.6,6.8,7.0 +Нью-Йорк.,24.2,3.9,16.8,3.9,7.1 +Сінгапур,19.4,5.2,14.8,6.6,6.2 +Торонто,20.8,5.4,18.2,3.4,8.0 +Копенгаген,24.3,2.8,10.8,5.0,3.7 \ No newline at end of file diff --git a/ReactTool/frontend/src/components/data/Treemap.json b/ReactTool/frontend/src/components/data/Treemap.json index 54ebadb..8a77110 100644 --- a/ReactTool/frontend/src/components/data/Treemap.json +++ b/ReactTool/frontend/src/components/data/Treemap.json @@ -1,7 +1,7 @@ { "children": [ { - "name": "Search/Portal", + "name": "Пошук/Портал", "children": [ { "name": "Google", @@ -31,7 +31,7 @@ "colname": "level2" }, { - "name": "Social Network", + "name": "Соцмережа", "children": [ { "name": "Facebook", @@ -61,7 +61,7 @@ "colname": "level2" }, { - "name": "Software", + "name": "Програмне забезпечення", "children": [ { "name": "Mozilla", @@ -97,7 +97,7 @@ "colname": "level2" }, { - "name": "Retail", + "name": "Онлайн-магазини", "children": [ { "name": "eBay", @@ -133,7 +133,7 @@ "colname": "level2" }, { - "name": "Computer", + "name": "Копмʼютери", "children": [ { "name": "Apple", diff --git a/ReactTool/frontend/src/components/histogram-mini.js b/ReactTool/frontend/src/components/histogram-mini.js index 3703c6a..611cc94 100644 --- a/ReactTool/frontend/src/components/histogram-mini.js +++ b/ReactTool/frontend/src/components/histogram-mini.js @@ -146,7 +146,7 @@ class HistogramMini extends Component { .attr("x", - (height / 1.9)) .attr("dy", "1em") .style("text-anchor", "middle") - .text("Number of Customers") + .text("Кількість користувачів") .style("font-weight", "bold") svg.append("text") @@ -164,14 +164,14 @@ class HistogramMini extends Component { }) .style("text-anchor", "middle") .style("font-weight", "bold") - .text("Distance (in Km)") + .text("Відстань (км)") svg .append("text") .attr("class", "title") .attr("x", width / 3) .attr("y", -length / margin.top) // +20 to adjust position (lower) - .text("Trip Distance and Customers") + .text("Відстань та користувачі") .attr("fill", "black") .style("font-weight", "bold") }) diff --git a/ReactTool/frontend/src/components/linechart-mini.js b/ReactTool/frontend/src/components/linechart-mini.js index a0848d2..84e56a7 100644 --- a/ReactTool/frontend/src/components/linechart-mini.js +++ b/ReactTool/frontend/src/components/linechart-mini.js @@ -5,6 +5,18 @@ import { Container, Col, Row, Navbar, Button, ButtonGroup, ToggleButton, Form, I import '../App.css'; import img12 from '../components/data/Mini-VLAT/LineChart.png'; +const ukLocale = { + "dateTime": "%A, %e %B %Y р. %X", + "date": "%d.%m.%Y", + "time": "%H:%M:%S", + "periods": ["AM", "PM"], + "days": ["неділя", "понеділок", "вівторок", "середа", "четвер", "п'ятниця", "субота"], + "shortDays": ["нд", "пн", "вт", "ср", "чт", "пт", "сб"], + "months": ["січень", "лютий", "березень", "квітень", "травень", "червень", "липень", "серпень", "вересень", "жовтень", "листопад", "грудень"], + "shortMonths": ["січ", "лют", "бер", "кві", "тра", "чер", "лип", "сер", "вер", "жов", "лис", "гру"] +}; + +const formatUk = d3.timeFormatLocale(ukLocale).format("%B"); class LineChartMini extends Component { @@ -72,7 +84,7 @@ class LineChartMini extends Component { svg.append("g") //.attr("class", "axis") .attr("transform", `translate(0, ${height})`) - .call(d3.axisBottom(xScale).tickFormat(d3.timeFormat("%B"))) + .call(d3.axisBottom(xScale).tickFormat(formatUk)) /* .style("font-size", function() { if (length < 700){ @@ -206,7 +218,7 @@ class LineChartMini extends Component { .attr("x", 0 - (height / 1.9)) .attr("dy", "1em") .style("text-anchor", "middle") - .text("Oil Price ($)") + .text("Ціна на нафту ($)") .style("font-weight", "bold") svg @@ -214,7 +226,7 @@ class LineChartMini extends Component { .attr("class", "title") .attr("x", width / 2.5) .attr("y", -length / margin.top) // +20 to adjust position (lower) - .text("Oil Prices in 2020") + .text("Ціни на нафту в 2020") .attr("fill", "black") .style("font-weight", "bold") @@ -233,7 +245,7 @@ class LineChartMini extends Component { }) .style("text-anchor", "middle") .style("font-weight", "bold") - .text("Month") + .text("Місяць") } diff --git a/ReactTool/frontend/src/components/pieChart-mini.js b/ReactTool/frontend/src/components/pieChart-mini.js index 6f925ca..b0ecd0f 100644 --- a/ReactTool/frontend/src/components/pieChart-mini.js +++ b/ReactTool/frontend/src/components/pieChart-mini.js @@ -60,7 +60,7 @@ class PieChartMini extends Component { .append("g") .attr("transform", `translate(${width / 2}, ${height / 2})`); - var data = { Samsung: 17.6, Xiaomi: 15.5, Apple: 15.0, Oppo: 10.2, Vivo: 9.8, Others: 31.9 } + var data = { Samsung: 17.6, Xiaomi: 15.5, Apple: 15.0, Oppo: 10.2, Vivo: 9.8, Інші: 31.9 } const color = d3.scaleOrdinal() .range(['#0868ac', '#f03b20', '#feb24c', '#78c679', '#ffffb2', '#756bb1']) @@ -119,7 +119,7 @@ class PieChartMini extends Component { .attr("class", "title") .attr("x", -width / 5.5) .attr("y", -width / 3) // +20 to adjust position (lower) - .text("Global Smartphone Market Share in 2021") + .text("Світовий ринок смартфонів в 2021") .attr("fill", "black") .style("font-weight", "bold") diff --git a/ReactTool/frontend/src/components/scatterplot-mini.js b/ReactTool/frontend/src/components/scatterplot-mini.js index 467e38a..ab807fe 100644 --- a/ReactTool/frontend/src/components/scatterplot-mini.js +++ b/ReactTool/frontend/src/components/scatterplot-mini.js @@ -135,7 +135,7 @@ class ScatterPlotMini extends Component { .attr("x", 0 - (height / 1.9)) .attr("dy", "1em") .style("text-anchor", "middle") - .text("Weight (kg)") + .text("Маса (кг)") .style("font-weight", "bold") svg @@ -143,7 +143,7 @@ class ScatterPlotMini extends Component { .attr("class", "title") .attr("x", width / 4) .attr("y", -length / margin.top) // +20 to adjust position (lower) - .text("Weight and Height of 85 Individuals") + .text("Маса та висота 85 осіб") .attr("fill", "black") .style("font-weight", "bold") @@ -159,7 +159,7 @@ class ScatterPlotMini extends Component { }) .style("text-anchor", "middle") .style("font-weight", "bold") - .text("Height (cm)") + .text("Висота (см)") }) diff --git a/ReactTool/frontend/src/components/stacked100bar-mini.js b/ReactTool/frontend/src/components/stacked100bar-mini.js index e949bc4..4bb5c30 100644 --- a/ReactTool/frontend/src/components/stacked100bar-mini.js +++ b/ReactTool/frontend/src/components/stacked100bar-mini.js @@ -152,7 +152,7 @@ class StackedBarChartMini extends Component { .attr("x", 0 - (height / 1.9)) .attr("dy", "1em") .style("text-anchor", "middle") - .text("Olympic Medals (%)") + .text("Олімпійські Медалі (%)") .style("font-weight", "bold") svg.append("text") @@ -167,7 +167,7 @@ class StackedBarChartMini extends Component { }) .style("text-anchor", "middle") .style("font-weight", "bold") - .text("Countries") + .text("Країни") //var legend = svg.append('g').attr('class', 'legend').attr('transform', 'translate(' + (margin.left/2) + ',0)'); @@ -274,7 +274,7 @@ class StackedBarChartMini extends Component { .attr("fill", "#feb24c") svg.append("text") - .text("Bronze") + .text("Бронза") .attr("x", function () { if (width < 500 && width > 400) { return width + (5.5 * width / margin.left) @@ -300,7 +300,7 @@ class StackedBarChartMini extends Component { .attr("class", "legend-value") svg.append("text") - .text("Silver") + .text("Срібло") .attr("x", function () { if (width < 500 && width > 400) { return width + (5.5 * width / margin.left) @@ -326,7 +326,7 @@ class StackedBarChartMini extends Component { .attr("class", "legend-value") svg.append("text") - .text("Gold") + .text("Золото") .attr("x", function () { if (width < 500 && width > 400) { return width + (5.5 * width / margin.left) @@ -363,7 +363,7 @@ class StackedBarChartMini extends Component { } }) .attr("y", -length / margin.top) // +20 to adjust position (lower) - .text("Tokyo 2020 Olympics Performance Summary") + .text("Підсумок Олімпіади 2020 в Токіо") .attr("fill", "black") .style("font-weight", "bold") diff --git a/ReactTool/frontend/src/components/stackedArea-mini.js b/ReactTool/frontend/src/components/stackedArea-mini.js index 3046af1..de5d362 100644 --- a/ReactTool/frontend/src/components/stackedArea-mini.js +++ b/ReactTool/frontend/src/components/stackedArea-mini.js @@ -123,7 +123,7 @@ class StackedAreaPlotMini extends Component { .attr("x", 0 - (height / 1.9)) .attr("dy", "1em") .style("text-anchor", "middle") - .text("Number of Girls") + .text("Кількість дівчат") .style("font-weight", "bold") .style('font-size', function () { if (width < 500) { @@ -143,7 +143,7 @@ class StackedAreaPlotMini extends Component { }) .style("text-anchor", "middle") .style("font-weight", "bold") - .text("Year") + .text("Рік") const areaChart = svg.append('g') .attr("clip-path", "url(#clip)") @@ -276,7 +276,7 @@ class StackedAreaPlotMini extends Component { .attr("fill", "#3182bd") svg.append("text") - .text("Olivia") + .text("Олівія") .attr("x", function () { if (width < 500 && width > 400) { return width + (2 * width / margin.left) + length / 25; @@ -296,7 +296,7 @@ class StackedAreaPlotMini extends Component { .attr("class", "legend-value") svg.append("text") - .text("Isla") + .text("Айле") .attr("x", function () { if (width < 500 && width > 400) { return width + (2 * width / margin.left) + length / 25; @@ -317,7 +317,7 @@ class StackedAreaPlotMini extends Component { .attr("class", "legend-value") svg.append("text") - .text("Amelia") + .text("Амелія") .attr("x", function () { if (width < 500 && width > 400) { return width + (2 * width / margin.left) + length / 25; @@ -349,7 +349,7 @@ class StackedAreaPlotMini extends Component { } }) .attr("y", -length / margin.top) // +20 to adjust position (lower) - .text("Popular Girls' names in the UK") + .text("Популярні жіночі імена в Великій Британії") .attr("fill", "black") .style("font-weight", "bold") }) diff --git a/ReactTool/frontend/src/components/stackedbar-mini.js b/ReactTool/frontend/src/components/stackedbar-mini.js index 19bd107..40b608d 100644 --- a/ReactTool/frontend/src/components/stackedbar-mini.js +++ b/ReactTool/frontend/src/components/stackedbar-mini.js @@ -172,7 +172,7 @@ class StackedBarChart2Mini extends Component { .attr("x", - (height / 1.9)) .attr("dy", "1em") .style("text-anchor", "middle") - .text("Cost ($)") + .text("Ціна ($)") .style("font-weight", "bold") svg.append("text") @@ -187,7 +187,7 @@ class StackedBarChart2Mini extends Component { }) .style("text-anchor", "middle") .style("font-weight", "bold") - .text("Cities") + .text("Міста") var dataNormalized = [] data.forEach(function (d) { @@ -339,7 +339,7 @@ class StackedBarChart2Mini extends Component { .attr("fill", "#7fc97f") svg.append("text") - .text("Vodka") + .text("Горілка") .attr("x", function () { if (width < 500 && width > 400) { return width + (5 * width / margin.left) @@ -365,7 +365,7 @@ class StackedBarChart2Mini extends Component { .attr("class", "legend-value") svg.append("text") - .text("Soda") + .text("Содова") .attr("x", function () { if (width < 500 && width > 400) { return width + (5 * width / margin.left) @@ -391,7 +391,7 @@ class StackedBarChart2Mini extends Component { .attr("class", "legend-value") svg.append("text") - .text("Peanut") + .text("Арахіс") .attr("x", function () { if (width < 500 && width > 400) { return width + (5 * width / margin.left) @@ -417,7 +417,7 @@ class StackedBarChart2Mini extends Component { .attr("class", "legend-value") svg.append("text") - .text("Water") + .text("Вода") .attr("x", function () { if (width < 500 && width > 400) { return width + (5 * width / margin.left) @@ -443,7 +443,7 @@ class StackedBarChart2Mini extends Component { .attr("class", "legend-value") svg.append("text") - .text("Sandwich") + .text("Сендвіч") .attr("x", function () { if (width < 500 && width > 400) { return width + (5 * width / margin.left) @@ -473,7 +473,7 @@ class StackedBarChart2Mini extends Component { .attr("class", "title") .attr("x", width / 3) .attr("y", -length / margin.top) // +20 to adjust position (lower) - .text("Room Service Prices") + .text("Вартість обслуговування номера") .attr("fill", "black") .style("font-weight", "bold") }) diff --git a/ReactTool/frontend/src/components/treeMap-mini.js b/ReactTool/frontend/src/components/treeMap-mini.js index 5d5b011..822a918 100644 --- a/ReactTool/frontend/src/components/treeMap-mini.js +++ b/ReactTool/frontend/src/components/treeMap-mini.js @@ -200,7 +200,7 @@ class TreeMapMini extends Component { .attr("class", "title") .attr("x", width / margin.left) .attr("y", -length / margin.top) // +20 to adjust position (lower) - .text("The Number of Unique Visitors for Websites") + .text("Кількість унікальних відвідувачів вебсайтів") .attr("fill", "black") .style("font-weight", "bold") diff --git a/ReactTool/frontend/src/pages/visualization_quiz.js b/ReactTool/frontend/src/pages/visualization_quiz.js index a231a21..4bcf7a5 100644 --- a/ReactTool/frontend/src/pages/visualization_quiz.js +++ b/ReactTool/frontend/src/pages/visualization_quiz.js @@ -78,7 +78,7 @@ let minivis = [ 'vis': ScatterPlotMini, 'type': 'Точкова діаграма (Scatterplot)', 'question': 'Існує негативна лінійна залежність між ростом і вагою 85 чоловіків.', - 'options': ['True', 'False', "Пропустити"], + 'options': ['Вірно', 'Невірно', "Пропустити"], 'correct_answer': 1, 'cimage': img1 },
QuestionResultЗапитанняРезультат
{question} - {answer === 'Correct' ? : answer === 'Wrong' ? : answer} + {answer === 'Вірно' ? : answer === 'Невірно' ? : answer}