Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project/Task/Job Analytics #6371

Merged
merged 72 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from 58 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
4c0ce59
mock
azhavoro Jun 16, 2023
e60723c
updated mock data
klakhov Jun 22, 2023
57a17f1
added cvat-core part
klakhov Jun 26, 2023
90a79c6
Merge branch 'develop' into az/annotation_analytics
klakhov Jun 26, 2023
f3e9649
added raw project analytics
klakhov Jun 26, 2023
a9883ce
added support for histograms
klakhov Jun 26, 2023
7a3f1ce
added numeric value, improved colors
klakhov Jun 26, 2023
eda75e8
unified analytics component
klakhov Jun 26, 2023
19cf321
added analytics links to all menus
klakhov Jun 26, 2023
7d37b9c
added time interval select
klakhov Jun 26, 2023
5e5383d
added grid layout
klakhov Jun 26, 2023
d567c8f
made grid layout better
klakhov Jun 27, 2023
4aa6212
backend part 1
azhavoro Jun 27, 2023
98cfb7b
use mock for tasks and projects
azhavoro Jun 27, 2023
f703f34
Merge remote-tracking branch 'origin/az/annotation_analytics' into az…
azhavoro Jun 27, 2023
61a95a9
Merge branch 'az/annotation_analytics' of github.com:opencv/cvat into…
azhavoro Jun 27, 2023
8208fe5
t
azhavoro Jun 27, 2023
a4734b5
Descriptions
azhavoro Jun 27, 2023
161a409
Merge remote-tracking branch 'origin' into az/annotation_analytics
azhavoro Jun 30, 2023
ecc6c89
wip
azhavoro Jul 3, 2023
9aa4e36
t
azhavoro Jul 5, 2023
cfb69c0
t
azhavoro Jul 5, 2023
5854d57
transformation data
azhavoro Jul 5, 2023
e637ff1
queue
azhavoro Jul 5, 2023
90ea980
Merge remote-tracking branch 'origin/develop' into az/annotation_anal…
azhavoro Jul 5, 2023
7dc7db7
squash migrations
azhavoro Jul 5, 2023
c567e62
added licence headers
azhavoro Jul 5, 2023
53ed172
fix pylint
azhavoro Jul 5, 2023
6ce6276
fix eslint
azhavoro Jul 5, 2023
5c65291
UI binary transformation support
azhavoro Jul 5, 2023
8ba969e
Merge remote-tracking branch 'origin/develop' into az/annotation_anal…
azhavoro Jul 6, 2023
e97118e
fix tests
azhavoro Jul 6, 2023
06abeec
refactoring && apply comments
azhavoro Jul 10, 2023
184c850
apply comments part2
azhavoro Jul 10, 2023
5f499b7
apply comments part 3
azhavoro Jul 10, 2023
e1b07dc
apply comments
azhavoro Jul 12, 2023
c71443f
fix
azhavoro Jul 12, 2023
7242f0e
simple tests
azhavoro Jul 12, 2023
4dde9c2
autoformat
azhavoro Jul 13, 2023
f35c8fd
Merge remote-tracking branch 'origin/develop' into az/annotation_anal…
azhavoro Jul 13, 2023
b5fc9b3
fix pylint
azhavoro Jul 13, 2023
bd02d48
update stylint config to use scss
azhavoro Jul 13, 2023
aa2c6a7
update helm
azhavoro Jul 13, 2023
e544ee9
fix typing
azhavoro Jul 13, 2023
5f7ff61
autoformat
azhavoro Jul 13, 2023
dafa7ad
apply comments
azhavoro Jul 17, 2023
401f807
fixes
azhavoro Jul 18, 2023
d3e626a
t
azhavoro Jul 18, 2023
fbc831b
t
azhavoro Jul 18, 2023
8ca4cf9
t
azhavoro Jul 18, 2023
a97b606
t
azhavoro Jul 19, 2023
e573e8d
autoformat
azhavoro Jul 19, 2023
bc29f3f
dataseries -> data_series
azhavoro Jul 19, 2023
7ae2c06
t
azhavoro Jul 19, 2023
1263ca0
added computation time on the page
azhavoro Jul 19, 2023
f3245f4
Fixed hash for shapes and tags
bsekachev Jul 19, 2023
f52a504
Updated version of cvat-core
bsekachev Jul 19, 2023
4c4401d
Updated changelog
bsekachev Jul 19, 2023
9023f9a
title
azhavoro Jul 19, 2023
341698a
Fixed export hash for skeletons
bsekachev Jul 19, 2023
6ca5ffd
Merge branch 'develop' into bs/fixed_hash
bsekachev Jul 19, 2023
e9ab310
fix
azhavoro Jul 19, 2023
dbb962a
linter
azhavoro Jul 19, 2023
e87d3c3
Merge remote-tracking branch 'origin' into az/annotation_analytics
azhavoro Jul 20, 2023
29340b6
Merge branch 'bs/fixed_hash' into az/annotation_analytics
azhavoro Jul 20, 2023
215798b
v9.3.0
azhavoro Jul 20, 2023
458b446
v1.54.0
azhavoro Jul 20, 2023
43538b2
update changelog
azhavoro Jul 20, 2023
b77e179
Merge branch 'develop' into az/annotation_analytics
azhavoro Jul 20, 2023
9202238
apply comments
azhavoro Jul 20, 2023
a3c9038
Merge branch 'az/annotation_analytics' of github.com:opencv/cvat into…
azhavoro Jul 20, 2023
e92b7e9
Merge branch 'develop' into az/annotation_analytics
azhavoro Jul 20, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/black.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jobs:
cvat-cli/**/*.py
tests/python/**/*.py
cvat/apps/quality_control/**/*.py
cvat/apps/analytics_report/**/*.py
dir_names: true

