Skip to content
This repository was archived by the owner on Mar 8, 2024. It is now read-only.

Commit 2f91186

Browse files
authored
adds confidence distribution chart (#60)
* adds confidence distribution chart * added suggestions * displays confidence chart as record-wise below 100 samples
1 parent 5d5bb1b commit 2f91186

15 files changed

+266
-4
lines changed

src/app/base/services/project/project-apollo.service.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,24 @@ export class ProjectApolloService {
199199
);
200200
}
201201

202+
getConfidenceDistributions(projectId: string, labelingTaskId: string = null, sliceId: string = null) {
203+
return this.apollo
204+
.query({
205+
query: queries.GET_CONFIDENCE_DISTRIBUTION,
206+
variables: {
207+
projectId: projectId,
208+
labelingTaskId: labelingTaskId,
209+
sliceId: sliceId,
210+
},
211+
fetchPolicy: 'no-cache',
212+
})
213+
.pipe(
214+
map((result) => {
215+
return JSON.parse(result['data']['confidenceDistribution']);
216+
})
217+
);
218+
}
219+
202220
getProjectByIdQuery(
203221
projectId: string
204222
) {

src/app/base/services/project/project-queries.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@ export const queries = {
119119
}
120120
`,
121121

122+
GET_CONFIDENCE_DISTRIBUTION: gql`
123+
query ($projectId: ID!, $labelingTaskId: ID, $sliceId: ID) {
124+
confidenceDistribution(projectId: $projectId, labelingTaskId: $labelingTaskId, sliceId: $sliceId)
125+
}
126+
`,
127+
122128
GET_ATTRIBUTES_BY_PROJECT_ID: gql`
123129
query($projectId: ID!){
124130
attributesByProjectId(projectId: $projectId) {

src/app/charts/charts.module.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,23 @@ import { BarChartComponent } from './components/bar-chart/bar-chart.component';
66
import { HorizontalGroupedBarChartComponent } from './components/horizontal-grouped-bar-chart/horizontal-grouped-bar-chart.component';
77
import { BoxplotComponent } from './components/boxplot/boxplot.component';
88
import { ConfusionMatrixComponent } from './components/confusion-matrix/confusion-matrix.component';
9+
import { LineChartComponent } from './components/line-chart/line-chart.component';
910

1011

1112

1213
@NgModule({
13-
declarations: [GroupedBarChartComponent, BarChartComponent, HorizontalGroupedBarChartComponent, BoxplotComponent, ConfusionMatrixComponent],
14+
declarations: [LineChartComponent, GroupedBarChartComponent, BarChartComponent, HorizontalGroupedBarChartComponent, BoxplotComponent, ConfusionMatrixComponent],
1415
imports: [
1516
CommonModule,
1617
AppRoutingModule
1718
],
1819
exports: [
20+
LineChartComponent,
1921
GroupedBarChartComponent,
2022
BarChartComponent,
2123
HorizontalGroupedBarChartComponent,
2224
BoxplotComponent,
23-
ConfusionMatrixComponent
25+
ConfusionMatrixComponent,
2426
]
2527
})
2628
export class ChartsModule { }
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<div class="lineChartTooltip"></div>
2+
<div id="line-chart" class="container" width="100%"></div>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.lineChartTooltip {
2+
position: absolute;
3+
display: none;
4+
width: auto;
5+
height: auto;
6+
background: #F3F4F6;
7+
border: 0 none;
8+
border-radius: 4px;
9+
color: #0C052E;
10+
font: 14px sans-serif;
11+
padding: 5px;
12+
text-align: center;
13+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { LineChartComponent } from './line-chart.component';
4+
5+
describe('LineChartComponent', () => {
6+
let component: LineChartComponent;
7+
let fixture: ComponentFixture<LineChartComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
declarations: [LineChartComponent]
12+
})
13+
.compileComponents();
14+
});
15+
16+
beforeEach(() => {
17+
fixture = TestBed.createComponent(LineChartComponent);
18+
component = fixture.componentInstance;
19+
fixture.detectChanges();
20+
});
21+
22+
it('should create', () => {
23+
expect(component).toBeTruthy();
24+
});
25+
});
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import { Component, Input, OnChanges, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core';
2+
import { fromEvent, Observable, Subscription } from "rxjs";
3+
4+
import * as d3 from 'd3v4';
5+
6+
@Component({
7+
selector: 'kern-line-chart',
8+
encapsulation: ViewEncapsulation.None,
9+
templateUrl: './line-chart.component.html',
10+
styleUrls: ['./line-chart.component.scss'],
11+
})
12+
export class LineChartComponent implements OnInit, OnChanges {
13+
@Input() data: any;
14+
15+
resizeObservable$: Observable<Event>
16+
resizeSubscription$: Subscription
17+
18+
constructor() { }
19+
20+
ngOnInit(): void {
21+
this.resizeObservable$ = fromEvent(window, 'resize')
22+
this.resizeSubscription$ = this.resizeObservable$.subscribe(evt => {
23+
this.initSVG(this.data);
24+
})
25+
}
26+
27+
28+
ngOnChanges(changes: SimpleChanges): void {
29+
this.initSVG(this.data);
30+
}
31+
32+
initSVG(data_) {
33+
34+
let data = []
35+
for (var i = 0; i < data_.length; i++) {
36+
data.push({ idx: i, value: data_[i] * 100 });
37+
}
38+
39+
// set the dimensions and margins of the graph
40+
var margin = { top: 40, right: 20, bottom: 40, left: 50 },
41+
width = +(window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) * 0.78 + margin.left + margin.right,
42+
height = 450 - margin.top - margin.bottom;
43+
44+
d3.select("#line-chart").selectAll("*").remove();
45+
46+
// append the svg object to the body of the page
47+
var svg = d3.select("#line-chart")
48+
.append("svg")
49+
.attr("width", width + margin.left + margin.right)
50+
.attr("height", height + margin.top + margin.bottom)
51+
.append("g")
52+
.attr("transform",
53+
"translate(" + margin.left + "," + margin.top + ")");
54+
55+
// Add X axis
56+
var x = d3.scaleLinear()
57+
.domain(d3.extent(data, function (d) { return d.idx; }))
58+
.range([0, width]);
59+
60+
61+
// Add Y axis
62+
var y = d3.scaleLinear()
63+
.domain([0, d3.max(data, function (d) { return +d.value; })])
64+
.range([height, 0]);
65+
66+
67+
// Add the area
68+
svg.append("path")
69+
.datum(data)
70+
.attr("fill", "#bbf7d0")
71+
.attr("stroke", "#22c55e")
72+
.attr("stroke-width", 1.5)
73+
.attr("d", d3.area()
74+
.x(function (d) { return x(d.idx) })
75+
.y0(y(0))
76+
.y1(function (d) { return y(d.value) })
77+
)
78+
79+
svg.append("g")
80+
.style("font-size", 14)
81+
.style('font-family', '"DM Sans", sans-serif')
82+
.call(d3.axisLeft(y))
83+
.append("text")
84+
.attr("x", 0)
85+
.attr("dy", 15)
86+
.attr("fill", "#000")
87+
.attr("text-anchor", "end")
88+
.attr("transform", "rotate(-90)")
89+
.text("Confidence score (%)");
90+
91+
if (data.length >= 100) {
92+
svg.append("g")
93+
.attr("transform", "translate(0," + height + ")")
94+
.style("font-size", 14)
95+
.style('font-family', '"DM Sans", sans-serif')
96+
.call(d3.axisBottom(x))
97+
.append("text")
98+
.attr("y", -5)
99+
.attr("dx", width)
100+
.attr("fill", "#000")
101+
.attr("text-anchor", "end")
102+
.text("Percentile (%)");
103+
} else {
104+
svg.append("g")
105+
.attr("transform", "translate(0," + height + ")")
106+
.style("font-size", 14)
107+
.style('font-family', '"DM Sans", sans-serif')
108+
.call(d3.axisBottom(x))
109+
.append("text")
110+
.attr("y", -5)
111+
.attr("dx", width)
112+
.attr("fill", "#000")
113+
.attr("text-anchor", "end")
114+
.text("Record");
115+
}
116+
117+
};
118+
119+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<kern-line-chart [data]="dataInput">
2+
</kern-line-chart>

src/app/monitor/components/confidence-line-chart/confidence-line-chart.component.scss

Whitespace-only changes.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { ConfidenceLineChartComponent } from './confidence-line-chart.component';
4+
5+
describe('ConfidenceLineChartComponent', () => {
6+
let component: ConfidenceLineChartComponent;
7+
let fixture: ComponentFixture<ConfidenceLineChartComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
declarations: [ConfidenceLineChartComponent]
12+
})
13+
.compileComponents();
14+
});
15+
16+
beforeEach(() => {
17+
fixture = TestBed.createComponent(ConfidenceLineChartComponent);
18+
component = fixture.componentInstance;
19+
fixture.detectChanges();
20+
});
21+
22+
it('should create', () => {
23+
expect(component).toBeTruthy();
24+
});
25+
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Component, Input, OnInit } from '@angular/core';
2+
3+
@Component({
4+
selector: 'kern-confidence-line-chart',
5+
templateUrl: './confidence-line-chart.component.html',
6+
styleUrls: ['./confidence-line-chart.component.scss'],
7+
})
8+
export class ConfidenceLineChartComponent implements OnInit {
9+
constructor() { }
10+
@Input() dataInput: any;
11+
12+
ngOnInit(): void {
13+
}
14+
}

