Browse Source

Enable to show relation distribution

pull/1703/head
Hironsan 2 years ago
parent
commit
d0e49f7586
9 changed files with 76 additions and 6 deletions
  1. 15
      backend/labels/managers.py
  2. 9
      backend/labels/models.py
  3. 2
      backend/metrics/urls.py
  4. 9
      backend/metrics/views.py
  5. 31
      frontend/components/metrics/RelationDistribution.vue
  6. 1
      frontend/domain/models/metrics/metricsRepository.ts
  7. 5
      frontend/pages/projects/_id/metrics/index.vue
  8. 6
      frontend/repositories/metrics/apiMetricsRepository.ts
  9. 4
      frontend/services/application/metrics/metricsApplicationService.ts

15
backend/labels/managers.py

@ -2,6 +2,8 @@ from django.db.models import Count, Manager
class LabelManager(Manager):
label_type_field = "label"
def calc_label_distribution(self, examples, members, labels):
"""Calculate label distribution.
@ -20,12 +22,12 @@ class LabelManager(Manager):
distribution = {member.username: {label.text: 0 for label in labels} for member in members}
items = (
self.filter(example_id__in=examples)
.values("user__username", "label__text")
.annotate(count=Count("label__text"))
.values("user__username", f"{self.label_type_field}__text")
.annotate(count=Count(f"{self.label_type_field}__text"))
)
for item in items:
username = item["user__username"]
label = item["label__text"]
label = item[f"{self.label_type_field}__text"]
count = item["count"]
distribution[username][label] = count
return distribution
@ -72,3 +74,10 @@ class TextLabelManager(LabelManager):
if text.is_same_text(label):
return False
return True
class RelationManager(LabelManager):
label_type_field = "type"
def can_annotate(self, label, project) -> bool:
return True

9
backend/labels/models.py

@ -2,7 +2,13 @@ from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.db import models
from .managers import CategoryManager, LabelManager, SpanManager, TextLabelManager
from .managers import (
CategoryManager,
LabelManager,
RelationManager,
SpanManager,
TextLabelManager,
)
from examples.models import Example
from label_types.models import CategoryType, RelationType, SpanType
@ -91,6 +97,7 @@ class TextLabel(Label):
class Relation(Label):
objects = RelationManager()
from_id = models.ForeignKey(Span, on_delete=models.CASCADE, related_name="from_relations")
to_id = models.ForeignKey(Span, on_delete=models.CASCADE, related_name="to_relations")
type = models.ForeignKey(RelationType, on_delete=models.CASCADE)

2
backend/metrics/urls.py

@ -4,6 +4,7 @@ from .views import (
CategoryTypeDistribution,
MemberProgressAPI,
ProgressAPI,
RelationTypeDistribution,
SpanTypeDistribution,
)
@ -11,5 +12,6 @@ urlpatterns = [
path(route="progress", view=ProgressAPI.as_view(), name="progress"),
path(route="member-progress", view=MemberProgressAPI.as_view(), name="member_progress"),
path(route="category-distribution", view=CategoryTypeDistribution.as_view(), name="category_distribution"),
path(route="relation-distribution", view=RelationTypeDistribution.as_view(), name="relation_distribution"),
path(route="span-distribution", view=SpanTypeDistribution.as_view(), name="span_distribution"),
]

9
backend/metrics/views.py

@ -6,8 +6,8 @@ from rest_framework.response import Response
from rest_framework.views import APIView
from examples.models import Example, ExampleState
from label_types.models import CategoryType, LabelType, SpanType
from labels.models import Category, Label, Span
from label_types.models import CategoryType, LabelType, RelationType, SpanType
from labels.models import Category, Label, Relation, Span
from projects.models import Member
from projects.permissions import IsProjectAdmin, IsProjectStaffAndReadOnly
@ -54,3 +54,8 @@ class CategoryTypeDistribution(LabelDistribution):
class SpanTypeDistribution(LabelDistribution):
model = Span
label_type = SpanType
class RelationTypeDistribution(LabelDistribution):
model = Relation
label_type = RelationType

31
frontend/components/metrics/RelationDistribution.vue

@ -0,0 +1,31 @@
<template>
<label-distribution
title="Relation Distribution"
:distribution="distribution"
:color-mapping="colorMapping"
/>
</template>
<script lang="ts">
import Vue from 'vue'
import LabelDistribution from './LabelDistribution.vue'
export default Vue.extend({
components: {
LabelDistribution
},
data() {
return {
distribution: {},
colorMapping: {},
}
},
async created() {
this.distribution = await this.$services.metrics.fetchRelationDistribution(this.$route.params.id)
const labels = await this.$services.relationType.list(this.$route.params.id)
this.colorMapping = Object.fromEntries(labels.map((label) => [label.text, label.backgroundColor]))
}
})
</script>

1
frontend/domain/models/metrics/metricsRepository.ts

@ -3,6 +3,7 @@ import { Distribution, Progress, MyProgress } from '~/domain/models/metrics/metr
export interface MetricsRepository {
fetchCategoryDistribution(projectId: string): Promise<Distribution>
fetchSpanDistribution(projectId: string): Promise<Distribution>
fetchRelationDistribution(projectId: string): Promise<Distribution>
fetchMemberProgress(projectId: string): Promise<Progress>
fetchMyProgress(projectId: string): Promise<MyProgress>
}

5
frontend/pages/projects/_id/metrics/index.vue

@ -9,17 +9,22 @@
<v-col v-if="!!project.hasSpan" cols="12">
<span-distribution />
</v-col>
<v-col v-if="!!project.useRelation" cols="12">
<relation-distribution />
</v-col>
</v-row>
</template>
<script>
import CategoryDistribution from '~/components/metrics/CategoryDistribution'
import RelationDistribution from '~/components/metrics/RelationDistribution'
import SpanDistribution from '~/components/metrics/SpanDistribution'
import MemberProgress from '~/components/metrics/MemberProgress'
export default {
components: {
CategoryDistribution,
RelationDistribution,
SpanDistribution,
MemberProgress
},

6
frontend/repositories/metrics/apiMetricsRepository.ts

@ -19,6 +19,12 @@ export class APIMetricsRepository implements MetricsRepository {
return response.data
}
async fetchRelationDistribution(projectId: string): Promise<Distribution> {
const url = `/projects/${projectId}/metrics/relation-distribution`
const response = await this.request.get(url)
return response.data
}
async fetchMemberProgress(projectId: string): Promise<Progress> {
const url = `/projects/${projectId}/metrics/member-progress`
const response = await this.request.get(url)

4
frontend/services/application/metrics/metricsApplicationService.ts

@ -18,6 +18,10 @@ export class MetricsApplicationService {
return await this.repository.fetchSpanDistribution(projectId)
}
public async fetchRelationDistribution(projectId: string): Promise<Distribution> {
return await this.repository.fetchRelationDistribution(projectId)
}
public async fetchMyProgress(projectId: string): Promise<MyProgress> {
return await this.repository.fetchMyProgress(projectId)
}

Loading…
Cancel
Save