Skip to content

Commit cd33bde

Browse files
authored
Merge pull request #74 from NGO-Algorithm-Audit/feature/updates-may-2025-udb-2
Feature/updates may 2025 udb 2
2 parents 68281f6 + 2fe5ac2 commit cd33bde

File tree

4 files changed

+149
-9
lines changed

4 files changed

+149
-9
lines changed

src/components/BiasSettings.tsx

Lines changed: 99 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
TooltipContent,
2828
} from './ui/touch-tooltip';
2929
import Markdown from 'react-markdown';
30+
import { IconInfoTooltip } from './ui/info-icon-tooltip';
3031

3132
const FormSchema = z.object({
3233
file: z.string({
@@ -43,6 +44,11 @@ const FormSchema = z.object({
4344
required_error: 'biasSettings.form.errors.dataTypeRequired',
4445
})
4546
.nonempty(),
47+
selectedDataType: z
48+
.string({
49+
required_error: 'biasSettings.form.errors.dataTypeRequired',
50+
})
51+
.nonempty(),
4652
});
4753

4854
export default function BiasSettings({
@@ -71,6 +77,7 @@ export default function BiasSettings({
7177

7278
const [performanceMetricColumnError, setPerformanceMetricColumnError] =
7379
useState<string | null>(null);
80+
const [dataTypeError, setDataTypeError] = useState<string | null>(null);
7481

7582
const [dataKey, setDataKey] = useState<string>(new Date().toISOString());
7683
const [data, setData] = useState<{
@@ -87,7 +94,7 @@ export default function BiasSettings({
8794
const isReset = stringified.length === 0;
8895
if (isReset) {
8996
form.reset();
90-
//setDefaultDataType('numeric');
97+
setDataTypeError(null);
9198
} else {
9299
form.setValue('file', stringified);
93100
}
@@ -97,6 +104,7 @@ export default function BiasSettings({
97104
setClusters([Math.round(dataLength / 4)]);
98105

99106
setPerformanceMetricColumnError(null);
107+
setDataTypeError(null);
100108
if (!isReset) {
101109
// Find numeric columns
102110
const numericColumns = Object.keys(data[0] || {})
@@ -115,10 +123,8 @@ export default function BiasSettings({
115123

116124
if (numericColumns.length === Object.keys(data[0] || {}).length) {
117125
form.setValue('dataType', 'numeric');
118-
//setDefaultDataType('numeric');
119126
} else {
120127
form.setValue('dataType', 'categorical');
121-
//setDefaultDataType('categorical');
122128
}
123129
}
124130

@@ -141,14 +147,30 @@ export default function BiasSettings({
141147
);
142148
};
143149

144-
const onSubmit = (data: z.infer<typeof FormSchema>) => {
150+
const onSubmit = (formData: z.infer<typeof FormSchema>) => {
151+
// Check if data type matches the actual data
152+
153+
const isNumericData = formData.dataType === 'numeric';
154+
155+
if (formData.selectedDataType === 'numeric' && !isNumericData) {
156+
setDataTypeError(t('biasSettings.form.errors.numericDataRequired'));
157+
return;
158+
}
159+
160+
if (formData.dataType === 'categorical' && isNumericData) {
161+
setDataTypeError(
162+
t('biasSettings.form.errors.categoricalDataRequired')
163+
);
164+
return;
165+
}
166+
145167
onRun({
146168
clusterSize: clusters[0],
147169
iterations: iter[0],
148-
targetColumn: data.targetColumn,
149-
dataType: data.dataType,
170+
targetColumn: formData.targetColumn,
171+
dataType: formData.dataType,
150172
higherIsBetter:
151-
data.whichPerformanceMetricValueIsBetter === 'higher',
173+
formData.whichPerformanceMetricValueIsBetter === 'higher',
152174
isDemo: false,
153175
});
154176
};
@@ -165,8 +187,14 @@ export default function BiasSettings({
165187
{t('biasSettings.form.fieldsets.data.title')}
166188
</legend>
167189
<div className="relative grid gap-3 select-none">
168-
<div className="absolute -top-[10px] leading-0 left-4 px-1 bg-white text-sm font-medium">
190+
<div className="flex flex-row items-center gap-1 absolute -top-[10px] leading-0 left-4 px-1 bg-white text-sm font-medium">
169191
{t('biasSettings.form.fieldsets.data.dataSet')}
192+
193+
<IconInfoTooltip
194+
tooltipText={t(
195+
'biasSettings.form.fieldsets.data.dataSetTooltip'
196+
)}
197+
/>
170198
</div>
171199
<FormField
172200
control={form.control}
@@ -252,6 +280,63 @@ export default function BiasSettings({
252280
)}
253281
/>
254282
</div>
283+
<div className="grid gap-3">
284+
<FormField
285+
control={form.control}
286+
name="selectedDataType"
287+
disabled={isLoading}
288+
render={({ field }) => (
289+
<FormItem>
290+
<FormLabel>
291+
{t(
292+
'biasSettings.form.fieldsets.data.dataType'
293+
)}
294+
</FormLabel>
295+
<RadioGroup
296+
onValueChange={value => {
297+
setDataTypeError(null);
298+
field.onChange(value);
299+
}}
300+
defaultValue={field.value}
301+
key={`${dataKey}_selecteddataType`}
302+
className="flex flex-col space-y-1"
303+
>
304+
<FormItem className="flex items-center space-x-3 space-y-0">
305+
<FormControl>
306+
<RadioGroupItem
307+
value="categorical"
308+
disabled={isLoading}
309+
/>
310+
</FormControl>
311+
<FormLabel className="font-normal">
312+
{t(
313+
'biasSettings.form.fieldsets.data.categoricalData'
314+
)}
315+
</FormLabel>
316+
</FormItem>
317+
<FormItem className="flex items-center space-x-3 space-y-0">
318+
<FormControl>
319+
<RadioGroupItem
320+
value="numeric"
321+
disabled={isLoading}
322+
/>
323+
</FormControl>
324+
<FormLabel className="font-normal">
325+
{t(
326+
'biasSettings.form.fieldsets.data.numericalData'
327+
)}
328+
</FormLabel>
329+
</FormItem>
330+
</RadioGroup>
331+
{dataTypeError && (
332+
<div className="text-red-500 text-sm mt-1">
333+
{dataTypeError}
334+
</div>
335+
)}
336+
</FormItem>
337+
)}
338+
/>
339+
</div>
255340
</fieldset>
256341

257342
<fieldset className="grid gap-6 rounded-lg border p-4">
@@ -342,10 +427,15 @@ export default function BiasSettings({
342427
/>
343428
</div>
344429
<div className="flex flex-col gap-3">
345-
<label className="text-sm font-medium">
430+
<label className="flex flex-row gap-1 items-center text-sm font-medium">
346431
{t(
347432
'biasSettings.form.fieldsets.parameters.performanceInterpretation.title'
348433
)}
434+
<IconInfoTooltip
435+
tooltipText={t(
436+
'biasSettings.form.fieldsets.parameters.performanceInterpretation.tooltip'
437+
)}
438+
/>
349439
</label>
350440
<FormField
351441
control={form.control}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { InfoIcon } from 'lucide-react';
2+
import {
3+
Tooltip,
4+
TooltipContent,
5+
TooltipProvider,
6+
TooltipTrigger,
7+
} from './touch-tooltip';
8+
import Markdown from 'react-markdown';
9+
10+
export const IconInfoTooltip = ({ tooltipText }: { tooltipText: string }) => {
11+
return (
12+
<TooltipProvider>
13+
<Tooltip>
14+
<TooltipTrigger
15+
onClick={event => {
16+
event.preventDefault();
17+
}}
18+
>
19+
<InfoIcon className="size-3.5" />
20+
</TooltipTrigger>
21+
<TooltipContent>
22+
<div className="whitespace-pre-wrap max-w-full w-[400px] p-2">
23+
<Markdown className="-mt-2 text-gray-800 markdown">
24+
{tooltipText}
25+
</Markdown>
26+
</div>
27+
</TooltipContent>
28+
</Tooltip>
29+
</TooltipProvider>
30+
);
31+
};

src/locales/en.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ export const en = {
2828
data: {
2929
title: 'Data',
3030
dataSet: 'Dataset',
31+
dataSetTooltip: `Your data should be prepared as follows: ...`,
3132
performanceMetric: 'Bias metric',
33+
dataType: 'Type of data',
34+
categoricalData: 'Categorical data',
35+
numericalData: 'Numerical data',
3236
},
3337
parameters: {
3438
title: 'Parameters',
@@ -38,6 +42,7 @@ export const en = {
3842
title: 'Bias metric interpretation',
3943
lower: 'Lower value of bias metric is better, e.g., error rate',
4044
higher: 'Higher value of bias metric is better, e.g., accuracy',
45+
tooltip: 'Clustering will be based on the bias metrics',
4146
},
4247
iterationsTooltip:
4348
'Number of times the dataset is split in smaller clusters until the minimal cluster size is reached',
@@ -53,6 +58,10 @@ export const en = {
5358
'No numeric columns found. Please upload a valid dataset.',
5459
analysisError: 'Error while analysing',
5560
noData: 'No data loaded',
61+
numericDataRequired:
62+
'Selected column must contain numerical data for k-means clustering.',
63+
categoricalDataRequired:
64+
'Selected column must contain categorical data for k-modes clustering.',
5665
},
5766
actions: {
5867
tryItOut: 'Demo dataset',

src/locales/nl.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ export const nl = {
2626
data: {
2727
title: 'Data',
2828
dataSet: 'Dataset',
29+
dataSetTooltip: `Data wordt als volgt behandeld: ...`,
2930
performanceMetric: 'Gelijkheidsmetriek',
31+
dataType: 'Type data',
32+
categoricalData: 'Categorische data',
33+
numericalData: 'Numerieke data',
3034
},
3135
parameters: {
3236
title: 'Parameters',
@@ -36,6 +40,8 @@ export const nl = {
3640
title: 'Interpretatie van gelijkheidsmetriek',
3741
lower: 'Lagere waarde van gelijkheidsmetriek is beter, bijv. foutpercentage',
3842
higher: 'Hogere waarde van gelijkheidsmetriek is beter, bijv. nauwkeurigheid',
43+
tooltip:
44+
'Clustering is gebaseerd op de gelijkheidsmetriek.',
3945
},
4046
iterationsTooltip:
4147
'Aantal keren dat de dataset wordt opgesplitst in kleinere clusters totdat de minimale clustergrootte is bereikt.',
@@ -51,6 +57,10 @@ export const nl = {
5157
'Geen numerieke kolommen gevonden. Upload een geldige dataset.',
5258
analysisError: 'Fout tijdens analyse',
5359
noData: 'Geen gegevens geladen',
60+
numericDataRequired:
61+
'Geselecteerde kolom moet numerieke data bevatten voor k-means clustering.',
62+
categoricalDataRequired:
63+
'Geselecteerde kolom moet categorische data bevatten voor k-modes clustering.',
5464
},
5565
actions: {
5666
tryItOut: 'Demo dataset',

0 commit comments

Comments
 (0)