src/app/project-overview/components/project-overview/project-overview.component.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,22 @@
219219
</div>
220220
</div>
221221

222+
<div class="mt-8 w-2/4 grid w-full"
223+
[ngClass]="displayGraphsForm.value == DisplayGraphsType.ALL || displayGraphsForm.value == DisplayGraphsType.CONFIDENCE_DISTRIBUTION?null:'hidden'">
224+
<div class="text-lg leading-6 text-gray-900 font-medium inline-block">
225+
Confidence distribution
226+
</div>
227+
<div class="mt-1 text-sm leading-5 font-medium text-gray-700 inline-block">See the confidence distribution
228+
of your weakly supervised records.</div>
229+
<div class="mt-2 w-full h-full shadow stats bg-white grid place-items-center flex-grow">
230+
<div style="width:100%;height:100%;padding-left:20px;padding-right:20px;padding-top:20px;padding-bottom:20px;"
231+
*ngIf="lineChartData">
232+
<kern-confidence-line-chart [dataInput]="lineChartData">
233+
</kern-confidence-line-chart>
234+
</div>
235+
</div>
236+
</div>
237+
222238
<div class="mt-8 w-2/4 grid w-full"
223239
[ngClass]="displayGraphsForm.value == DisplayGraphsType.ALL || displayGraphsForm.value == DisplayGraphsType.CONFUSION_MATRIX?null:'hidden'">
224240
<div class="text-lg leading-6 text-gray-900 font-medium inline-block">