- name: Run checks
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/isort.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jobs:
cvat-cli/**/*.py
tests/python/**/*.py
cvat/apps/quality_control/**/*.py
cvat/apps/analytics_report/**/*.py
dir_names: true

- name: Run checks
Expand Down
6 changes: 4 additions & 2 deletions .stylelintrc.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"extends": "stylelint-config-standard",
"extends": "stylelint-config-standard-scss",
"rules": {
"indentation": 4,
"value-keyword-case": null,
Expand All @@ -16,7 +16,9 @@
{
"ignoreTypes": ["first-child"]
}
]
],
"scss/comment-no-empty": null,
"scss/at-extend-no-missing-placeholder": null
},
"ignoreFiles": ["**/*.js", "**/*.ts", "**/*.py"]
}
43 changes: 43 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,26 @@
],
"justMyCode": false,
},
{
"name": "REST API tests: Attach to RQ analytics reports worker",
"type": "python",
"request": "attach",
"connect": {
"host": "127.0.0.1",
"port": 9095
},
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "/home/django/"
},
{
"localRoot": "${workspaceFolder}/.env",
"remoteRoot": "/opt/venv",
}
],
"justMyCode": false,
},
{
"type": "pwa-chrome",
"request": "launch",
Expand Down Expand Up @@ -240,6 +260,28 @@
},
"console": "internalConsole"
},
{
"name": "server: RQ - analytics reports",
"type": "python",
"request": "launch",
"stopOnEntry": false,
"justMyCode": false,
"python": "${command:python.interpreterPath}",
"program": "${workspaceRoot}/manage.py",
"args": [
"rqworker",
"analytics_reports",
"--worker-class",
"cvat.rqworker.SimpleWorker",
],
"django": true,
"cwd": "${workspaceFolder}",
"env": {
"DJANGO_LOG_SERVER_HOST": "localhost",
"DJANGO_LOG_SERVER_PORT": "8282"
},
"console": "internalConsole"
},
{
"name": "server: RQ - scheduler",
"type": "python",
Expand Down Expand Up @@ -499,6 +541,7 @@
"server: RQ - webhooks",
"server: RQ - scheduler",
"server: RQ - quality reports",
"server: RQ - analytics reports",
"server: RQ - cleaning",
"server: git",
]
Expand Down
2 changes: 1 addition & 1 deletion cvat-canvas/src/typescript/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export interface DrawnState {
occluded?: boolean;
hidden?: boolean;
lock: boolean;
source: 'AUTO' | 'SEMI-AUTO' | 'MANUAL';
source: 'AUTO' | 'SEMI-AUTO' | 'MANUAL' | 'FILE';
bsekachev marked this conversation as resolved.
Show resolved Hide resolved
shapeType: string;
points?: number[];
rotation: number;
Expand Down
183 changes: 183 additions & 0 deletions cvat-core/src/analytics-report.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
// Copyright (C) 2023 CVAT.ai Corporation
//
// SPDX-License-Identifier: MIT

import { ArgumentError } from './exceptions';

export interface SerializedDataEntry {
date?: string;
value?: number | Record<string, number>
}

export interface SerializedTransformBinaryOp {
left: string;
operator: string;
right: string;
}

export interface SerializedTransformationEntry {
name: string;
binary?: SerializedTransformBinaryOp;
}

export interface SerializedAnalyticsEntry {
name?: string;
title?: string;
description?: string;
granularity?: string;
default_view?: string;
data_series?: Record<string, SerializedDataEntry[]>;
transformations?: SerializedTransformationEntry[];
}

export interface SerializedAnalyticsReport {
id?: number;
target?: string;
created_date?: string;
statistics?: SerializedAnalyticsEntry[];
}

export enum AnalyticsReportTarget {
JOB = 'job',
TASK = 'task',
PROJECT = 'project',
}

export enum AnalyticsEntryViewType {
HISTOGRAM = 'histogram',
NUMERIC = 'numeric',
}

export class AnalyticsEntry {
#name: string;
#title: string;
#description: string;
#granularity: string;
#defaultView: AnalyticsEntryViewType;
#dataSeries: Record<string, SerializedDataEntry[]>;
#transformations: SerializedTransformationEntry[];

constructor(initialData: SerializedAnalyticsEntry) {
this.#name = initialData.name;
this.#title = initialData.title;
this.#description = initialData.description;
this.#granularity = initialData.granularity;
this.#defaultView = initialData.default_view as AnalyticsEntryViewType;
this.#transformations = initialData.transformations;
this.#dataSeries = this.applyTransformations(initialData.data_series);
}

get name(): string {
return this.#name;
}

get title(): string {
return this.#title;
}

get description(): string {
return this.#description;
}

// Probably need to create enum for this
get granularity(): string {
return this.#granularity;
}

get defaultView(): AnalyticsEntryViewType {
return this.#defaultView;
}

get dataSeries(): Record<string, SerializedDataEntry[]> {
return this.#dataSeries;
}

get transformations(): SerializedTransformationEntry[] {
return this.#transformations;
}

private applyTransformations(
dataSeries: Record<string, SerializedDataEntry[]>,
): Record<string, SerializedDataEntry[]> {
this.#transformations.forEach((transform) => {
if (transform.binary) {
let operator: (left: number, right: number) => number;
switch (transform.binary.operator) {
case '+': {
operator = (left: number, right: number) => left + right;
break;
}
case '-': {
operator = (left: number, right: number) => left - right;
break;
}
case '*': {
operator = (left: number, right: number) => left * right;
break;
}
case '/': {
operator = (left: number, right: number) => (right !== 0 ? left / right : 0);
break;
}
default: {
throw new ArgumentError(
`Cannot apply transformation: got unsupported operator type ${transform.binary.operator}.`,
);
}
}

const leftName = transform.binary.left;
const rightName = transform.binary.right;
dataSeries[transform.name] = dataSeries[leftName].map((left, i) => {
const right = dataSeries[rightName][i];
if (typeof left.value === 'number' && typeof right.value === 'number') {
return {
value: operator(left.value, right.value),
date: left.date,
};
}
return {
value: 0,
date: left.date,
};
});
delete dataSeries[leftName];
delete dataSeries[rightName];
}
});
return dataSeries;
}
}

