Skip to content

Commit ae0f820

Browse files
committed
Updated the way the dashboard works
1 parent 9cd0e83 commit ae0f820

2 files changed

Lines changed: 220 additions & 261 deletions

File tree

src/analysis-breakdown.md

Lines changed: 30 additions & 261 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,27 @@
22
theme: [dashboard, air]
33
title: Get analyses by requirements
44
toc: false
5-
sql:
6-
fed_types: ./data/federated-types.db
75
---
6+
87
```js
9-
import tex from "npm:@observablehq/tex";
10-
import {sql} from "npm:@observablehq/duckdb";
8+
import { Statistic, Algorithm } from "./components/display_statistic.js"
119
```
1210

1311
# Available analyses
1412

1513
## TRE requirements
1614

17-
<!-- Load analyses -->
15+
<!-- Load data -->
1816
```js
19-
const analyses = FileAttachment("data/analyses.json").json();
17+
const statistics = FileAttachment("./data/statistics.csv").csv();
18+
const algorithms = FileAttachment("./data/algorithms.csv").csv();
19+
const aliases = FileAttachment("./data/statistic_aliases.csv").csv();
20+
const observableData = FileAttachment("./data/observable_data.csv").csv();
21+
const statisticRelationships = FileAttachment("./data/statistic_relationships.csv").csv();
22+
const statbarns = FileAttachment("./data/statbarns.csv").csv();
2023
```
2124

