Skip to content

Commit 573e62b

Browse files
authored
Merge pull request #58 from NGO-Algorithm-Audit/feature/small-tweaks-code-improvements
Feature/small tweaks code improvements
2 parents 9543efe + 85e4207 commit 573e62b

15 files changed

+721
-432
lines changed

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"react-to-print": "^3.0.1",
5252
"tailwind-merge": "^2.5.2",
5353
"tailwindcss-animate": "^1.0.7",
54+
"unist-util-visit-parents": "^6.0.1",
5455
"vaul": "^0.9.1",
5556
"zod": "^3.23.8"
5657
},

src/assets/synthetic-data.tsx

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -281,15 +281,10 @@ def run():
281281
282282
# Convert list of dictionaries to DataFrame
283283
metrics_df = pd.DataFrame(metrics_list)
284-
columns_order = ['dataType'] + [col for col in metrics_df.columns if col != 'dataType']
285-
metrics_df = metrics_df[columns_order]
286-
columns_order = ['column'] + [col for col in metrics_df.columns if col != 'column']
287-
metrics_df = metrics_df[columns_order]
288-
289-
clf_efficacy = EfficacyMetrics(task='classification', target_column="bar")
290-
clf_metrics = clf_efficacy.evaluate(df_imputed, synthetic_data)
291-
print("=== Classification Efficacy Metrics === BAR")
292-
print(clf_metrics)
284+
285+
front_columns = ['column', 'dataType']
286+
other_columns = [col for col in metrics_df.columns if col not in front_columns]
287+
metrics_df = metrics_df[front_columns + other_columns]
293288
294289
dp = DisclosureProtection(df_imputed, synthetic_data)
295290
dp_score = dp.score()
@@ -318,13 +313,17 @@ def run():
318313
{
319314
'reportType': 'text',
320315
'textKey': 'syntheticData.handlingMissingDataDescription'
321-
},
316+
},
322317
{
323318
'reportType': 'table',
324319
'titleKey': 'syntheticData.handlingMissingDataTableTitle',
325320
'showIndex' : False,
326321
'data': missingness_dict_df.to_json(orient="records"),
327322
},
323+
{
324+
'reportType': 'text',
325+
'textKey': 'syntheticData.missingData'
326+
},
328327
{
329328
'reportType': 'heading',
330329
'headingKey': 'syntheticData.cartModelTitle' if sdgMethod == 'cart' else 'syntheticData.gaussianCopulaModelTitle'

src/components/DistributionReport.tsx

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { t } from 'i18next';
2-
import Markdown from 'react-markdown';
32
import { Fragment } from 'react/jsx-runtime';
43
import ErrorBoundary from './ErrorBoundary';
54
import DistributionBarChart from './graphs/DistributionBarChart';
@@ -10,6 +9,7 @@ import { createHeatmapdata } from './createHeatmapdata';
109
import ViolinChart from './graphs/ViolinChart';
1110
import GroupBarChart from './graphs/GroupBarChart';
1211
import SimpleTable from './SimpleTable';
12+
import { MarkdownWithTooltips } from './MarkdownWithTooltips';
1313

1414
interface CorrelationMatrixProps {
1515
heatmapData: {
@@ -34,8 +34,12 @@ function CorrelationMatrix(props: CorrelationMatrixProps) {
3434
);
3535
}
3636

37+
interface DataRow {
38+
[key: string]: string | number | boolean;
39+
}
40+
3741
function countCategory2ForCategory1(
38-
data: Record<string, any>[],
42+
data: DataRow[],
3943
category1: string,
4044
category2: string,
4145
column1: string,
@@ -106,12 +110,12 @@ export const DistributionReport = (
106110
}
107111
if (report.reportType === 'text' && report.textKey) {
108112
return (
109-
<Markdown
113+
<MarkdownWithTooltips
110114
key={indexReport}
111115
className="-mt-2 text-gray-800 markdown"
112116
>
113117
{t(report.textKey, report.params)}
114-
</Markdown>
118+
</MarkdownWithTooltips>
115119
);
116120
}
117121

@@ -143,7 +147,7 @@ export const DistributionReport = (
143147
'text'
144148
) {
145149
return (
146-
<Markdown
150+
<MarkdownWithTooltips
147151
key={index}
148152
className="-mt-2 text-gray-800 markdown"
149153
>
@@ -152,7 +156,7 @@ export const DistributionReport = (
152156
'',
153157
content.params
154158
)}
155-
</Markdown>
159+
</MarkdownWithTooltips>
156160
);
157161
}
158162
}
@@ -172,7 +176,7 @@ export const DistributionReport = (
172176
'text'
173177
) {
174178
return (
175-
<Markdown
179+
<MarkdownWithTooltips
176180
key={index}
177181
className="-mt-2 text-gray-800 markdown"
178182
>
@@ -181,7 +185,7 @@ export const DistributionReport = (
181185
'',
182186
content.params
183187
)}
184-
</Markdown>
188+
</MarkdownWithTooltips>
185189
);
186190
} else if (
187191
content.contentType ===
@@ -282,11 +286,18 @@ export const DistributionReport = (
282286
) {
283287
const data = realData.reduce(
284288
(
285-
acc: Record<string, any>,
286-
row: Record<string, any>
289+
acc: Record<
290+
string,
291+
Record<string, number>
292+
>,
293+
row: DataRow
287294
) => {
288-
const category = row[column];
289-
const category2 = row[column2];
295+
const category = row[
296+
column
297+
] as string;
298+
const category2 = row[
299+
column2
300+
] as string;
290301
if (!acc[category]) {
291302
acc[category] = {};
292303
}
@@ -433,14 +444,16 @@ export const DistributionReport = (
433444
const categories = Array.from(
434445
new Set([
435446
...realData.map(
436-
(d: any) => d[column]
447+
(d: DataRow) =>
448+
d[column] as string
437449
),
438450
])
439451
);
440452
const categories2 = Array.from(
441453
new Set([
442454
...realData.map(
443-
(d: any) => d[column2]
455+
(d: DataRow) =>
456+
d[column2] as string
444457
),
445458
])
446459
);
@@ -522,15 +535,15 @@ export const DistributionReport = (
522535
)}
523536
content={
524537
<div>
525-
<Markdown className="py-4 markdown">
538+
<MarkdownWithTooltips className="py-4 markdown">
526539
{t(
527540
'syntheticData.bivariateText',
528541
{
529542
samples:
530543
syntheticData.length,
531544
}
532545
)}
533-
</Markdown>
546+
</MarkdownWithTooltips>
534547
{charts}
535548
</div>
536549
}
@@ -616,15 +629,15 @@ export const DistributionReport = (
616629
)}
617630
content={
618631
<>
619-
<Markdown className="py-4 markdown">
632+
<MarkdownWithTooltips className="py-4 markdown">
620633
{t(
621634
'syntheticData.univariateText',
622635
{
623636
samples:
624637
syntheticData.length,
625638
}
626639
)}
627-
</Markdown>
640+
</MarkdownWithTooltips>
628641
{Object.keys(
629642
realData[0]
630643
).map(
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import Markdown from 'react-markdown';
2+
import { remarkInfoTooltip } from './remark-info-tooltip';
3+
import { rehypeInfoTooltip } from './rehype-info-tooltip';
4+
import { TooltipWrapper } from './TooltipWrapper';
5+
import type { Element, ElementData } from 'hast';
6+
7+
interface MarkdownWithTooltipsProps {
8+
children: string;
9+
className?: string;
10+
}
11+
12+
interface CustomElementData extends ElementData {
13+
hProperties?: {
14+
tooltip?: string;
15+
};
16+
}
17+
18+
interface CustomElement extends Element {
19+
data?: CustomElementData;
20+
}
21+
22+
export function MarkdownWithTooltips({
23+
children,
24+
className,
25+
}: MarkdownWithTooltipsProps) {
26+
return (
27+
<Markdown
28+
className={className}
29+
remarkPlugins={[remarkInfoTooltip]}
30+
rehypePlugins={[rehypeInfoTooltip]}
31+
components={{
32+
// @ts-expect-error - TooltipWrapper is a custom component
33+
TooltipWrapper,
34+
span: ({ node, children, ...props }) => {
35+
const element = node as CustomElement;
36+
const tooltipContent = element.data?.hProperties?.tooltip;
37+
if (tooltipContent) {
38+
return (
39+
<TooltipWrapper
40+
tooltipContent={tooltipContent}
41+
children={children}
42+
/>
43+
);
44+
}
45+
return <span {...props}>{children}</span>;
46+
},
47+
}}
48+
>
49+
{children}
50+
</Markdown>
51+
);
52+
}

src/components/TooltipWrapper.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { InfoIcon } from 'lucide-react';
2+
import {
3+
Tooltip,
4+
TooltipContent,
5+
TooltipProvider,
6+
TooltipTrigger,
7+
} from './ui/tooltip';
8+
import { MarkdownWithTooltips } from './MarkdownWithTooltips';
9+
10+
interface TooltipWrapperProps {
11+
tooltipContent: string;
12+
children: React.ReactNode;
13+
}
14+
15+
export function TooltipWrapper({
16+
tooltipContent,
17+
children,
18+
}: TooltipWrapperProps) {
19+
return (
20+
<span className="inline-flex items-center">
21+
{children}
22+
<TooltipProvider>
23+
<Tooltip>
24+
<TooltipTrigger
25+
onClick={event => {
26+
event.preventDefault();
27+
}}
28+
>
29+
<InfoIcon className="size-3.5 ml-1" />
30+
</TooltipTrigger>{' '}
31+
&nbsp;
32+
<TooltipContent className="max-w-[400px] p-2">
33+
<MarkdownWithTooltips className="text-gray-800 markdown">
34+
{tooltipContent}
35+
</MarkdownWithTooltips>
36+
</TooltipContent>
37+
</Tooltip>
38+
</TooltipProvider>
39+
</span>
40+
);
41+
}

src/components/componentMapper.tsx

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,19 @@ import SimpleTable from './SimpleTable';
22
import SingleBarChart from './graphs/SingleBarChart';
33
import GroupBarChart from './graphs/GroupBarChart';
44
import ErrorBoundary from './ErrorBoundary';
5-
import Markdown from 'react-markdown';
65
import { getLabel } from './graphs/get-label';
76
import { CSVData } from './bias-detection-interfaces/csv-data';
87
import { Fragment } from 'react/jsx-runtime';
98
import { Accordion } from './ui/accordion';
109
import { useTranslation } from 'react-i18next';
1110
import { DistributionReport } from './DistributionReport';
11+
import { MarkdownWithTooltips } from './MarkdownWithTooltips';
12+
import { TooltipProvider } from '@radix-ui/react-tooltip';
13+
14+
interface Comparison {
15+
key: string;
16+
params: Record<string, string | number | boolean>;
17+
}
1218

1319
const createArrayFromPythonDictionary = (dict: Record<string, number>) => {
1420
const resultArray = [];
@@ -90,11 +96,8 @@ export default function ComponentMapper({
9096
if (resultItem.comparisons) {
9197
// Handle translation of comparisons
9298
const content = resultItem.comparisons
93-
.map(
94-
(comparison: {
95-
key: string;
96-
params: Record<string, any>;
97-
}) => t(comparison.key, comparison.params)
99+
.map((comparison: Comparison) =>
100+
t(comparison.key, comparison.params)
98101
)
99102
.join('\n');
100103

@@ -125,14 +128,16 @@ export default function ComponentMapper({
125128

126129
case 'text':
127130
return (
128-
<Markdown
129-
key={index}
130-
className="-mt-2 text-gray-800 markdown"
131-
>
132-
{resultItem.key
133-
? t(resultItem.key, resultItem.params)
134-
: resultItem.data}
135-
</Markdown>
131+
<TooltipProvider>
132+
<MarkdownWithTooltips
133+
key={index}
134+
className="-mt-2 text-gray-800 markdown"
135+
>
136+
{resultItem.key
137+
? t(resultItem.key, resultItem.params)
138+
: resultItem.data}
139+
</MarkdownWithTooltips>
140+
</TooltipProvider>
136141
);
137142
case 'histogram': {
138143
const histogramData = JSON.parse(resultItem.data)?.map(

0 commit comments

Comments
 (0)