export default class AnalyticsReport {
#id: number;
#target: AnalyticsReportTarget;
#createdDate: string;
#statistics: AnalyticsEntry[];

constructor(initialData: SerializedAnalyticsReport) {
this.#id = initialData.id;
this.#target = initialData.target as AnalyticsReportTarget;
this.#createdDate = initialData.created_date;
this.#statistics = [];
for (const analyticsEntry of initialData.statistics) {
this.#statistics.push(new AnalyticsEntry(analyticsEntry));
}
}

get id(): number {
return this.#id;
}

get target(): AnalyticsReportTarget {
return this.#target;
}

get createdDate(): string {
return this.#createdDate;
}

get statistics(): AnalyticsEntry[] {
return this.#statistics;
}
}
34 changes: 34 additions & 0 deletions cvat-core/src/api-implementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import QualityReport from './quality-report';
import QualityConflict from './quality-conflict';
import QualitySettings from './quality-settings';
import { FramesMetaData } from './frames';
import AnalyticsReport from './analytics-report';

export default function implementAPI(cvat) {
cvat.plugins.list.implementation = PluginRegistry.list;
Expand Down Expand Up @@ -404,5 +405,38 @@ export default function implementAPI(cvat) {
return new FramesMetaData({ ...result });
};

cvat.analytics.performance.reports.implementation = async (filter) => {
checkFilter(filter, {
jobID: isInteger,
taskID: isInteger,
projectID: isInteger,
startDate: isString,
endDate: isString,
});

checkExclusiveFields(filter, ['jobID', 'taskID', 'projectID'], ['startDate', 'endDate']);

const updatedParams: Record<string, string> = {};

if ('taskID' in filter) {
azhavoro marked this conversation as resolved.
Show resolved Hide resolved
updatedParams.task_id = filter.taskID;
}
if ('jobID' in filter) {
updatedParams.job_id = filter.jobID;
}
if ('projectID' in filter) {
updatedParams.project_id = filter.projectID;
}
if ('startDate' in filter) {
updatedParams.start_date = filter.startDate;
}
if ('endDate' in filter) {
updatedParams.end_date = filter.endDate;
}

const reportData = await serverProxy.analytics.performance.reports(updatedParams);
return new AnalyticsReport(reportData);
};

return cvat;
}
6 changes: 6 additions & 0 deletions cvat-core/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,12 @@ function build() {
},
},
analytics: {
performance: {
async reports(filter = {}) {
const result = await PluginRegistry.apiWrapper(cvat.analytics.performance.reports, filter);
return result;
},
},
quality: {
async reports(filter: any) {
const result = await PluginRegistry.apiWrapper(cvat.analytics.quality.reports, filter);
Expand Down
1 change: 1 addition & 0 deletions cvat-core/src/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export enum Source {
MANUAL = 'manual',
SEMI_AUTO = 'semi-auto',
AUTO = 'auto',
FILE = 'file',
}

export enum LogType {
Expand Down
2 changes: 1 addition & 1 deletion cvat-core/src/object-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ export default class ObjectState {
}),
);

if ([Source.MANUAL, Source.SEMI_AUTO, Source.AUTO].includes(serialized.source)) {
if ([Source.MANUAL, Source.SEMI_AUTO, Source.AUTO, Source.FILE].includes(serialized.source)) {
data.source = serialized.source;
}
if (typeof serialized.zOrder === 'number') {
Expand Down
Loading