jupyterlab_tabular_data_viewer_extension 1.2.13 → 1.2.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/lib/modal.js +1 -1
- package/lib/widget.js +28 -5
- package/package.json +1 -1
- package/src/modal.ts +1 -1
- package/src/widget.ts +31 -5
- package/style/base.css +12 -0
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# jupyterlab_tabular_data_viewer_extension
|
|
2
2
|
|
|
3
|
-

|
|
4
|
-
[](https://github.com/stellarshenson/jupyterlab_tabular_data_viewer_extension/actions/workflows/build.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/jupyterlab_tabular_data_viewer_extension)
|
|
5
|
+
[](https://pypi.org/project/jupyterlab-tabular-data-viewer-extension/)
|
|
6
6
|
[](https://pepy.tech/project/jupyterlab-tabular-data-viewer-extension)
|
|
7
|
-
](https://jupyterlab.readthedocs.io/en/stable/)
|
|
8
8
|
|
|
9
9
|
View and browse Parquet, Excel, CSV, and TSV files directly in JupyterLab. Double-click any .parquet, .xlsx, .csv, or .tsv file to open it in a simple, spreadsheet-like table view - no code required. Navigate through your data, inspect values, and explore the structure of your tabular data files with interactive column resizing and advanced filtering capabilities.
|
|
10
10
|
|
|
@@ -50,7 +50,7 @@ View and browse Parquet, Excel, CSV, and TSV files directly in JupyterLab. Doubl
|
|
|
50
50
|
- Multiple filters work together to narrow down results
|
|
51
51
|
|
|
52
52
|
**Additional features:**
|
|
53
|
-
- Column statistics modal - View comprehensive statistics including data type, row counts, null values, unique counts, and type-specific metrics (numeric: min/max/mean/median/std dev/outliers
|
|
53
|
+
- Column statistics modal - View comprehensive statistics including data type, row counts, null values, unique counts, and type-specific metrics (numeric: min/max/mean/median/std dev/outliers; string: most common value/length stats; date: earliest/latest dates). Copy statistics as JSON with one click
|
|
54
54
|
- Right-click context menu on rows to copy data as JSON
|
|
55
55
|
- Configurable file type support via Settings - Enable/disable Parquet, Excel, or CSV/TSV handling
|
|
56
56
|
- All features work seamlessly across all supported file formats
|
package/lib/modal.js
CHANGED
|
@@ -82,7 +82,7 @@ export class ColumnStatsModal extends Widget {
|
|
|
82
82
|
items.push(`Std Dev: ${this._formatNumber(this._stats.std_dev)}`);
|
|
83
83
|
}
|
|
84
84
|
if (this._stats.outlier_count !== undefined) {
|
|
85
|
-
items.push(`Outliers
|
|
85
|
+
items.push(`Outliers: ${this._formatNumber(this._stats.outlier_count)} (${this._stats.outlier_percentage}%)`);
|
|
86
86
|
}
|
|
87
87
|
numericList.innerHTML = items.map(item => `<li>${item}</li>`).join('');
|
|
88
88
|
numericSection.appendChild(numericList);
|
package/lib/widget.js
CHANGED
|
@@ -261,7 +261,9 @@ export class TabularDataViewer extends Widget {
|
|
|
261
261
|
if (reset) {
|
|
262
262
|
this._totalRows = response.totalRows;
|
|
263
263
|
}
|
|
264
|
-
|
|
264
|
+
// Calculate starting row number (1-indexed)
|
|
265
|
+
const startingRowNumber = this._data.length - response.data.length + 1;
|
|
266
|
+
this._renderData(response.data, startingRowNumber);
|
|
265
267
|
this._updateStatusBar();
|
|
266
268
|
}
|
|
267
269
|
catch (error) {
|
|
@@ -277,6 +279,22 @@ export class TabularDataViewer extends Widget {
|
|
|
277
279
|
_renderHeaders() {
|
|
278
280
|
this._filterRow.innerHTML = '';
|
|
279
281
|
this._headerRow.innerHTML = '';
|
|
282
|
+
// Add row number column header
|
|
283
|
+
const rowNumFilterCell = document.createElement('th');
|
|
284
|
+
rowNumFilterCell.className = 'jp-TabularDataViewer-filterCell jp-TabularDataViewer-rowNumberCell';
|
|
285
|
+
this._filterRow.appendChild(rowNumFilterCell);
|
|
286
|
+
const rowNumHeaderCell = document.createElement('th');
|
|
287
|
+
rowNumHeaderCell.className = 'jp-TabularDataViewer-headerCell jp-TabularDataViewer-rowNumberCell';
|
|
288
|
+
const rowNumContent = document.createElement('div');
|
|
289
|
+
rowNumContent.className = 'jp-TabularDataViewer-headerContent';
|
|
290
|
+
const rowNumName = document.createElement('div');
|
|
291
|
+
rowNumName.className = 'jp-TabularDataViewer-columnName';
|
|
292
|
+
rowNumName.textContent = '';
|
|
293
|
+
rowNumContent.appendChild(rowNumName);
|
|
294
|
+
rowNumHeaderCell.appendChild(rowNumContent);
|
|
295
|
+
rowNumHeaderCell.style.width = '60px';
|
|
296
|
+
rowNumFilterCell.style.width = '60px';
|
|
297
|
+
this._headerRow.appendChild(rowNumHeaderCell);
|
|
280
298
|
this._columns.forEach(col => {
|
|
281
299
|
// Create filter cell
|
|
282
300
|
const filterCell = document.createElement('th');
|
|
@@ -352,17 +370,22 @@ export class TabularDataViewer extends Widget {
|
|
|
352
370
|
filterCell.style.width = `${columnWidth}px`;
|
|
353
371
|
this._headerRow.appendChild(headerCell);
|
|
354
372
|
});
|
|
355
|
-
// Set table width to sum of all column widths
|
|
356
|
-
const totalWidth = Array.from(this._columnWidths.values()).reduce((sum, w) => sum + w, 0);
|
|
373
|
+
// Set table width to sum of all column widths plus row number column (60px)
|
|
374
|
+
const totalWidth = Array.from(this._columnWidths.values()).reduce((sum, w) => sum + w, 0) + 60;
|
|
357
375
|
this._table.style.width = `${totalWidth}px`;
|
|
358
376
|
}
|
|
359
377
|
/**
|
|
360
378
|
* Render data rows
|
|
361
379
|
*/
|
|
362
|
-
_renderData(rows) {
|
|
363
|
-
rows.forEach(row => {
|
|
380
|
+
_renderData(rows, startingRowNumber = 1) {
|
|
381
|
+
rows.forEach((row, index) => {
|
|
364
382
|
const tr = document.createElement('tr');
|
|
365
383
|
tr.className = 'jp-TabularDataViewer-row';
|
|
384
|
+
// Add row number cell
|
|
385
|
+
const rowNumCell = document.createElement('td');
|
|
386
|
+
rowNumCell.className = 'jp-TabularDataViewer-cell jp-TabularDataViewer-rowNumberCell';
|
|
387
|
+
rowNumCell.textContent = String(startingRowNumber + index);
|
|
388
|
+
tr.appendChild(rowNumCell);
|
|
366
389
|
this._columns.forEach(col => {
|
|
367
390
|
const td = document.createElement('td');
|
|
368
391
|
td.className = 'jp-TabularDataViewer-cell';
|
package/package.json
CHANGED
package/src/modal.ts
CHANGED
|
@@ -95,7 +95,7 @@ export class ColumnStatsModal extends Widget {
|
|
|
95
95
|
items.push(`Std Dev: ${this._formatNumber(this._stats.std_dev)}`);
|
|
96
96
|
}
|
|
97
97
|
if (this._stats.outlier_count !== undefined) {
|
|
98
|
-
items.push(`Outliers
|
|
98
|
+
items.push(`Outliers: ${this._formatNumber(this._stats.outlier_count)} (${this._stats.outlier_percentage}%)`);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
numericList.innerHTML = items.map(item => `<li>${item}</li>`).join('');
|
package/src/widget.ts
CHANGED
|
@@ -292,7 +292,9 @@ export class TabularDataViewer extends Widget {
|
|
|
292
292
|
this._totalRows = response.totalRows;
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
-
|
|
295
|
+
// Calculate starting row number (1-indexed)
|
|
296
|
+
const startingRowNumber = this._data.length - response.data.length + 1;
|
|
297
|
+
this._renderData(response.data, startingRowNumber);
|
|
296
298
|
this._updateStatusBar();
|
|
297
299
|
} catch (error) {
|
|
298
300
|
this._showError(`Failed to load data: ${error}`);
|
|
@@ -308,6 +310,24 @@ export class TabularDataViewer extends Widget {
|
|
|
308
310
|
this._filterRow.innerHTML = '';
|
|
309
311
|
this._headerRow.innerHTML = '';
|
|
310
312
|
|
|
313
|
+
// Add row number column header
|
|
314
|
+
const rowNumFilterCell = document.createElement('th');
|
|
315
|
+
rowNumFilterCell.className = 'jp-TabularDataViewer-filterCell jp-TabularDataViewer-rowNumberCell';
|
|
316
|
+
this._filterRow.appendChild(rowNumFilterCell);
|
|
317
|
+
|
|
318
|
+
const rowNumHeaderCell = document.createElement('th');
|
|
319
|
+
rowNumHeaderCell.className = 'jp-TabularDataViewer-headerCell jp-TabularDataViewer-rowNumberCell';
|
|
320
|
+
const rowNumContent = document.createElement('div');
|
|
321
|
+
rowNumContent.className = 'jp-TabularDataViewer-headerContent';
|
|
322
|
+
const rowNumName = document.createElement('div');
|
|
323
|
+
rowNumName.className = 'jp-TabularDataViewer-columnName';
|
|
324
|
+
rowNumName.textContent = '';
|
|
325
|
+
rowNumContent.appendChild(rowNumName);
|
|
326
|
+
rowNumHeaderCell.appendChild(rowNumContent);
|
|
327
|
+
rowNumHeaderCell.style.width = '60px';
|
|
328
|
+
rowNumFilterCell.style.width = '60px';
|
|
329
|
+
this._headerRow.appendChild(rowNumHeaderCell);
|
|
330
|
+
|
|
311
331
|
this._columns.forEach(col => {
|
|
312
332
|
// Create filter cell
|
|
313
333
|
const filterCell = document.createElement('th');
|
|
@@ -398,19 +418,25 @@ export class TabularDataViewer extends Widget {
|
|
|
398
418
|
this._headerRow.appendChild(headerCell);
|
|
399
419
|
});
|
|
400
420
|
|
|
401
|
-
// Set table width to sum of all column widths
|
|
402
|
-
const totalWidth = Array.from(this._columnWidths.values()).reduce((sum, w) => sum + w, 0);
|
|
421
|
+
// Set table width to sum of all column widths plus row number column (60px)
|
|
422
|
+
const totalWidth = Array.from(this._columnWidths.values()).reduce((sum, w) => sum + w, 0) + 60;
|
|
403
423
|
this._table.style.width = `${totalWidth}px`;
|
|
404
424
|
}
|
|
405
425
|
|
|
406
426
|
/**
|
|
407
427
|
* Render data rows
|
|
408
428
|
*/
|
|
409
|
-
private _renderData(rows: any[]): void {
|
|
410
|
-
rows.forEach(row => {
|
|
429
|
+
private _renderData(rows: any[], startingRowNumber: number = 1): void {
|
|
430
|
+
rows.forEach((row, index) => {
|
|
411
431
|
const tr = document.createElement('tr');
|
|
412
432
|
tr.className = 'jp-TabularDataViewer-row';
|
|
413
433
|
|
|
434
|
+
// Add row number cell
|
|
435
|
+
const rowNumCell = document.createElement('td');
|
|
436
|
+
rowNumCell.className = 'jp-TabularDataViewer-cell jp-TabularDataViewer-rowNumberCell';
|
|
437
|
+
rowNumCell.textContent = String(startingRowNumber + index);
|
|
438
|
+
tr.appendChild(rowNumCell);
|
|
439
|
+
|
|
414
440
|
this._columns.forEach(col => {
|
|
415
441
|
const td = document.createElement('td');
|
|
416
442
|
td.className = 'jp-TabularDataViewer-cell';
|
package/style/base.css
CHANGED
|
@@ -168,6 +168,18 @@
|
|
|
168
168
|
box-sizing: border-box;
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
/* Row Number Cell */
|
|
172
|
+
.jp-TabularDataViewer-rowNumberCell {
|
|
173
|
+
text-align: center;
|
|
174
|
+
background-color: var(--jp-layout-color2);
|
|
175
|
+
color: var(--jp-ui-font-color2);
|
|
176
|
+
font-weight: 500;
|
|
177
|
+
user-select: none;
|
|
178
|
+
min-width: 60px;
|
|
179
|
+
max-width: 60px;
|
|
180
|
+
width: 60px;
|
|
181
|
+
}
|
|
182
|
+
|
|
171
183
|
.jp-TabularDataViewer-cell:last-child {
|
|
172
184
|
border-right: none;
|
|
173
185
|
}
|