From 305b0680de8a4a9850d96cb1f0e23dd8249031eb Mon Sep 17 00:00:00 2001 From: sumn2u Date: Wed, 3 Jul 2024 14:00:15 -0500 Subject: [PATCH 1/2] added link to the dependencies page --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 58a2006..293043b 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ annotation-lab/ One can configure the tools, tags, upload images and do many more from the settings. ![configuration](./sample_images/configuration.png) -## Dependencies +## Dependencies [[documentation page]](https://annotate-docs.dwaste.live/overview/project-structure#dependencies) ### Client - [React](https://react.dev/) From dd5b1d03f557456d063b6bec0b8af833c80be6d5 Mon Sep 17 00:00:00 2001 From: sumn2u Date: Wed, 3 Jul 2024 16:01:56 -0500 Subject: [PATCH 2/2] support class distribution --- client/package-lock.json | 260 +++++++++++++++++- client/package.json | 3 +- .../src/ClassDistributionSidebarBox/index.jsx | 92 +++++++ client/src/Localization/translation-de-DE.js | 2 + client/src/Localization/translation-en-EN.js | 2 + client/src/MainLayout/index.jsx | 7 +- client/src/utils/get-data-from-server.js | 11 + server/app.py | 14 + server/db/db_handler.py | 11 + 9 files changed, 385 insertions(+), 17 deletions(-) create mode 100644 client/src/ClassDistributionSidebarBox/index.jsx diff --git a/client/package-lock.json b/client/package-lock.json index 31f19a4..cd32443 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -16,6 +16,7 @@ "@fortawesome/react-fontawesome": "^0.2.2", "@mui/icons-material": "^5.15.19", "@mui/material": "^5.15.19", + "@mui/x-charts": "^7.8.0", "axios": "^1.7.2", "cash-dom": "^8.1.5", "classnames": "^2.3.2", @@ -1838,9 +1839,9 @@ "dev": true }, "node_modules/@babel/runtime": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", - "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", + "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -3623,12 +3624,12 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.15.14", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.14.tgz", - "integrity": "sha512-UH0EiZckOWcxiXLX3Jbb0K7rC8mxTr9L9l6QhOZxYc4r8FHUkefltV9VDGLrzCaWh30SQiJvAEd7djX3XXY6Xw==", + "version": "5.15.20", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.20.tgz", + "integrity": "sha512-BK8F94AIqSrnaPYXf2KAOjGZJgWfvqAVQ2gVR3EryvQFtuBnG6RwodxrCvd3B48VuMy6Wsk897+lQMUxJyk+6g==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/utils": "^5.15.14", + "@mui/utils": "^5.15.20", "prop-types": "^15.8.1" }, "engines": { @@ -3680,15 +3681,15 @@ } }, "node_modules/@mui/system": { - "version": "5.15.15", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.15.tgz", - "integrity": "sha512-aulox6N1dnu5PABsfxVGOZffDVmlxPOVgj56HrUnJE8MCSh8lOvvkd47cebIVQQYAjpwieXQXiDPj5pwM40jTQ==", + "version": "5.15.20", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.20.tgz", + "integrity": "sha512-LoMq4IlAAhxzL2VNUDBTQxAb4chnBe8JvRINVNDiMtHE2PiPOoHlhOPutSxEbaL5mkECPVWSv6p8JEV+uykwIA==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/private-theming": "^5.15.14", + "@mui/private-theming": "^5.15.20", "@mui/styled-engine": "^5.15.14", "@mui/types": "^7.2.14", - "@mui/utils": "^5.15.14", + "@mui/utils": "^5.15.20", "clsx": "^2.1.0", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -3732,9 +3733,9 @@ } }, "node_modules/@mui/utils": { - "version": "5.15.14", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.14.tgz", - "integrity": "sha512-0lF/7Hh/ezDv5X7Pry6enMsbYyGKjADzvHyo3Qrc/SSlTsQ1VkbDMbH0m2t3OR5iIVLwMoxwM7yGd+6FCMtTFA==", + "version": "5.15.20", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.20.tgz", + "integrity": "sha512-mAbYx0sovrnpAu1zHc3MDIhPqL8RPVC5W5xcO1b7PiSCJPtckIZmBkp8hefamAvUiAV8gpfMOM6Zb+eSisbI2A==", "dependencies": { "@babel/runtime": "^7.23.9", "@types/prop-types": "^15.7.11", @@ -3758,6 +3759,44 @@ } } }, + "node_modules/@mui/x-charts": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-7.8.0.tgz", + "integrity": "sha512-SosaVtx4Ig1nu/loH6Mq4peH5Pq5UvVEnsMfe4G2IEVrMxfwrktWJo+86t9LxiHTERt4wxPKnsqlhkgBIf9ePQ==", + "dependencies": { + "@babel/runtime": "^7.24.7", + "@mui/base": "^5.0.0-beta.40", + "@mui/system": "^5.15.20", + "@mui/utils": "^5.15.20", + "@react-spring/rafz": "^9.7.3", + "@react-spring/web": "^9.7.3", + "clsx": "^2.1.1", + "d3-color": "^3.1.0", + "d3-delaunay": "^6.0.4", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.2.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.15.14", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -4005,6 +4044,71 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@react-spring/animated": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.3.tgz", + "integrity": "sha512-5CWeNJt9pNgyvuSzQH+uy2pvTg8Y4/OisoscZIR8/ZNLIOI+CatFBhGZpDGTF/OzdNFsAoGk3wiUYTwoJ0YIvw==", + "dependencies": { + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/core": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.3.tgz", + "integrity": "sha512-IqFdPVf3ZOC1Cx7+M0cXf4odNLxDC+n7IN3MDcVCTIOSBfqEcBebSv+vlY5AhM0zw05PDbjKrNmBpzv/AqpjnQ==", + "dependencies": { + "@react-spring/animated": "~9.7.3", + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/rafz": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.3.tgz", + "integrity": "sha512-9vzW1zJPcC4nS3aCV+GgcsK/WLaB520Iyvm55ARHfM5AuyBqycjvh1wbmWmgCyJuX4VPoWigzemq1CaaeRSHhQ==" + }, + "node_modules/@react-spring/shared": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.3.tgz", + "integrity": "sha512-NEopD+9S5xYyQ0pGtioacLhL2luflh6HACSSDUZOwLHoxA5eku1UPuqcJqjwSD6luKjjLfiLOspxo43FUHKKSA==", + "dependencies": { + "@react-spring/types": "~9.7.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/types": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.3.tgz", + "integrity": "sha512-Kpx/fQ/ZFX31OtlqVEFfgaD1ACzul4NksrvIgYfIFq9JpDHFwQkMVZ10tbo0FU/grje4rcL4EIrjekl3kYwgWw==" + }, + "node_modules/@react-spring/web": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.3.tgz", + "integrity": "sha512-BXt6BpS9aJL/QdVqEIX9YoUy8CE6TJrU0mNCqSoxdXlIeNcEBWOfIyE6B14ENNsyQKS3wOWkiJfco0tCr/9tUg==", + "dependencies": { + "@react-spring/animated": "~9.7.3", + "@react-spring/core": "~9.7.3", + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/@rollup/plugin-inject": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz", @@ -6960,6 +7064,111 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/data-urls": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", @@ -7061,6 +7270,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -8618,6 +8835,14 @@ "fast-loops": "^1.1.3" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/into-stream": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-7.0.0.tgz", @@ -16381,6 +16606,11 @@ "inherits": "^2.0.1" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + }, "node_modules/rollup": { "version": "4.13.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", diff --git a/client/package.json b/client/package.json index 7a51b4d..5a626ab 100644 --- a/client/package.json +++ b/client/package.json @@ -15,6 +15,7 @@ "@fortawesome/react-fontawesome": "^0.2.2", "@mui/icons-material": "^5.15.19", "@mui/material": "^5.15.19", + "@mui/x-charts": "^7.8.0", "axios": "^1.7.2", "cash-dom": "^8.1.5", "classnames": "^2.3.2", @@ -72,7 +73,7 @@ "prettier": { "semi": false }, - "jest":{ + "jest": { "testEnvironment": "jsdom", "moduleNameMapper": { "^color-alpha$": "/node_modules/color-alpha" diff --git a/client/src/ClassDistributionSidebarBox/index.jsx b/client/src/ClassDistributionSidebarBox/index.jsx new file mode 100644 index 0000000..408def2 --- /dev/null +++ b/client/src/ClassDistributionSidebarBox/index.jsx @@ -0,0 +1,92 @@ +// @flow + +import React, { useEffect, useState } from "react" +import { createTheme, ThemeProvider } from "@mui/material/styles" +import SidebarBoxContainer from "../SidebarBoxContainer" +import BarChartIcon from '@mui/icons-material/BarChart'; +import { grey } from "@mui/material/colors" +import { useTranslation } from "react-i18next" +import { BarChart } from '@mui/x-charts/BarChart'; +import RefreshIcon from '@mui/icons-material/Refresh'; +import IconButton from "@mui/material/IconButton"; +import { getLabels } from "../utils/get-data-from-server"; +import colors from "../colors"; + +const theme = createTheme() +export const ClassDistributionSidebarBox = ({ + regionClsList +}) => { + + const { t } = useTranslation(); + const [labelsInfo, setLabelsInfo] = useState([]) + const assignRandomColors = (responseList, classList) => { + let coloredResponse = []; + responseList.forEach(entry => { + let className = entry['class']; + let index = classList.indexOf(className); + + if (index !== -1) { + const randomColor = index < classList.length ? colors[index]: colors[index % colors.length] + entry['color'] = randomColor; + entry['label'] = className; + coloredResponse.push(entry); + } + }); + return coloredResponse; + } + + + + const fetchData = () => { + getLabels() + .then(response => { + let coloredResponse = assignRandomColors(response, regionClsList); + setLabelsInfo(coloredResponse); + }) + .catch(error => { + console.log(error, "error"); + }); + }; + + useEffect(() => { + fetchData(); + }, []); + + const handleRefreshClick = () => { + fetchData(); + }; + + const barChartsParams = { + slotProps: { + legend: { + hidden: true, + }, + }, + } + + return ( + + } + noScroll={true} + > +
+ + + + +
+
+
+ ) +} + +export default ClassDistributionSidebarBox; diff --git a/client/src/Localization/translation-de-DE.js b/client/src/Localization/translation-de-DE.js index f07ea63..63038d3 100644 --- a/client/src/Localization/translation-de-DE.js +++ b/client/src/Localization/translation-de-DE.js @@ -2,6 +2,8 @@ const translationDeDE = { "menu.classifications": "Labels", "menu.history": "Verlauf", "menu.regions": "Regionen", + "menu.class_distribution": "Klassenverteilung", + "menu.class_distribution_count": "Anzahl", "menu.keyframes": "Schlüsselbilder", "menu.images": "Bilder", "error.image": "Bild konnte nicht geladen werden", diff --git a/client/src/Localization/translation-en-EN.js b/client/src/Localization/translation-en-EN.js index 322ddbc..583a705 100644 --- a/client/src/Localization/translation-en-EN.js +++ b/client/src/Localization/translation-en-EN.js @@ -1,6 +1,8 @@ const translationEnEN = { "menu.classifications": "Labels", "menu.history": "History", + "menu.class_distribution": "Class Distribution", + "menu.class_distribution_count": "Count", "menu.regions": "Regions", "menu.keyframes": "Keyframes", "menu.images": "Images", diff --git a/client/src/MainLayout/index.jsx b/client/src/MainLayout/index.jsx index 89bc437..ba2f014 100644 --- a/client/src/MainLayout/index.jsx +++ b/client/src/MainLayout/index.jsx @@ -26,7 +26,8 @@ import {Save, ExitToApp} from "@mui/icons-material" import capitalize from "lodash/capitalize" import { useTranslation } from "react-i18next" import { clear_db } from "../utils/get-data-from-server" -import { useSnackbar} from "../SnackbarContext/index.jsx" +import { useSnackbar} from "../SnackbarContext" +import ClassDistributionSidebarBox from "../ClassDistributionSidebarBox" const emptyArr = [] const theme = createTheme() @@ -385,6 +386,10 @@ export const MainLayout = ({ history={state.history} onRestoreHistory={action("RESTORE_HISTORY")} />, + ].filter(Boolean)} > {canvas} diff --git a/client/src/utils/get-data-from-server.js b/client/src/utils/get-data-from-server.js index 6772446..3ed05c4 100644 --- a/client/src/utils/get-data-from-server.js +++ b/client/src/utils/get-data-from-server.js @@ -24,6 +24,17 @@ export const getImageFile = (api, configuration) => { }); }; +export const getLabels = () => { + return new Promise((resolve, reject) => { + axios.post(`${config.SERVER_URL}/class_distribution`) + .then(response => { + resolve(response.data); + }) + .catch(error => { + reject(error?.response); // Reject with error data + }); + }) + } export const clear_db = () => { return new Promise((resolve, reject) => { diff --git a/server/app.py b/server/app.py index 2f3af27..f29f38c 100644 --- a/server/app.py +++ b/server/app.py @@ -279,6 +279,20 @@ def download_configuration(): print('Error:', e) return jsonify({'error': str(e)}), 500 +@app.route('/class_distribution', methods=['POST']) +@cross_origin(origin=client_url, headers=['Content-Type']) +def class_distribution(): + try: + class_data = dbModule.get_class_distribution() + response_data = [{'data': [count], 'class': class_name} for class_name, count in class_data.items()] + + return jsonify(response_data), 200 + + except Exception as e: + print('Error:', e) + traceback.print_exc() + return jsonify({'error': str(e)}), 500 + @app.route('/download_image_with_annotations', methods=['POST']) @cross_origin(origin=client_url, headers=['Content-Type']) def download_image_with_annotations(): diff --git a/server/db/db_handler.py b/server/db/db_handler.py index 7044029..1d3c12d 100644 --- a/server/db/db_handler.py +++ b/server/db/db_handler.py @@ -272,6 +272,17 @@ def clear_db(self): except Exception as e: print(f"Error occurred: {e}") + + def get_class_distribution(self): + class_counts = pd.Series(dtype=int) + + # Count classes in each DataFrame + class_counts = class_counts.add(self.imageCircleRegions['class'].value_counts(), fill_value=0) + class_counts = class_counts.add(self.imageBoxRegions['class'].value_counts(), fill_value=0) + class_counts = class_counts.add(self.imagePolygonRegions['class'].value_counts(), fill_value=0) + + # Convert the series to a dictionary and return + return class_counts.to_dict() def __str__(self): return 'database'