/ concept-collection / benchcompress
Sign in
concept-collection / benchcompress
test real data
Jeremy Magland <jmagland@flatironinstitute.org> committed commit eacabc855c20 parent fb768fe Browse files
16 changed files+570−308
test1.pymodified+11−7View file
@@ -1,3 +1,11 @@
1+# %%
2+import numpy as np
3+from zia_benchmark._filters import bandpass_filter, highpass_filter
4+from zia_benchmark._compress_ints_lossless import compress_ints_lossless
5+from zia_benchmark.datasets import datasets
6+# %%
7+import numpy as np
8+
19 # %%
210 import numpy as np
311 from zia_benchmark._filters import bandpass_filter, highpass_filter
@@ -7,13 +15,9 @@ from zia_benchmark._analysis import linear_fit, compute_entropy_per_sample, esti
715 import matplotlib.pyplot as plt
816
917 # %%
10-N = 500_000
11-
12-channel_number = 101
13-X = load_real_000409(num_samples=N, num_channels=1, start_channel=channel_number).flatten()
14-
15-# X = load_real_001290(num_samples=N, num_channels=1, start_channel=0).flatten()
16-# X = load_real_000876(num_samples=N, num_channels=1, start_channel=45).flatten()
18+# Find the real-000409-ch101 dataset
19+real_dataset = next(d for d in datasets if d['name'] == 'real-000409-ch101')
20+X = real_dataset['create']().flatten()
1721
1822 X = X.astype(np.int16)
1923
web-ui/index.htmlmodified+2−2View file
@@ -2,9 +2,9 @@
22 <html lang="en">
33 <head>
44 <meta charset="UTF-8" />
5- <link rel="icon" type="image/svg+xml" href="/vite.svg" />
5+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
66 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7- <title>Vite + React + TS</title>
7+ <title>Zia Benchmark</title>
88 </head>
99 <body>
1010 <div id="root"></div>
web-ui/public/favicon.svgadded+26−0View file
@@ -0,0 +1,26 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
3+ <!-- Background circle -->
4+ <circle cx="16" cy="16" r="15" fill="#f0f0f0"/>
5+
6+ <!-- Compression arrows -->
7+ <g transform="translate(16 16) scale(0.0625)">
8+ <!-- Left arrows -->
9+ <path d="M-180 -60 L-100 -60 L-100 -90 L-20 -30 L-100 30 L-100 0 L-180 0 Z" fill="#2563eb"/>
10+ <!-- Right arrows -->
11+ <path d="M180 60 L100 60 L100 90 L20 30 L100 -30 L100 0 L180 0 Z" fill="#2563eb"/>
12+
13+ <!-- Central data points/graph -->
14+ <g fill="#1e40af">
15+ <circle cx="-60" cy="40" r="8"/>
16+ <circle cx="-20" cy="-30" r="8"/>
17+ <circle cx="20" cy="10" r="8"/>
18+ <circle cx="60" cy="-40" r="8"/>
19+ <path d="M-60 40 L-20 -30 L20 10 L60 -40"
20+ fill="none"
21+ stroke="#1e40af"
22+ stroke-width="4"
23+ stroke-linecap="round"/>
24+ </g>
25+ </g>
26+</svg>
web-ui/public/logo.svgadded+37−0View file
@@ -0,0 +1,37 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
3+ <!-- Background circle -->
4+ <circle cx="256" cy="256" r="240" fill="#f0f0f0"/>
5+
6+ <!-- Compression arrows -->
7+ <g transform="translate(256 256)">
8+ <!-- Left arrows -->
9+ <path d="M-180 -60 L-100 -60 L-100 -90 L-20 -30 L-100 30 L-100 0 L-180 0 Z" fill="#2563eb"/>
10+ <!-- Right arrows -->
11+ <path d="M180 60 L100 60 L100 90 L20 30 L100 -30 L100 0 L180 0 Z" fill="#2563eb"/>
12+
13+ <!-- Central data points/graph -->
14+ <g fill="#1e40af">
15+ <circle cx="-60" cy="40" r="8"/>
16+ <circle cx="-20" cy="-30" r="8"/>
17+ <circle cx="20" cy="10" r="8"/>
18+ <circle cx="60" cy="-40" r="8"/>
19+ <!-- Connecting lines -->
20+ <path d="M-60 40 L-20 -30 L20 10 L60 -40"
21+ fill="none"
22+ stroke="#1e40af"
23+ stroke-width="4"
24+ stroke-linecap="round"/>
25+ </g>
26+ </g>
27+
28+ <!-- "ZIA" text -->
29+ <text x="256" y="380"
30+ font-family="Arial, sans-serif"
31+ font-size="72"
32+ font-weight="bold"
33+ text-anchor="middle"
34+ fill="#1e40af">
35+ ZIA
36+ </text>
37+</svg>
web-ui/src/App.tsxmodified+6−6View file
@@ -5,17 +5,17 @@ function App() {
55 <div style={{ padding: '2rem' }}>
66 <header style={{ marginBottom: '2rem' }}>
77 <h1 style={{
8- fontSize: '2rem',
9- fontWeight: 'bold',
10- color: '#333'
11- }}>
12- Zia Compression Benchmark Results
8+ fontSize: '2rem',
9+ fontWeight: 'bold',
10+ color: '#333'
11+ }}>
12+ ZIA Integer Compression Benchmark
1313 </h1>
1414 <p style={{
1515 color: '#666',
1616 marginTop: '0.5rem'
1717 }}>
18- Comparing different compression algorithms and their performance
18+ Comparing different integer array compression algorithms and their performance
1919 </p>
2020 </header>
2121 <main>
web-ui/src/components/BenchmarkTable.tsxmodified+1−290View file
@@ -1,290 +1 @@
1-import { useEffect, useState, useMemo } from 'react';
2-import axios from 'axios';
3-import Plot from 'react-plotly.js';
4-import {
5- createColumnHelper,
6- flexRender,
7- getCoreRowModel,
8- useReactTable,
9- getSortedRowModel,
10-} from '@tanstack/react-table';
11-import { BenchmarkResult } from '../types';
12-
13-const columnHelper = createColumnHelper<BenchmarkResult>();
14-
15-const formatNumber = (num: number, decimals = 2) => {
16- return new Intl.NumberFormat('en-US', {
17- minimumFractionDigits: decimals,
18- maximumFractionDigits: decimals,
19- }).format(num);
20-};
21-
22-const formatSize = (bytes: number) => {
23- const mb = bytes / (1024 * 1024);
24- return `${formatNumber(mb)} MB`;
25-};
26-
27-const columns = [
28- columnHelper.accessor('dataset', {
29- header: 'Dataset',
30- cell: info => info.getValue(),
31- }),
32- columnHelper.accessor('algorithm', {
33- header: 'Algorithm',
34- cell: info => info.getValue(),
35- }),
36- columnHelper.accessor('compression_ratio', {
37- header: 'Compression Ratio',
38- cell: info => `${formatNumber(info.getValue())}x`,
39- sortingFn: (rowA, rowB) => {
40- const a = rowA.original.compression_ratio;
41- const b = rowB.original.compression_ratio;
42- return a - b;
43- },
44- }),
45- columnHelper.accessor('encode_time', {
46- header: 'Encode Time (s)',
47- cell: info => formatNumber(info.getValue(), 4),
48- sortingFn: (rowA, rowB) => {
49- const a = rowA.original.encode_time;
50- const b = rowB.original.encode_time;
51- return a - b;
52- },
53- }),
54- columnHelper.accessor('decode_time', {
55- header: 'Decode Time (s)',
56- cell: info => formatNumber(info.getValue(), 4),
57- sortingFn: (rowA, rowB) => {
58- const a = rowA.original.decode_time;
59- const b = rowB.original.decode_time;
60- return a - b;
61- },
62- }),
63- columnHelper.accessor('encode_mb_per_sec', {
64- header: 'Encode Speed (MB/s)',
65- cell: info => formatNumber(info.getValue()),
66- sortingFn: (rowA, rowB) => {
67- const a = rowA.original.encode_mb_per_sec;
68- const b = rowB.original.encode_mb_per_sec;
69- return a - b;
70- },
71- }),
72- columnHelper.accessor('decode_mb_per_sec', {
73- header: 'Decode Speed (MB/s)',
74- cell: info => formatNumber(info.getValue()),
75- sortingFn: (rowA, rowB) => {
76- const a = rowA.original.decode_mb_per_sec;
77- const b = rowB.original.decode_mb_per_sec;
78- return a - b;
79- },
80- }),
81- columnHelper.accessor('original_size', {
82- header: 'Original Size',
83- cell: info => formatSize(info.getValue()),
84- sortingFn: (rowA, rowB) => {
85- const a = rowA.original.original_size;
86- const b = rowB.original.original_size;
87- return a - b;
88- },
89- }),
90- columnHelper.accessor('compressed_size', {
91- header: 'Compressed Size',
92- cell: info => formatSize(info.getValue()),
93- sortingFn: (rowA, rowB) => {
94- const a = rowA.original.compressed_size;
95- const b = rowB.original.compressed_size;
96- return a - b;
97- },
98- }),
99-];
100-
101-export function BenchmarkTable() {
102- const [data, setData] = useState<BenchmarkResult[]>([]);
103- const [selectedDataset, setSelectedDataset] = useState<string>('');
104- const [availableDatasets, setAvailableDatasets] = useState<string[]>([]);
105- const [isLoading, setIsLoading] = useState(true);
106- const [error, setError] = useState<string | null>(null);
107-
108- useEffect(() => {
109- const fetchData = async () => {
110- try {
111- setIsLoading(true);
112- setError(null);
113- const response = await axios.get(
114- 'https://raw.githubusercontent.com/magland/zia/benchmark-results/benchmark_results/results.json'
115- );
116- const results = response.data.results;
117- setData(results);
118- // Extract unique dataset names with proper typing
119- const datasets = Array.from(new Set(results.map((result: BenchmarkResult) => result.dataset))).sort() as string[];
120- setAvailableDatasets(datasets);
121- } catch (error) {
122- const message = error instanceof Error ? error.message : 'Failed to fetch data';
123- setError(message);
124- console.error('Error fetching benchmark data:', error);
125- } finally {
126- setIsLoading(false);
127- }
128- };
129-
130- fetchData();
131- }, []);
132-
133- // Memoize filtered data to prevent unnecessary recalculations
134- const filteredData = useMemo(() => {
135- if (!selectedDataset) return data;
136- return data.filter(row => row.dataset === selectedDataset);
137- }, [data, selectedDataset]);
138-
139- const table = useReactTable({
140- data: filteredData || [],
141- columns,
142- getCoreRowModel: getCoreRowModel(),
143- getSortedRowModel: getSortedRowModel(),
144- });
145-
146- // Prepare data for bar charts when a dataset is selected
147- const chartData = useMemo(() => {
148- if (!selectedDataset) return [];
149- return data
150- .filter(row => row.dataset === selectedDataset)
151- .map(row => ({
152- algorithm: row.algorithm,
153- compression_ratio: row.compression_ratio,
154- encode_speed: row.encode_mb_per_sec,
155- decode_speed: row.decode_mb_per_sec
156- }));
157- }, [data, selectedDataset]);
158-
159- if (isLoading) {
160- return <div>Loading benchmark data...</div>;
161- }
162-
163- if (error) {
164- return <div>Error: {error}</div>;
165- }
166-
167- return (
168- <div className="table-container">
169- <div style={{ marginBottom: '20px', display: 'flex', alignItems: 'center', gap: '10px' }}>
170- <label htmlFor="dataset-select">Filter by Dataset:</label>
171- <select
172- id="dataset-select"
173- value={selectedDataset}
174- onChange={(e) => setSelectedDataset(e.target.value)}
175- style={{
176- padding: '8px',
177- borderRadius: '4px',
178- border: '1px solid #ccc',
179- minWidth: '200px',
180- backgroundColor: '#fff'
181- }}
182- >
183- <option value="">All Datasets</option>
184- {availableDatasets.map(dataset => (
185- <option key={dataset} value={dataset}>
186- {dataset}
187- </option>
188- ))}
189- </select>
190- </div>
191-
192- {selectedDataset && chartData.length > 0 && (
193- <div style={{ marginBottom: '30px' }}>
194- <div style={{ marginBottom: '20px' }}>
195- <h3 style={{ marginBottom: '10px' }}>Compression Ratio</h3>
196- <Plot
197- data={[{
198- type: 'bar',
199- x: chartData.map(d => d.algorithm),
200- y: chartData.map(d => d.compression_ratio),
201- marker: { color: '#8884d8' }
202- }]}
203- layout={{
204- width: 800,
205- height: 300,
206- margin: { t: 5, r: 30, l: 50, b: 30 },
207- yaxis: { title: 'Ratio' }
208- }}
209- config={{ displayModeBar: false }}
210- />
211- </div>
212-
213- <div style={{ marginBottom: '20px' }}>
214- <h3 style={{ marginBottom: '10px' }}>Encode Speed (MB/s)</h3>
215- <Plot
216- data={[{
217- type: 'bar',
218- x: chartData.map(d => d.algorithm),
219- y: chartData.map(d => d.encode_speed),
220- marker: { color: '#82ca9d' }
221- }]}
222- layout={{
223- width: 800,
224- height: 300,
225- margin: { t: 5, r: 30, l: 50, b: 30 },
226- yaxis: { title: 'MB/s' }
227- }}
228- config={{ displayModeBar: false }}
229- />
230- </div>
231-
232- <div style={{ marginBottom: '20px' }}>
233- <h3 style={{ marginBottom: '10px' }}>Decode Speed (MB/s)</h3>
234- <Plot
235- data={[{
236- type: 'bar',
237- x: chartData.map(d => d.algorithm),
238- y: chartData.map(d => d.decode_speed),
239- marker: { color: '#ff7300' }
240- }]}
241- layout={{
242- width: 800,
243- height: 300,
244- margin: { t: 5, r: 30, l: 50, b: 30 },
245- yaxis: { title: 'MB/s' }
246- }}
247- config={{ displayModeBar: false }}
248- />
249- </div>
250- </div>
251- )}
252- <table>
253- <thead>
254- {table.getHeaderGroups().map(headerGroup => (
255- <tr key={headerGroup.id}>
256- {headerGroup.headers.map(header => (
257- <th
258- key={header.id}
259- onClick={header.column.getToggleSortingHandler()}
260- style={{ cursor: 'pointer' }}
261- >
262- {flexRender(
263- header.column.columnDef.header,
264- header.getContext()
265- )}
266- {header.column.getIsSorted() && (
267- <span style={{ marginLeft: '4px' }}>
268- {header.column.getIsSorted() === 'asc' ? '↑' : '↓'}
269- </span>
270- )}
271- </th>
272- ))}
273- </tr>
274- ))}
275- </thead>
276- <tbody>
277- {table.getRowModel().rows.map(row => (
278- <tr key={row.id}>
279- {row.getVisibleCells().map(cell => (
280- <td key={cell.id}>
281- {flexRender(cell.column.columnDef.cell, cell.getContext())}
282- </td>
283- ))}
284- </tr>
285- ))}
286- </tbody>
287- </table>
288- </div>
289- );
290-}
1+export { BenchmarkTable } from './benchmark/table/BenchmarkTable';
web-ui/src/components/benchmark/charts/BenchmarkCharts.tsxadded+80−0View file
@@ -0,0 +1,80 @@
1+import Plot from 'react-plotly.js';
2+
3+interface ChartData {
4+ algorithm: string;
5+ compression_ratio: number;
6+ encode_speed: number;
7+ decode_speed: number;
8+}
9+
10+interface BenchmarkChartsProps {
11+ chartData: ChartData[];
12+}
13+
14+export function BenchmarkCharts({ chartData }: BenchmarkChartsProps) {
15+ if (!chartData.length) return null;
16+
17+ return (
18+ <div style={{ marginBottom: '30px' }}>
19+ <div style={{ marginBottom: '20px' }}>
20+ <h3 style={{ marginBottom: '10px' }}>Compression Ratio</h3>
21+ <Plot
22+ data={[{
23+ type: 'bar',
24+ orientation: 'h',
25+ y: chartData.map(d => d.algorithm),
26+ x: chartData.map(d => d.compression_ratio),
27+ marker: { color: '#8884d8' }
28+ }]}
29+ layout={{
30+ width: 800,
31+ height: 400,
32+ margin: { t: 5, r: 30, l: 120, b: 30 },
33+ xaxis: { title: 'Ratio' }
34+ }}
35+ config={{ displayModeBar: false }}
36+ />
37+ </div>
38+
39+ <div style={{ marginBottom: '20px' }}>
40+ <h3 style={{ marginBottom: '10px' }}>Encode Speed (MB/s)</h3>
41+ <Plot
42+ data={[{
43+ type: 'bar',
44+ orientation: 'h',
45+ y: chartData.map(d => d.algorithm),
46+ x: chartData.map(d => d.encode_speed),
47+ marker: { color: '#82ca9d' }
48+ }]}
49+ layout={{
50+ width: 800,
51+ height: 400,
52+ margin: { t: 5, r: 30, l: 120, b: 30 },
53+ xaxis: { title: 'MB/s' }
54+ }}
55+ config={{ displayModeBar: false }}
56+ />
57+ </div>
58+
59+ <div style={{ marginBottom: '20px' }}>
60+ <h3 style={{ marginBottom: '10px' }}>Decode Speed (MB/s)</h3>
61+ <Plot
62+ data={[{
63+ type: 'bar',
64+ orientation: 'h',
65+ y: chartData.map(d => d.algorithm),
66+ x: chartData.map(d => d.decode_speed),
67+ marker: { color: '#ff7300' }
68+ }]}
69+ layout={{
70+ width: 800,
71+ height: 400,
72+ margin: { t: 5, r: 30, l: 120, b: 30 },
73+ xaxis: { title: 'MB/s' }
74+ }}
75+ config={{ displayModeBar: false }}
76+ />
77+ </div>
78+ </div>
79+ );
80+}
web-ui/src/components/benchmark/export/csvExport.tsadded+36−0View file
@@ -0,0 +1,36 @@
1+import { BenchmarkResult } from '../../../types';
2+import { formatNumber, formatSize } from '../utils/formatters';
3+import { columns } from '../table/columns';
4+
5+export const exportToCsv = (data: BenchmarkResult[], selectedDataset: string) => {
6+ // Convert data to CSV
7+ const headers = columns.map(col => col.header).join(',');
8+ const rows = data.map(row =>
9+ columns.map(col => {
10+ const value = row[col.accessorKey as keyof BenchmarkResult];
11+ // Format numbers according to their display format
12+ if (col.accessorKey === 'compression_ratio') {
13+ return `${formatNumber(value as number)}x`;
14+ } else if (col.accessorKey === 'encode_time' || col.accessorKey === 'decode_time') {
15+ return formatNumber(value as number, 4);
16+ } else if (col.accessorKey === 'original_size' || col.accessorKey === 'compressed_size') {
17+ return formatSize(value as number);
18+ } else if (typeof value === 'number') {
19+ return formatNumber(value);
20+ }
21+ return value;
22+ }).join(',')
23+ ).join('\n');
24+ const csv = `${headers}\n${rows}`;
25+
26+ // Create and trigger download
27+ const blob = new Blob([csv], { type: 'text/csv' });
28+ const url = window.URL.createObjectURL(blob);
29+ const a = document.createElement('a');
30+ a.href = url;
31+ a.download = `benchmark-results${selectedDataset ? `-${selectedDataset}` : ''}.csv`;
32+ document.body.appendChild(a);
33+ a.click();
34+ document.body.removeChild(a);
35+ window.URL.revokeObjectURL(url);
36+};
web-ui/src/components/benchmark/table/BenchmarkTable.tsxadded+169−0View file
@@ -0,0 +1,169 @@
1+import { useEffect, useState, useMemo } from 'react';
2+import axios from 'axios';
3+import {
4+ flexRender,
5+ getCoreRowModel,
6+ useReactTable,
7+ getSortedRowModel,
8+} from '@tanstack/react-table';
9+import { BenchmarkResult } from '../../../types';
10+import { columns } from './columns';
11+import { BenchmarkCharts } from '../charts/BenchmarkCharts';
12+import { exportToCsv } from '../export/csvExport';
13+
14+export function BenchmarkTable() {
15+ const [data, setData] = useState<BenchmarkResult[]>([]);
16+ const [selectedDataset, setSelectedDataset] = useState<string>('');
17+ const [availableDatasets, setAvailableDatasets] = useState<string[]>([]);
18+ const [isLoading, setIsLoading] = useState(true);
19+ const [error, setError] = useState<string | null>(null);
20+
21+ useEffect(() => {
22+ const fetchData = async () => {
23+ try {
24+ setIsLoading(true);
25+ setError(null);
26+ const response = await axios.get(
27+ 'https://raw.githubusercontent.com/magland/zia/benchmark-results/benchmark_results/results.json'
28+ );
29+ const results = response.data.results;
30+ setData(results);
31+ // Extract unique dataset names with proper typing
32+ const datasets = Array.from(new Set(results.map((result: BenchmarkResult) => result.dataset))).sort() as string[];
33+ setAvailableDatasets(datasets);
34+ } catch (error) {
35+ const message = error instanceof Error ? error.message : 'Failed to fetch data';
36+ setError(message);
37+ console.error('Error fetching benchmark data:', error);
38+ } finally {
39+ setIsLoading(false);
40+ }
41+ };
42+
43+ fetchData();
44+ }, []);
45+
46+ // Memoize filtered data to prevent unnecessary recalculations
47+ const filteredData = useMemo(() => {
48+ if (!selectedDataset) return data;
49+ return data.filter(row => row.dataset === selectedDataset);
50+ }, [data, selectedDataset]);
51+
52+ const table = useReactTable({
53+ data: filteredData || [],
54+ columns,
55+ getCoreRowModel: getCoreRowModel(),
56+ getSortedRowModel: getSortedRowModel(),
57+ });
58+
59+ // Prepare data for bar charts when a dataset is selected
60+ const chartData = useMemo(() => {
61+ if (!selectedDataset) return [];
62+ return data
63+ .filter(row => row.dataset === selectedDataset)
64+ .map(row => ({
65+ algorithm: row.algorithm,
66+ compression_ratio: row.compression_ratio,
67+ encode_speed: row.encode_mb_per_sec,
68+ decode_speed: row.decode_mb_per_sec
69+ }));
70+ }, [data, selectedDataset]);
71+
72+ if (isLoading) {
73+ return <div>Loading benchmark data...</div>;
74+ }
75+
76+ if (error) {
77+ return <div>Error: {error}</div>;
78+ }
79+
80+ return (
81+ <div className="table-container">
82+ <div style={{ marginBottom: '20px', display: 'flex', alignItems: 'center', gap: '10px', justifyContent: 'space-between' }}>
83+ <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
84+ <label htmlFor="dataset-select">Filter by Dataset:</label>
85+ <select
86+ id="dataset-select"
87+ value={selectedDataset}
88+ onChange={(e) => setSelectedDataset(e.target.value)}
89+ style={{
90+ padding: '8px',
91+ borderRadius: '4px',
92+ border: '1px solid #ccc',
93+ minWidth: '200px',
94+ backgroundColor: '#fff'
95+ }}
96+ >
97+ <option value="">All Datasets</option>
98+ {availableDatasets.map(dataset => (
99+ <option key={dataset} value={dataset}>
100+ {dataset}
101+ </option>
102+ ))}
103+ </select>
104+ </div>
105+ <button
106+ onClick={() => exportToCsv(filteredData, selectedDataset)}
107+ style={{
108+ padding: '8px 16px',
109+ backgroundColor: '#4CAF50',
110+ color: 'white',
111+ border: 'none',
112+ borderRadius: '4px',
113+ cursor: 'pointer',
114+ display: 'flex',
115+ alignItems: 'center',
116+ gap: '8px'
117+ }}
118+ >
119+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
120+ <path d="M8 12L3 7H6V1H10V7H13L8 12Z" fill="currentColor"/>
121+ <path d="M2 14V15H14V14H2Z" fill="currentColor"/>
122+ </svg>
123+ Download CSV
124+ </button>
125+ </div>
126+
127+ {selectedDataset && chartData.length > 0 && (
128+ <BenchmarkCharts chartData={chartData} />
129+ )}
130+
131+ <table>
132+ <thead>
133+ {table.getHeaderGroups().map(headerGroup => (
134+ <tr key={headerGroup.id}>
135+ {headerGroup.headers.map(header => (
136+ <th
137+ key={header.id}
138+ onClick={header.column.getToggleSortingHandler()}
139+ style={{ cursor: 'pointer' }}
140+ >
141+ {flexRender(
142+ header.column.columnDef.header,
143+ header.getContext()
144+ )}
145+ {header.column.getIsSorted() && (
146+ <span style={{ marginLeft: '4px' }}>
147+ {header.column.getIsSorted() === 'asc' ? '↑' : '↓'}
148+ </span>
149+ )}
150+ </th>
151+ ))}
152+ </tr>
153+ ))}
154+ </thead>
155+ <tbody>
156+ {table.getRowModel().rows.map(row => (
157+ <tr key={row.id}>
158+ {row.getVisibleCells().map(cell => (
159+ <td key={cell.id}>
160+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
161+ </td>
162+ ))}
163+ </tr>
164+ ))}
165+ </tbody>
166+ </table>
167+ </div>
168+ );
169+}
web-ui/src/components/benchmark/table/columns.tsxadded+79−0View file
@@ -0,0 +1,79 @@
1+import { createColumnHelper } from '@tanstack/react-table';
2+import { BenchmarkResult } from '../../../types';
3+import { formatNumber, formatSize } from '../utils/formatters';
4+
5+const columnHelper = createColumnHelper<BenchmarkResult>();
6+
7+export const columns = [
8+ columnHelper.accessor('dataset', {
9+ header: 'Dataset',
10+ cell: info => info.getValue(),
11+ }),
12+ columnHelper.accessor('algorithm', {
13+ header: 'Algorithm',
14+ cell: info => info.getValue(),
15+ }),
16+ columnHelper.accessor('compression_ratio', {
17+ header: 'Compression Ratio',
18+ cell: info => `${formatNumber(info.getValue())}x`,
19+ sortingFn: (rowA, rowB) => {
20+ const a = rowA.original.compression_ratio;
21+ const b = rowB.original.compression_ratio;
22+ return a - b;
23+ },
24+ }),
25+ columnHelper.accessor('encode_time', {
26+ header: 'Encode Time (s)',
27+ cell: info => formatNumber(info.getValue(), 4),
28+ sortingFn: (rowA, rowB) => {
29+ const a = rowA.original.encode_time;
30+ const b = rowB.original.encode_time;
31+ return a - b;
32+ },
33+ }),
34+ columnHelper.accessor('decode_time', {
35+ header: 'Decode Time (s)',
36+ cell: info => formatNumber(info.getValue(), 4),
37+ sortingFn: (rowA, rowB) => {
38+ const a = rowA.original.decode_time;
39+ const b = rowB.original.decode_time;
40+ return a - b;
41+ },
42+ }),
43+ columnHelper.accessor('encode_mb_per_sec', {
44+ header: 'Encode Speed (MB/s)',
45+ cell: info => formatNumber(info.getValue()),
46+ sortingFn: (rowA, rowB) => {
47+ const a = rowA.original.encode_mb_per_sec;
48+ const b = rowB.original.encode_mb_per_sec;
49+ return a - b;
50+ },
51+ }),
52+ columnHelper.accessor('decode_mb_per_sec', {
53+ header: 'Decode Speed (MB/s)',
54+ cell: info => formatNumber(info.getValue()),
55+ sortingFn: (rowA, rowB) => {
56+ const a = rowA.original.decode_mb_per_sec;
57+ const b = rowB.original.decode_mb_per_sec;
58+ return a - b;
59+ },
60+ }),
61+ columnHelper.accessor('original_size', {
62+ header: 'Original Size',
63+ cell: info => formatSize(info.getValue()),
64+ sortingFn: (rowA, rowB) => {
65+ const a = rowA.original.original_size;
66+ const b = rowB.original.original_size;
67+ return a - b;
68+ },
69+ }),
70+ columnHelper.accessor('compressed_size', {
71+ header: 'Compressed Size',
72+ cell: info => formatSize(info.getValue()),
73+ sortingFn: (rowA, rowB) => {
74+ const a = rowA.original.compressed_size;
75+ const b = rowB.original.compressed_size;
76+ return a - b;
77+ },
78+ }),
79+];
web-ui/src/components/benchmark/utils/formatters.tsadded+11−0View file
@@ -0,0 +1,11 @@
1+export const formatNumber = (num: number, decimals = 2) => {
2+ return new Intl.NumberFormat('en-US', {
3+ minimumFractionDigits: decimals,
4+ maximumFractionDigits: decimals,
5+ }).format(num);
6+};
7+
8+export const formatSize = (bytes: number) => {
9+ const mb = bytes / (1024 * 1024);
10+ return `${formatNumber(mb)} MB`;
11+};
zia_benchmark/setup.pymodified+2−1View file
@@ -9,7 +9,8 @@ setup(
99 "numpy",
1010 "zstandard",
1111 "simple_ans",
12- "requests"
12+ "requests",
13+ "lindi"
1314 ],
1415 python_requires=">=3.8",
1516 author="Jeremy Magland",
zia_benchmark/src/zia_benchmark/_data_loaders.pymodified+18−0View file
@@ -1,6 +1,9 @@
1+"""Data loading utilities."""
2+
13 import numpy as np
24 import lindi
35 from typing import cast
6+import warnings
47
58
69 def load_real_000876(*, num_samples: int, num_channels: int, start_channel: int) -> np.ndarray:
@@ -14,6 +17,11 @@ def load_real_000876(*, num_samples: int, num_channels: int, start_channel: int)
1417 Returns:
1518 Array of shape (num_samples, num_channels) containing the loaded data
1619 """
20+ warnings.warn(
21+ "This function is deprecated. Use datasets['real-000876-ch45']['create']() instead.",
22+ DeprecationWarning,
23+ stacklevel=2
24+ )
1725 nwb_url = "https://api.dandiarchive.org/api/assets/7e1de06d-d478-40e2-9b64-9dd04eafaa4c/download/"
1826 h5f = lindi.LindiH5pyFile.from_hdf5_file(nwb_url)
1927 ds = h5f["/acquisition/ElectricalSeriesAP/data"]
@@ -33,6 +41,11 @@ def load_real_000409(*, num_samples: int, num_channels: int, start_channel: int)
3341 Returns:
3442 Array of shape (num_samples, num_channels) containing the loaded data
3543 """
44+ warnings.warn(
45+ "This function is deprecated. Use datasets['real-000409-ch101']['create']() instead.",
46+ DeprecationWarning,
47+ stacklevel=2
48+ )
3649 nwb_url = "https://api.dandiarchive.org/api/assets/c04f6b30-82bf-40e1-9210-34f0bcd8be24/download/"
3750 h5f = lindi.LindiH5pyFile.from_hdf5_file(nwb_url)
3851 ds = h5f['/acquisition/ElectricalSeriesAp/data']
@@ -52,6 +65,11 @@ def load_real_001290(*, num_samples: int, num_channels: int, start_channel: int)
5265 Returns:
5366 Array of shape (num_samples, num_channels) containing the loaded data
5467 """
68+ warnings.warn(
69+ "This function is deprecated. Use datasets['real-001290-ch0']['create']() instead.",
70+ DeprecationWarning,
71+ stacklevel=2
72+ )
5573 nwb_url = "https://api.dandiarchive.org/api/assets/78c99d23-da88-4ecd-9086-c488a126eac5/download/"
5674 h5f = lindi.LindiH5pyFile.from_hdf5_file(nwb_url)
5775 ds = h5f['/acquisition/ElectricalSeriesAPImec/data']
zia_benchmark/src/zia_benchmark/datasets/__init__.pymodified+2−1View file
@@ -1,4 +1,5 @@
11 from .bernoulli import datasets as bernoulli_datasets
22 from .gaussian import datasets as gaussian_datasets
3+from .real import datasets as real_datasets
34
4-datasets = bernoulli_datasets + gaussian_datasets
5+datasets = bernoulli_datasets + gaussian_datasets + real_datasets
zia_benchmark/src/zia_benchmark/datasets/real/__init__.pyadded+82−0View file
@@ -0,0 +1,82 @@
1+import numpy as np
2+import lindi
3+from typing import cast
4+
5+
6+def _load_real_000876(*, num_samples: int, num_channels: int, start_channel: int) -> np.ndarray:
7+ """Load data from DANDI dataset 000876.
8+
9+ Args:
10+ num_samples: Number of samples to load
11+ num_channels: Number of channels to load
12+ start_channel: Starting channel index
13+
14+ Returns:
15+ Array of shape (num_samples, num_channels) containing the loaded data
16+ """
17+ nwb_url = "https://api.dandiarchive.org/api/assets/7e1de06d-d478-40e2-9b64-9dd04eafaa4c/download/"
18+ h5f = lindi.LindiH5pyFile.from_hdf5_file(nwb_url)
19+ ds = h5f["/acquisition/ElectricalSeriesAP/data"]
20+ assert isinstance(ds, lindi.LindiH5pyDataset)
21+ ret = ds[:num_samples, start_channel:start_channel + num_channels]
22+ return cast(np.ndarray, ret)
23+
24+
25+def _load_real_000409(*, num_samples: int, num_channels: int, start_channel: int) -> np.ndarray:
26+ """Load data from DANDI dataset 000409.
27+
28+ Args:
29+ num_samples: Number of samples to load
30+ num_channels: Number of channels to load
31+ start_channel: Starting channel index
32+
33+ Returns:
34+ Array of shape (num_samples, num_channels) containing the loaded data
35+ """
36+ nwb_url = "https://api.dandiarchive.org/api/assets/c04f6b30-82bf-40e1-9210-34f0bcd8be24/download/"
37+ h5f = lindi.LindiH5pyFile.from_hdf5_file(nwb_url)
38+ ds = h5f['/acquisition/ElectricalSeriesAp/data']
39+ assert isinstance(ds, lindi.LindiH5pyDataset)
40+ ret = ds[:num_samples, start_channel:start_channel + num_channels]
41+ return cast(np.ndarray, ret)
42+
43+
44+def _load_real_001290(*, num_samples: int, num_channels: int, start_channel: int) -> np.ndarray:
45+ """Load data from DANDI dataset 001290.
46+
47+ Args:
48+ num_samples: Number of samples to load
49+ num_channels: Number of channels to load
50+ start_channel: Starting channel index
51+
52+ Returns:
53+ Array of shape (num_samples, num_channels) containing the loaded data
54+ """
55+ nwb_url = "https://api.dandiarchive.org/api/assets/78c99d23-da88-4ecd-9086-c488a126eac5/download/"
56+ h5f = lindi.LindiH5pyFile.from_hdf5_file(nwb_url)
57+ ds = h5f['/acquisition/ElectricalSeriesAPImec/data']
58+ assert isinstance(ds, lindi.LindiH5pyDataset)
59+ ret = ds[:num_samples, start_channel:start_channel + num_channels]
60+ return cast(np.ndarray, ret)
61+
62+
63+datasets = [
64+ {
65+ 'name': 'real-000876-ch45',
66+ 'version': '1',
67+ 'description': 'Real neurophysiology data from DANDI:000876, channel 45',
68+ 'create': lambda: _load_real_000876(num_samples=500_000, num_channels=1, start_channel=45).flatten()
69+ },
70+ {
71+ 'name': 'real-000409-ch101',
72+ 'version': '1',
73+ 'description': 'Real neurophysiology data from DANDI:000409, channel 101',
74+ 'create': lambda: _load_real_000409(num_samples=500_000, num_channels=1, start_channel=101).flatten()
75+ },
76+ {
77+ 'name': 'real-001290-ch0',
78+ 'version': '1',
79+ 'description': 'Real neurophysiology data from DANDI:001290, channel 0',
80+ 'create': lambda: _load_real_001290(num_samples=500_000, num_channels=1, start_channel=0).flatten()
81+ }
82+]
zia_benchmark/src/zia_benchmark/run_benchmarks.pymodified+8−1View file
@@ -56,9 +56,16 @@ def run_benchmarks(cache_dir: str = '.benchmark_cache', verbose: bool = True) ->
5656
5757 # First try local cache
5858 cached_data = None
59- if os.path.exists(metadata_file) and os.path.exists(compressed_file):
59+ if os.path.exists(metadata_file):
6060 with open(metadata_file, 'r') as f:
6161 cached_data = json.load(f)
62+ # if versions do not match, then set to None
63+ if (
64+ cached_data['result']['algorithm_version'] != algorithm['version'] or
65+ cached_data['result']['dataset_version'] != dataset['version'] or
66+ cached_data['result'].get('system_version', '') != system_version
67+ ):
68+ cached_data = None
6269
6370 # If not in local cache, try memobin
6471 if cached_data is None:
moveopenescclose