Skip to content

Commit 3642378

Browse files
committed
setup basics for synthetic data
1 parent b67b390 commit 3642378

File tree

5 files changed

+567
-1
lines changed

5 files changed

+567
-1
lines changed
Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
1+
import { Label } from '@/components/ui/label';
2+
import {
3+
Select,
4+
SelectContent,
5+
SelectItem,
6+
SelectTrigger,
7+
SelectValue,
8+
} from '@/components/ui/select';
9+
import { Slider } from '@/components/ui/slider';
10+
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
11+
12+
import CSVReader, { csvReader } from './CSVReader';
13+
import { useEffect, useState } from 'react';
14+
import { Button } from './ui/button';
15+
import { ArrowDown, ArrowRight } from 'lucide-react';
16+
import { z } from 'zod';
17+
import { useForm } from 'react-hook-form';
18+
import { zodResolver } from '@hookform/resolvers/zod';
19+
import { Form, FormControl, FormField, FormItem, FormLabel } from './ui/form';
20+
import { Card, CardDescription, CardHeader, CardTitle } from './ui/card';
21+
import Papa from 'papaparse';
22+
23+
const FormSchema = z.object({
24+
file: z.string({
25+
required_error: 'Please upload a CSV file.',
26+
}),
27+
whichPerformanceMetricValueIsBetter: z.string(),
28+
targetColumn: z
29+
.string({
30+
required_error: 'Please select a target column.',
31+
})
32+
.nonempty(),
33+
dataType: z
34+
.string({
35+
required_error: 'Please select a data type.',
36+
})
37+
.nonempty(),
38+
});
39+
40+
export default function BiasSettings({
41+
onRun,
42+
onDataLoad,
43+
isLoading,
44+
isErrorDuringAnalysis,
45+
isInitialised,
46+
}: {
47+
onRun: (
48+
clusterSize: number,
49+
iterations: number,
50+
targetColumn: string,
51+
dataType: string,
52+
higherIsBetter: boolean
53+
) => void;
54+
onDataLoad: csvReader['onChange'];
55+
isLoading: boolean;
56+
isErrorDuringAnalysis: boolean;
57+
isInitialised: boolean;
58+
}) {
59+
const form = useForm<z.infer<typeof FormSchema>>({
60+
resolver: zodResolver(FormSchema),
61+
defaultValues: {
62+
dataType: 'numeric',
63+
whichPerformanceMetricValueIsBetter: 'lower',
64+
},
65+
});
66+
const [iter, setIter] = useState([10]);
67+
const [clusters, setClusters] = useState([25]);
68+
69+
const [dataKey, setDataKey] = useState<string>(new Date().toISOString());
70+
const [data, setData] = useState<{
71+
data: Record<string, string>[];
72+
stringified: string;
73+
fileName: string;
74+
}>({ data: [], stringified: '', fileName: '' });
75+
76+
const onFileLoad = (
77+
data: Record<string, string>[],
78+
stringified: string,
79+
fileName: string
80+
) => {
81+
if (stringified.length === 0) {
82+
form.reset();
83+
} else {
84+
form.setValue('file', stringified);
85+
}
86+
setData({ data, stringified, fileName });
87+
88+
const dataLength = (data?.length || 1000) / 10;
89+
setClusters([Math.round(dataLength / 4)]);
90+
setDataKey(new Date().toISOString());
91+
};
92+
93+
useEffect(() => {
94+
onDataLoad(data.data, data.stringified, data.fileName);
95+
}, [data]);
96+
97+
const onDemoRun = async () => {
98+
const file = await fetch('/FP-test-set.csv')
99+
.then(response => response.text())
100+
.then(data => Papa.parse(data, { header: true }));
101+
onDataLoad(
102+
file.data as Record<string, string>[],
103+
Papa.unparse(file.data),
104+
'demo',
105+
true
106+
);
107+
};
108+
109+
const onSubmit = (data: z.infer<typeof FormSchema>) => {
110+
onRun(
111+
clusters[0],
112+
iter[0],
113+
data.targetColumn,
114+
data.dataType,
115+
data.whichPerformanceMetricValueIsBetter === 'higher'
116+
);
117+
};
118+
119+
return (
120+
<Form {...form}>
121+
<div className="h-auto md:h-full flex flex-col justify-between">
122+
<form
123+
onSubmit={form.handleSubmit(onSubmit)}
124+
className="grid w-full items-start gap-2 -mt-2 grid-cols-1 sm:gap-4 sm:grid-cols-2"
125+
>
126+
<fieldset className="grid gap-6 rounded-lg border p-4">
127+
<legend className="-ml-1 px-1 text-sm font-medium">
128+
Source Dataset
129+
</legend>
130+
<div className="grid gap-3">
131+
<FormField
132+
control={form.control}
133+
name="file"
134+
render={() => (
135+
<CSVReader onChange={onFileLoad} />
136+
)}
137+
/>
138+
</div>
139+
<div className="grid gap-3">
140+
<FormField
141+
control={form.control}
142+
name="targetColumn"
143+
render={({ field }) => (
144+
<FormItem>
145+
<FormLabel>
146+
Performance metric column
147+
</FormLabel>
148+
<Select
149+
onValueChange={field.onChange}
150+
key={`${dataKey}_select`}
151+
>
152+
<FormControl>
153+
<SelectTrigger>
154+
<SelectValue placeholder="Select a column" />
155+
</SelectTrigger>
156+
</FormControl>
157+
<SelectContent>
158+
{data.data?.[0] ? (
159+
Object.keys(
160+
data.data?.[0] ?? {}
161+
)
162+
.filter(
163+
column => column
164+
)
165+
.map(column => (
166+
<SelectItem
167+
key={`${dataKey}${column}`}
168+
value={column}
169+
>
170+
{column}
171+
</SelectItem>
172+
))
173+
) : (
174+
<SelectItem
175+
value="noData"
176+
disabled
177+
>
178+
No data loaded
179+
</SelectItem>
180+
)}
181+
</SelectContent>
182+
</Select>
183+
</FormItem>
184+
)}
185+
/>
186+
</div>
187+
<div className="grid gap-3">
188+
<FormField
189+
control={form.control}
190+
name="dataType"
191+
render={({ field }) => (
192+
<FormItem>
193+
<FormLabel>Data type</FormLabel>
194+
<Select
195+
defaultValue="numeric"
196+
onValueChange={field.onChange}
197+
key={`${dataKey}_dataType`}
198+
>
199+
<FormControl>
200+
<SelectTrigger>
201+
<SelectValue placeholder="Select dataType" />
202+
</SelectTrigger>
203+
</FormControl>
204+
<SelectContent>
205+
<SelectItem
206+
key="numeric"
207+
value="numeric"
208+
>
209+
Numeric
210+
</SelectItem>
211+
<SelectItem
212+
key="categorical"
213+
value="categorical"
214+
>
215+
Categorical
216+
</SelectItem>
217+
</SelectContent>
218+
</Select>
219+
</FormItem>
220+
)}
221+
/>
222+
</div>
223+
</fieldset>
224+
225+
{/* <fieldset className="grid gap-6 rounded-lg border p-4">
226+
<legend className="-ml-1 px-1 text-sm font-medium">
227+
Parameters
228+
</legend>
229+
<div className="grid gap-3">
230+
<Label htmlFor="iterations">
231+
Iterations ({iter})
232+
</Label>
233+
<Slider
234+
id="iterations"
235+
defaultValue={iter}
236+
max={100}
237+
step={1}
238+
onValueChange={value => setIter(value)}
239+
className="cursor-pointer"
240+
/>
241+
</div>
242+
<div className="grid gap-3">
243+
<Label htmlFor="min-cluster-size">
244+
Minimal cluster size ({clusters})
245+
</Label>
246+
<Slider
247+
id="min-cluster-size"
248+
defaultValue={clusters}
249+
key={`${dataKey}_clusters`}
250+
max={Math.floor(
251+
(data?.data?.length || 1000) / 10
252+
)}
253+
step={1}
254+
onValueChange={value => setClusters(value)}
255+
className="cursor-pointer"
256+
/>
257+
</div>
258+
<div className="flex flex-row gap-3">
259+
<FormField
260+
control={form.control}
261+
name="whichPerformanceMetricValueIsBetter"
262+
render={({ field }) => (
263+
<RadioGroup
264+
onValueChange={field.onChange}
265+
defaultValue={field.value}
266+
key={`${dataKey}_whichPerformanceMetricValueIsBetter`}
267+
className="flex flex-col space-y-1"
268+
>
269+
<FormItem className="flex items-center space-x-3 space-y-0">
270+
<FormControl>
271+
<RadioGroupItem value="lower" />
272+
</FormControl>
273+
<FormLabel className="font-normal">
274+
Lower value of performance
275+
metric is better, e.g., error
276+
rate
277+
</FormLabel>
278+
</FormItem>
279+
<FormItem className="flex items-center space-x-3 space-y-0">
280+
<FormControl>
281+
<RadioGroupItem value="higher" />
282+
</FormControl>
283+
<FormLabel className="font-normal">
284+
Higher value of performance
285+
metric is better, e.g., accuracy
286+
</FormLabel>
287+
</FormItem>
288+
</RadioGroup>
289+
)}
290+
></FormField>
291+
</div>
292+
</fieldset> */}
293+
294+
<div className="flex flex-row ml-auto gap-2">
295+
{isErrorDuringAnalysis && (
296+
<div className="text-red-500">
297+
{'Error while analysing'}
298+
</div>
299+
)}
300+
</div>
301+
302+
<div className="flex flex-row ml-auto gap-2 hideonprint">
303+
<Button
304+
onClick={event => {
305+
event.preventDefault();
306+
onDemoRun();
307+
return false;
308+
}}
309+
size="sm"
310+
variant={'outline'}
311+
className="gap-1.5 xl:hidden"
312+
disabled={isLoading}
313+
>
314+
{!isLoading ? 'Try it out' : 'Initialising...'}
315+
</Button>
316+
<Button
317+
type="submit"
318+
size="sm"
319+
className="gap-1.5"
320+
disabled={isLoading}
321+
>
322+
{!isLoading
323+
? 'Run Synthetic Data Generation'
324+
: isInitialised
325+
? 'Analyzing...'
326+
: 'Initialising...'}
327+
<ArrowRight className="size-3.5 hidden xl:flex" />
328+
<ArrowDown className="size-3.5 xl:hidden" />
329+
</Button>
330+
</div>
331+
</form>
332+
333+
<Card className="hidden xl:flex hideonprint">
334+
<div className="flex flex-row w-full items-center justify-between">
335+
<CardHeader>
336+
<CardTitle className="text-aaDark text-md">
337+
Try it out!
338+
</CardTitle>
339+
<CardDescription>
340+
Do you not have a dataset at hand? No worries
341+
use our demo data set.
342+
</CardDescription>
343+
</CardHeader>
344+
<Button
345+
onClick={() => onDemoRun()}
346+
size="sm"
347+
variant={'outline'}
348+
className="gap-1.5 mr-4"
349+
disabled={isLoading}
350+
>
351+
{!isLoading ? 'Try it out' : 'Initializing...'}
352+
</Button>
353+
</div>
354+
</Card>
355+
</div>
356+
</Form>
357+
);
358+
}

src/main.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import ReactDOM from 'react-dom/client';
33
import './index.css';
44
import Navigation from './routes/Index';
55
import BiasDetection from './routes/BiasDetection';
6+
import SyntheticDataGeneration from './routes/SyntheticData';
67

78
// Render the app
89
const rootElement = document.getElementById('root')!;
@@ -11,10 +12,14 @@ const routeName = rootElement?.getAttribute('data-route');
1112
if (!rootElement?.innerHTML) {
1213
const root = ReactDOM.createRoot(rootElement);
1314

15+
console.log(routeName);
16+
1417
const dynamicRoutes = () => {
1518
switch (routeName) {
1619
case 'bias-detection':
1720
return <BiasDetection />;
21+
case 'synthetic-data':
22+
return <SyntheticDataGeneration />;
1823
default:
1924
return <Navigation />;
2025
}

src/routes/Index.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ export default function Navigation() {
2424
</a>
2525
<hr />
2626
<a
27-
aria-disabled
2827
href="/synthetic-data.html"
2928
className="flex font-semibold rounded-lg p-2 text-sm items-center bg-muted [&.active]:text-white [&.active]:bg-aaRegular"
3029
>

0 commit comments

Comments
 (0)