22-
<!-- Define filter form -->
25+
<!-- Old filter form
2326
```js
2427
const filters = view(Inputs.form({
2528
// Trust requirements
@@ -83,267 +86,33 @@ const filters = view(Inputs.form({
8386
}
8487
)
8588
}));
86-
```
87-
88-
```sql
89-
-- I've tried filtering by separability but duckdb and observable don't do arrays well
90-
-- I'll just have to do it in js
91-
SELECT *
92-
FROM fed_types.algorithms a
93-
WHERE (a.requires_persistence = ${filters.persistence_capable} OR a.requires_persistence = false)
94-
AND (a.requires_branching = ${filters.branching_capable} OR a.requires_branching = false);
95-
```
96-
97-
98-
<!-- Filter function
99-
```js
100-
function filterAnalyses(analyses, filters) {
101-
return analyses
102-
.map(analysis => {
103-
// Filter algorithms within each analysis
104-
const compatibleAlgorithms = analysis.algorithms.filter(algo => {
105-
// Trust level check
106-
if (filters.trust_level === "Aggregate data only") {
107-
const hasRowLevel = algo.trust_requirements.aggregator.some(req =>
108-
req.toLowerCase().includes("row-level")
109-
);
110-
if (hasRowLevel) return false;
111-
}
112-
113-
// Communication rounds check
114-
if (filters.communication_rounds === "One round only") {
115-
if (algo.communication.rounds !== 1) return false;
116-
}
117-
118-
// Execution model check
119-
if (!filters.execution_models.includes(algo.computation.execution_model)) {
120-
return false;
121-
}
122-
123-
// Persistent executors check
124-
if (filters.persistent_executors === "Not required") {
125-
if (algo.computation.persistent_executors === true) return false;
126-
}
127-
128-
// Decomposability check
129-
if (!filters.decomposability.includes(algo.decomposability)) {
130-
return false;
131-
}
132-
133-
// Privacy methods check (if any are selected, algorithm must support at least one)
134-
if (filters.privacy_methods.length > 0) {
135-
const algoEncryption = algo.privacy_methods?.encryption || [];
136-
const hasDp = filters.privacy_methods.includes("Differential Privacy") &&
137-
algo.privacy_methods?.differential_privacy;
138-
const hasHe = filters.privacy_methods.includes("Homomorphic Encryption") &&
139-
algoEncryption.some(e => e.includes("HE"));
140-
const hasMpc = filters.privacy_methods.includes("Secure MPC") &&
141-
algoEncryption.some(e => e.includes("MPC"));
142-
143-
if (!hasDp && !hasHe && !hasMpc) return false;
144-
}
145-
146-
return true;
147-
});
148-
149-
// Return analysis with filtered algorithms, or null if none compatible
150-
if (compatibleAlgorithms.length === 0) return null;
151-
152-
return {
153-
...analysis,
154-
algorithms: compatibleAlgorithms,
155-
algorithmCount: compatibleAlgorithms.length
156-
};
157-
})
158-
.filter(a => a !== null)
159-
.filter(a => filters.output_types.includes(a.output.data_type));
160-
}
161-
```
162-
163-
<!-- Apply filters
164-
```js
165-
const filteredAnalyses = filterAnalyses(analyses, filters);
166-
```
167-
168-
<div style= padding: 1rem; border-radius: 0.5rem; margin: 1rem 0;">
169-
<h3 style="margin-top: 0;">Summary</h3>
170-
<p><strong>${filteredAnalyses.length}</strong> of <strong>${analyses.length}</strong> analyses are compatible with your capabilities</p>
171-
<p><strong>${filteredAnalyses.reduce((sum, a) => sum + a.algorithmCount, 0)}</strong> total compatible algorithms</p>
172-
</div>
89+
``` -->
17390

174-
<!-- Display results table
17591
```js
176-
Inputs.table(filteredAnalyses, {
177-
columns: [
178-
"name",
179-
"output",
180-
"algorithmCount"
181-
],
182-
header: {
183-
name: "Analysis",
184-
output: "Output",
185-
algorithmCount: "Compatible Algorithms"
186-
},
187-
format: {
188-
output: d => `${d.data_type} - ${d.description}`,
189-
algorithmCount: d => d
190-
},
191-
width: {
192-
name: "25%",
193-
output: "60%",
194-
algorithmCount: "15%"
195-
}
196-
})
92+
const filters = Inputs.form()
19793
```
19894

19995
```js
200-
import tex from "npm:@observablehq/tex";
201-
202-
display(html`<div style="margin-top: 2rem;">
203-
<h2>Detailed Compatibility</h2>
204-
${filteredAnalyses.map(analysis => html`
205-
<details style="
206-
border: 1px solid #e5e7eb;
207-
border-radius: 0.5rem;
208-
padding: 1rem;
209-
margin: 1rem 0;
210-
background: white;
211-
">
212-
<summary style="
213-
cursor: pointer;
214-
font-weight: 600;
215-
font-size: 1.1rem;
216-
user-select: none;
217-
">
218-
${analysis.mathjax ? tex`${analysis.mathjax}` : analysis.name}
219-
<span style="
220-
color: #6b7280;
221-
font-weight: normal;
222-
font-size: 0.9rem;
223-
"> — ${analysis.algorithmCount} algorithm(s)</span>
224-
</summary>
225-
226-
<div style="margin-top: 1rem; padding-top: 1rem; border-top: 1px solid #e5e7eb;">
227-
<p><strong>Description:</strong> ${analysis.description}</p>
228-
<p><strong>Output:</strong> ${analysis.output.data_type} — ${analysis.output.description}</p>
229-
230-
<h4>Compatible Algorithms:</h4>
231-
${analysis.algorithms.map(algo => html`
232-
<div style="
233-
background: #f9fafb;
234-
padding: 1rem;
235-
margin: 0.5rem 0;
236-
border-radius: 0.375rem;
237-
border-left: 3px solid ${getDecomposabilityColor(algo.decomposability)};
238-
">
239-
<div style="display: flex; justify-content: space-between; align-items: start;">
240-
<h5 style="margin: 0 0 0.5rem 0;">${algo.name}</h5>
241-
<span style="
242-
background: ${getDecomposabilityColor(algo.decomposability)};
243-
color: white;
244-
padding: 0.25rem 0.5rem;
245-
border-radius: 0.25rem;
246-
font-size: 0.75rem;
247-
font-weight: 600;
248-
">
249-
${algo.decomposability}
250-
</span>
251-
</div>
252-
253-
${algo.description ? html`<p style="color: #6b7280; margin: 0.5rem 0;">${algo.description}</p>` : ''}
254-
${algo.mathjax ? html`<div style="margin: 0.5rem 0; padding: 0.5rem; background: white; border-radius: 0.25rem;">${tex`${algo.mathjax}`}</div>` : ''}
255-
256-
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-top: 0.75rem; font-size: 0.875rem;">
257-
<div>
258-
<strong>Trust requirements:</strong>
259-
<ul style="margin: 0.25rem 0; padding-left: 1.5rem;">
260-
${algo.trust_requirements.aggregator.map(req => html`<li>${req}</li>`)}
261-
</ul>
262-
</div>
263-
264-
<div>
265-
<strong>Communication:</strong>
266-
<ul style="margin: 0.25rem 0; padding-left: 1.5rem;">
267-
<li>Rounds: ${algo.communication.rounds}</li>
268-
<li>Direction: ${algo.communication.direction}</li>
269-
</ul>
270-
</div>
271-
272-
<div>
273-
<strong>Computation:</strong>
274-
<ul style="margin: 0.25rem 0; padding-left: 1.5rem;">
275-
<li>Model: ${algo.computation.execution_model}</li>
276-
<li>Persistent: ${algo.computation.persistent_executors ? 'Yes' : 'No'}</li>
277-
</ul>
278-
</div>
279-
280-
${algo.privacy_methods ? html`
281-
<div>
282-
<strong>Privacy methods:</strong>
283-
<ul style="margin: 0.25rem 0; padding-left: 1.5rem;">
284-
${algo.privacy_methods.differential_privacy ? html`<li>DP: ${algo.privacy_methods.differential_privacy}</li>` : ''}
285-
${algo.privacy_methods.encryption?.length > 0 ? html`<li>Encryption: ${algo.privacy_methods.encryption.join(', ')}</li>` : ''}
286-
</ul>
287-
</div>
288-
` : ''}
289-
</div>
290-
291-
${algo.performance ? html`
292-
<div style="margin-top: 0.5rem;">
293-
<strong>Performance:</strong>
294-
<span style="
295-
background: ${getPerformanceColor(algo.performance)};
296-
padding: 0.125rem 0.5rem;
297-
border-radius: 0.25rem;
298-
font-size: 0.875rem;
299-
">${algo.performance}</span>
300-
</div>
301-
` : ''}
302-
303-
${algo.practical_notes?.length > 0 ? html`
304-
<div style="
305-
margin-top: 0.75rem;
306-
padding: 0.5rem;
307-
background: #fef3c7;
308-
border-radius: 0.25rem;
309-
font-size: 0.875rem;
310-
">
311-
<strong>Notes:</strong>
312-
<ul style="margin: 0.25rem 0; padding-left: 1.5rem;">
313-
${algo.practical_notes.map(note => html`<li>${note}</li>`)}
314-
</ul>
315-
</div>
316-
` : ''}
317-
</div>
318-
`)}
319-
</div>
320-
</details>
321-
`)}
322-
</div>`);
323-
```
96+
const algorithmList = algorithms.map(
97+
d => {
98+
const algo = new Algorithm(d);
99+
algo.addObservables(observableData);
100+
return algo
101+
}
102+
);
324103

325-
<!-- Helper functions for colors -->
326-
```js
327-
function getDecomposabilityColor(decomp) {
328-
const colors = {
329-
"fully-decomposable": "#10b981",
330-
"approximately-decomposable": "#3b82f6",
331-
"iteratively-decomposable": "#f59e0b",
332-
"non-decomposable": "#ef4444"
333-
};
334-
return colors[decomp] || "#6b7280";
335-
}
104+
const statisticsList = statistics.map(
105+
d => {
106+
const stat = new Statistic(d);
107+
stat.addAliases(aliases);
108+
stat.addAlgorithms(algorithmList);
109+
if (stat.algorithms.length > 0) {
110+
return stat
111+
}
112+
}
113+
);
336114
```
337115

338116
```js
339-
function getPerformanceColor(perf) {
340-
const colors = {
341-
"very fast": "#d1fae5",
342-
"fast": "#a7f3d0",
343-
"moderate": "#fef3c7",
344-
"slow": "#fed7aa",
345-
"very slow": "#fecaca"
346-
};
347-
return colors[perf] || "#f3f4f6";
348-
}
117+
html`${statisticsList.map(stat => stat ? stat.display(): "")}`
349118
```

0 commit comments

Comments
 (0)