src/app/project-overview/components/project-overview/project-overview.component.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ export class ProjectOverviewComponent implements OnInit, OnDestroy {
3434
description: string = '';
3535
descriptionOpen: boolean = false;
3636

37+
lineChartData: any;
38+
3739
newLabel = new FormControl('');
3840
colors = schemeCategory24;
3941
downloadMessage: DownloadState = DownloadState.NONE;
@@ -113,6 +115,7 @@ export class ProjectOverviewComponent implements OnInit, OnDestroy {
113115
this.labels = this.labelingTasksMap.get(labelingTaskId).labels;
114116
this.setDisplayNERConfusion(currentProjectID, labelingTaskId);
115117
this.getLabelDistributions(currentProjectID, labelingTaskId);
118+
this.getConfidenceDistributions(currentProjectID, labelingTaskId);
116119
this.getConfusionMatrix(currentProjectID, labelingTaskId);
117120
this.getInterAnnotatorMatrix(currentProjectID, labelingTaskId);
118121
this.refreshProjectStats(currentProjectID);
@@ -121,6 +124,7 @@ export class ProjectOverviewComponent implements OnInit, OnDestroy {
121124

122125
this.dataSliceForm.valueChanges.pipe(debounceTime(50)).subscribe((sliceId) => {
123126
this.getLabelDistributions(currentProjectID, this.labelingTasksForm.value);
127+
this.getConfidenceDistributions(currentProjectID, this.labelingTasksForm.value);
124128
this.getConfusionMatrix(currentProjectID, this.labelingTasksForm.value);
125129
this.getInterAnnotatorMatrix(currentProjectID, this.labelingTasksForm.value);
126130
this.refreshProjectStats(currentProjectID);
@@ -313,6 +317,18 @@ export class ProjectOverviewComponent implements OnInit, OnDestroy {
313317
});
314318
}
315319

320+
getConfidenceDistributions(projectId: string, labelingTaskId: string): void {
321+
const dataSliceId = this.dataSliceForm.value == "@@NO_SLICE@@" ? null : this.dataSliceForm.value;
322+
this.labelDistribution = null;
323+
this.projectApolloService.getConfidenceDistributions(
324+
projectId,
325+
labelingTaskId,
326+
dataSliceId
327+
).pipe(first()).subscribe((confidenceDist) => {
328+
this.lineChartData = confidenceDist;
329+
});
330+
}
331+
316332
private matchAndMergeLabelDistributionData(data) {
317333
let returnData = [];
318334
data.forEach(e => {

src/app/project-overview/components/project-overview/project-overview.helper.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export enum DisplayGraphs {
55
CONFUSION_MATRIX,
66
INTER_ANNOTATOR,
77
LABEL_DISTRIBUTION,
8+
CONFIDENCE_DISTRIBUTION,
89
}
910

1011
export function displayGraphsTypeToString(source: DisplayGraphs) {
@@ -13,6 +14,7 @@ export function displayGraphsTypeToString(source: DisplayGraphs) {
1314
case DisplayGraphs.CONFUSION_MATRIX: return "Confusion Matrix";
1415
case DisplayGraphs.INTER_ANNOTATOR: return "Inter Annotator";
1516
case DisplayGraphs.LABEL_DISTRIBUTION: return "Label Distribution";
17+
case DisplayGraphs.CONFIDENCE_DISTRIBUTION: return "Confidence Distribution";
1618
default: return "";
1719
}
1820
}

src/app/project-overview/project-overview.module.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ import { ChartsModule } from '../charts/charts.module';
99
import { LabelDistributionBarChartComponent } from '../monitor/components/label-distribution-bar-chart/label-distribution-bar-chart.component';
1010
import { ConfusionHeatmapComponent } from '../monitor/components/confusion-heatmap/confusion-heatmap.component';
1111
import { InterAnnotatorComponent } from '../monitor/components/inter-annotator/inter-annotator.component';
12+
import { ConfidenceLineChartComponent } from '../monitor/components/confidence-line-chart/confidence-line-chart.component';
1213

1314
@NgModule({
14-
declarations: [ProjectOverviewComponent, LabelDistributionBarChartComponent, ConfusionHeatmapComponent, InterAnnotatorComponent],
15+
declarations: [ProjectOverviewComponent, LabelDistributionBarChartComponent, ConfusionHeatmapComponent, InterAnnotatorComponent, ConfidenceLineChartComponent],
1516
imports: [
1617
CommonModule,
1718
BaseModule,
1819
ImportModule,
19-
ChartsModule],
20+
ChartsModule
21+
],
2022
})
2123
export class ProjectOverviewModule { }

0 commit comments

Comments
 (0)