From a7ae29ef13409cee65509857e01ea39d18861d4a Mon Sep 17 00:00:00 2001 From: Jerome Dockes Date: Tue, 10 Sep 2024 18:00:37 +0200 Subject: [PATCH 01/11] add sorting of the summary statistics table --- skrub/_reporting/_data/templates/report.js | 70 +++++++++++++++++- .../_data/templates/summary-statistics.html | 72 ++++++++++++------- 2 files changed, 112 insertions(+), 30 deletions(-) diff --git a/skrub/_reporting/_data/templates/report.js b/skrub/_reporting/_data/templates/report.js index b127a44bd..fae5dad01 100644 --- a/skrub/_reporting/_data/templates/report.js +++ b/skrub/_reporting/_data/templates/report.js @@ -266,7 +266,7 @@ if (customElements.get('skrub-table-report') === undefined) { return; } event.clipboardData.setData("text/plain", this.elem.dataset - .valueRepr); + .valueRepr); event.preventDefault(); this.elem.dataset.justCopied = ""; setTimeout(() => this.elem.removeAttribute("data-just-copied"), 1000); @@ -303,7 +303,9 @@ if (customElements.get('skrub-table-report') === undefined) { if (msg.cellId === this.elem.id) { this.elem.dataset.isActive = ""; this.elem.setAttribute("tabindex", 0); - this.elem.focus({focusVisible: true}); + this.elem.focus({ + focusVisible: true + }); } else { delete this.elem.dataset.isActive; this.elem.setAttribute("tabindex", -1); @@ -427,6 +429,67 @@ if (customElements.get('skrub-table-report') === undefined) { } SkrubTableReport.register(TabList); + class sortableTable extends Manager { + constructor(elem, exchange) { + super(elem, exchange); + this.elem.querySelectorAll("button[data-role='sort-button']").forEach( + b => b.addEventListener("click", e => this.sort(e))); + } + + getVal(row, colIdx) { + const td = row.querySelectorAll("td")[colIdx]; + if (!td.hasAttribute("data-value")) { + return td.textContent; + } + let value = td.dataset.value; + if (td.hasAttribute("data-numeric")) { + value = Number(value); + } + return value; + } + + compare(rowA, rowB, colIdx, ascending) { + let valA = this.getVal(rowA, colIdx); + let valB = this.getVal(rowB, colIdx); + if(typeof(valA) === "number" && typeof(valB) === "number"){ + if(isNaN(valA) && !isNaN(valB)){ + return 1; + } + if(isNaN(valB) && !isNaN(valA)){ + return -1; + } + } + if (!(valA > valB || valB > valA)) { + valA = Number(rowA.dataset.columnIdx); + valB = Number(rowB.dataset.columnIdx); + return valA - valB; + } + if (!ascending) { + [valA, valB] = [valB, valA]; + } + return valA > valB ? 1 : -1; + } + + sort(event) { + const headerRow = this.elem.querySelector("thead tr"); + const colHeaders = Array.from(headerRow.querySelectorAll("th")); + const colIdx = colHeaders.findIndex(th => Array.from(th.childNodes) + .includes(event.target)); + const body = this.elem.querySelector("tbody"); + const rows = Array.from(body.querySelectorAll("tr")); + const ascending = event.target.dataset.direction === "ascending"; + + rows.sort((a, b) => this.compare(a, b, colIdx, ascending)); + + body.innerHTML = ""; + for (let r of rows) { + body.appendChild(r); + } + } + + } + SkrubTableReport.register(sortableTable); + class SelectedColumnsDisplay extends Manager { constructor(elem, exchange) { @@ -517,7 +580,8 @@ if (customElements.get('skrub-table-report') === undefined) { return; } if (navigator.clipboard) { - navigator.clipboard.writeText( elem.dataset.copyText || elem.textContent || ""); + navigator.clipboard.writeText(elem.dataset.copyText || elem.textContent || + ""); } else { // fallback when navigator not available. in this case we just copy // the text content of the element (we could create a hidden one to diff --git a/skrub/_reporting/_data/templates/summary-statistics.html b/skrub/_reporting/_data/templates/summary-statistics.html index 327447edb..13170d97e 100644 --- a/skrub/_reporting/_data/templates/summary-statistics.html +++ b/skrub/_reporting/_data/templates/summary-statistics.html @@ -1,57 +1,75 @@ +{% macro th(name, ascending, descending) %} + + {% if name %} + {{ name }} + {% endif %} + + + +{% endmacro %} + +{% macro th1(name, low, high) %} +{{ th(name, "from columns with " + low + " to columns with " + high, "from columns with " + high + " to columns with " + low) }} +{% endmacro %} +
- +
- - - - - - - - - + {{ th("", "from first column to last column", "from last column to first column") }} + {{ th("Column name", "by column name from A to Z", "by column name from Z to A") }} + {{ th("dtype", "by dtype from A to Z", "by dtype from Z to A") }} + {{ th1("Null values", "the fewest null values", "the most null values") }} + {{ th1("Unique values", "the fewest unique values", "the most unique values") }} + {{ th1("Mean", "the lowest mean", "the highest mean") }} + {{ th1("Std", "the lowest standard deviation", "the highest standard deviation") }} + {{ th1("Min", "the lowest minimum value", "the highest minimum value") }} + {{ th1("Median", "the lowest median", "the highest median") }} + {{ th1("Max", "the lowest maximum value", "the highest maximum value") }} {% for column in summary.columns %} + data-column-name="{{ column.name }}" + data-column-idx="{{ loop.index0 }}"> + - {% if column.n_unique %} - {% else %} - + {% endif %} {% if "mean" in column %} - - + + {% else %} - - + + {% endif %} {% if column.quantiles %} - - - + + + {% elif "min" in column %} - - - + + + {% else %} - - - + + + {% endif %} From 62d74aa1ca385353f8ef4ce4d2349a9dfff68405 Mon Sep 17 00:00:00 2001 From: Jerome Dockes Date: Tue, 10 Sep 2024 18:02:59 +0200 Subject: [PATCH 02/11] _ --- examples/00_getting_started.py | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/00_getting_started.py b/examples/00_getting_started.py index ca6603948..8f42c2296 100644 --- a/examples/00_getting_started.py +++ b/examples/00_getting_started.py @@ -2,7 +2,6 @@ Getting Started =============== - This guide showcases the features of ``skrub``, an open-source package that aims at bridging the gap between tabular data sources and machine-learning models. From 70787cf8c5712c0f6b1c855c73c0615ba3f8667f Mon Sep 17 00:00:00 2001 From: Jerome Dockes Date: Wed, 11 Sep 2024 14:36:33 +0200 Subject: [PATCH 03/11] buttons display --- .../_data/templates/icons/arrow-down.svg | 3 ++ .../_data/templates/icons/arrow-up.svg | 3 ++ skrub/_reporting/_data/templates/report.css | 1 + skrub/_reporting/_data/templates/report.js | 4 +- .../_data/templates/summary-statistics.css | 53 +++++++++++++++++++ .../_data/templates/summary-statistics.html | 14 +++-- 6 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 skrub/_reporting/_data/templates/icons/arrow-down.svg create mode 100644 skrub/_reporting/_data/templates/icons/arrow-up.svg create mode 100644 skrub/_reporting/_data/templates/summary-statistics.css diff --git a/skrub/_reporting/_data/templates/icons/arrow-down.svg b/skrub/_reporting/_data/templates/icons/arrow-down.svg new file mode 100644 index 000000000..afba641b5 --- /dev/null +++ b/skrub/_reporting/_data/templates/icons/arrow-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/skrub/_reporting/_data/templates/icons/arrow-up.svg b/skrub/_reporting/_data/templates/icons/arrow-up.svg new file mode 100644 index 000000000..91c4ccc9c --- /dev/null +++ b/skrub/_reporting/_data/templates/icons/arrow-up.svg @@ -0,0 +1,3 @@ + + + diff --git a/skrub/_reporting/_data/templates/report.css b/skrub/_reporting/_data/templates/report.css index b8b4f8823..7ca0fb644 100644 --- a/skrub/_reporting/_data/templates/report.css +++ b/skrub/_reporting/_data/templates/report.css @@ -5,6 +5,7 @@ {% include "copybutton.css" %} {% include "column-summaries.css" %} {% include "dataframe-sample.css" %} +{% include "summary-statistics.css" %} {% include "tabs.css" %} {% include "tooltip.css" %} {% include "column-filter.css" %} diff --git a/skrub/_reporting/_data/templates/report.js b/skrub/_reporting/_data/templates/report.js index fae5dad01..a3942aa2b 100644 --- a/skrub/_reporting/_data/templates/report.js +++ b/skrub/_reporting/_data/templates/report.js @@ -473,7 +473,7 @@ if (customElements.get('skrub-table-report') === undefined) { sort(event) { const headerRow = this.elem.querySelector("thead tr"); const colHeaders = Array.from(headerRow.querySelectorAll("th")); - const colIdx = colHeaders.findIndex(th => Array.from(th.childNodes) + const colIdx = colHeaders.findIndex(th => Array.from(th.querySelectorAll("button")) .includes(event.target)); const body = this.elem.querySelector("tbody"); const rows = Array.from(body.querySelectorAll("tr")); @@ -481,6 +481,8 @@ if (customElements.get('skrub-table-report') === undefined) { rows.sort((a, b) => this.compare(a, b, colIdx, ascending)); + this.elem.querySelectorAll("button").forEach(b => b.removeAttribute("data-is-active")); + event.target.dataset.isActive = ""; body.innerHTML = ""; for (let r of rows) { body.appendChild(r); diff --git a/skrub/_reporting/_data/templates/summary-statistics.css b/skrub/_reporting/_data/templates/summary-statistics.css new file mode 100644 index 000000000..bd0b80567 --- /dev/null +++ b/skrub/_reporting/_data/templates/summary-statistics.css @@ -0,0 +1,53 @@ +th.sort-button-group-wrapper { + --btn-width: 2rem; + --btn-group-width: calc(var(--btn-width) * 2); + position: relative; + padding-top: var(--micro); + padding-bottom: var(--micro); + padding-right: calc(var(--tiny) + var(--btn-group-width)); +} + +.sort-button-group { + position: absolute; + top: 0; + bottom: 0; + right: calc(-1 * var(--btn-group-width)); + left: 100%; + transform: translateX(calc(-1 * var(--btn-group-width) + 1px)); + display: flex; + background: #999; + gap: 0px; + padding: 0px; + padding-bottom: 1px; +} + +.sort-button { + margin: 0; + box-sizing: border-box; + height: 100%; + flex-grow: 1; + border-radius: 0; + border: 1px solid #aaa; + border-bottom: none; + background: #e0e0e0; + color: #222; + padding: var(--tiny); + transform: translateY(-1px); +} + +.sort-button-group > .sort-button ~ .sort-button { + margin-left: -1px; +} + +.sort-button:active { + transform: none; +} + +.sort-button:hover { + background: #eeeeee; +} + +.sort-button[data-is-active]{ + background: var(--lightgreen); + color: black; +} diff --git a/skrub/_reporting/_data/templates/summary-statistics.html b/skrub/_reporting/_data/templates/summary-statistics.html index 13170d97e..dac8e3c9d 100644 --- a/skrub/_reporting/_data/templates/summary-statistics.html +++ b/skrub/_reporting/_data/templates/summary-statistics.html @@ -1,10 +1,16 @@ {% macro th(name, ascending, descending) %} - {% endmacro %} @@ -19,7 +25,7 @@ data-manager="sortableTable"> - {{ th("", "from first column to last column", "from last column to first column") }} + {{ th("Index", "from first column to last column", "from last column to first column") }} {{ th("Column name", "by column name from A to Z", "by column name from Z to A") }} {{ th("dtype", "by dtype from A to Z", "by dtype from Z to A") }} {{ th1("Null values", "the fewest null values", "the most null values") }} From 1eac7d30036335d1b0caac4cd228952c52dbdddc Mon Sep 17 00:00:00 2001 From: Jerome Dockes Date: Wed, 11 Sep 2024 14:38:21 +0200 Subject: [PATCH 04/11] _ --- skrub/_reporting/_data/templates/summary-statistics.css | 1 + 1 file changed, 1 insertion(+) diff --git a/skrub/_reporting/_data/templates/summary-statistics.css b/skrub/_reporting/_data/templates/summary-statistics.css index bd0b80567..457cc5eac 100644 --- a/skrub/_reporting/_data/templates/summary-statistics.css +++ b/skrub/_reporting/_data/templates/summary-statistics.css @@ -49,5 +49,6 @@ th.sort-button-group-wrapper { .sort-button[data-is-active]{ background: var(--lightgreen); + transform: none; color: black; } From 98f0f166ada07edd91df86a7ff2a48720e824467 Mon Sep 17 00:00:00 2001 From: Jerome Dockes Date: Wed, 11 Sep 2024 14:52:35 +0200 Subject: [PATCH 05/11] _ --- skrub/_reporting/_data/templates/summary-statistics.css | 9 +++++++++ skrub/_reporting/_data/templates/summary-statistics.html | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/skrub/_reporting/_data/templates/summary-statistics.css b/skrub/_reporting/_data/templates/summary-statistics.css index 457cc5eac..1caecacd6 100644 --- a/skrub/_reporting/_data/templates/summary-statistics.css +++ b/skrub/_reporting/_data/templates/summary-statistics.css @@ -1,3 +1,8 @@ +.summary-stats-table { + margin: 2px; +} + + th.sort-button-group-wrapper { --btn-width: 2rem; --btn-group-width: calc(var(--btn-width) * 2); @@ -35,6 +40,10 @@ th.sort-button-group-wrapper { transform: translateY(-1px); } +.sort-button-group > .sort-button:focus-visible { + z-index: 2; +} + .sort-button-group > .sort-button ~ .sort-button { margin-left: -1px; } diff --git a/skrub/_reporting/_data/templates/summary-statistics.html b/skrub/_reporting/_data/templates/summary-statistics.html index dac8e3c9d..a9b7e974b 100644 --- a/skrub/_reporting/_data/templates/summary-statistics.html +++ b/skrub/_reporting/_data/templates/summary-statistics.html @@ -21,7 +21,7 @@
-
Column namedtypeNull valuesUnique valuesMeanStdMinMedianMax
{{ loop.index0 }} {{ column.name }} {{ column.dtype }} + {{ column.null_count }} ({{ column.null_proportion | format_percent }}) {{ column.n_unique }} ({{ column.unique_proportion | format_percent }}) + {{ column.n_unique }} ({{ column.unique_proportion | format_percent }}) {{ column["mean"] | format_number }}{{ column["standard_deviation"] | format_number }}{{ column["mean"] | format_number }}{{ column["standard_deviation"] | format_number }}{{ column.quantiles[0.0] | format_number }}{{ column.quantiles[0.5] | format_number }}{{ column.quantiles[1.0] | format_number }}{{ column.quantiles[0.0] | format_number }}{{ column.quantiles[0.5] | format_number }}{{ column.quantiles[1.0] | format_number }}{{ column.min | format_number }}{{ column.max | format_number }}{{ column.min | format_number }}{{ column.max | format_number }}
+ {% if name %} {{ name }} {% endif %} - - +
+ + +
From e0b6142a88908974ae41a70a718433b1f2dbe352 Mon Sep 17 00:00:00 2001 From: Jerome Dockes Date: Wed, 11 Sep 2024 14:56:47 +0200 Subject: [PATCH 06/11] _ --- skrub/_reporting/_data/templates/summary-statistics.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skrub/_reporting/_data/templates/summary-statistics.html b/skrub/_reporting/_data/templates/summary-statistics.html index a9b7e974b..6cb0cda43 100644 --- a/skrub/_reporting/_data/templates/summary-statistics.html +++ b/skrub/_reporting/_data/templates/summary-statistics.html @@ -25,7 +25,7 @@ data-manager="sortableTable"> - {{ th("Index", "from first column to last column", "from last column to first column") }} + {{ th("Column", "from first column to last column", "from last column to first column") }} {{ th("Column name", "by column name from A to Z", "by column name from Z to A") }} {{ th("dtype", "by dtype from A to Z", "by dtype from Z to A") }} {{ th1("Null values", "the fewest null values", "the most null values") }} From c45b8ab29db332af58eedf55d2e8103bbd15ccc8 Mon Sep 17 00:00:00 2001 From: Jerome Dockes Date: Wed, 11 Sep 2024 15:02:46 +0200 Subject: [PATCH 07/11] _ --- skrub/_reporting/_data/templates/summary-statistics.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skrub/_reporting/_data/templates/summary-statistics.css b/skrub/_reporting/_data/templates/summary-statistics.css index 1caecacd6..73aa0fd69 100644 --- a/skrub/_reporting/_data/templates/summary-statistics.css +++ b/skrub/_reporting/_data/templates/summary-statistics.css @@ -20,7 +20,7 @@ th.sort-button-group-wrapper { left: 100%; transform: translateX(calc(-1 * var(--btn-group-width) + 1px)); display: flex; - background: #999; + background: #aaa; gap: 0px; padding: 0px; padding-bottom: 1px; From 2922776aeb1820df512612eca9ab9083f0e6e779 Mon Sep 17 00:00:00 2001 From: Jerome Dockes Date: Wed, 11 Sep 2024 15:47:10 +0200 Subject: [PATCH 08/11] changelog + formatting --- CHANGES.rst | 4 +- .../_data/templates/summary-statistics.html | 53 +++++++++++-------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 7cdc92093..063bc704d 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -34,8 +34,8 @@ Minor changes * A "stats" panel has been added to the TableReport, showing summary statistics for all columns (number of missing values, mean, etc. -- similar to - ``pandas.info()`` ) in a table. - :pr:`1056` by :user:`Jérôme Dockès `. + ``pandas.info()`` ) in a table. It can be sorted by each column. + :pr:`1056` and :pr:`1068` by :user:`Jérôme Dockès `. Release 0.3.0 ============= diff --git a/skrub/_reporting/_data/templates/summary-statistics.html b/skrub/_reporting/_data/templates/summary-statistics.html index 6cb0cda43..cf23edd5c 100644 --- a/skrub/_reporting/_data/templates/summary-statistics.html +++ b/skrub/_reporting/_data/templates/summary-statistics.html @@ -1,15 +1,17 @@ {% macro th(name, ascending, descending) %} - {% endmacro %} @@ -19,10 +21,10 @@ {% endmacro %}
+ data-hide-on="EMPTY_COLUMN_FILTER_SELECTED">
+ {% if name %} {{ name }} {% endif %}
- - + +
+ data-manager="sortableTable"> {{ th("Column", "from first column to last column", "from last column to first column") }} @@ -39,39 +41,48 @@ {% for column in summary.columns %} - - + - {% if column.n_unique %} - {% else %} {% endif %} {% if "mean" in column %} - - + + {% else %} {% endif %} {% if column.quantiles %} - - - + + + {% elif "min" in column %} - + - + {% else %} From ad3bfdc122f0cb853b59fd87b741d9c525250fbc Mon Sep 17 00:00:00 2001 From: Jerome Dockes Date: Thu, 12 Sep 2024 14:33:47 +0200 Subject: [PATCH 09/11] remove shadow below buttons --- .../_data/templates/summary-statistics.css | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/skrub/_reporting/_data/templates/summary-statistics.css b/skrub/_reporting/_data/templates/summary-statistics.css index 73aa0fd69..d572b98b9 100644 --- a/skrub/_reporting/_data/templates/summary-statistics.css +++ b/skrub/_reporting/_data/templates/summary-statistics.css @@ -14,16 +14,14 @@ th.sort-button-group-wrapper { .sort-button-group { position: absolute; - top: 0; + top: -1px; bottom: 0; right: calc(-1 * var(--btn-group-width)); left: 100%; transform: translateX(calc(-1 * var(--btn-group-width) + 1px)); display: flex; - background: #aaa; gap: 0px; padding: 0px; - padding-bottom: 1px; } .sort-button { @@ -33,11 +31,9 @@ th.sort-button-group-wrapper { flex-grow: 1; border-radius: 0; border: 1px solid #aaa; - border-bottom: none; background: #e0e0e0; color: #222; padding: var(--tiny); - transform: translateY(-1px); } .sort-button-group > .sort-button:focus-visible { @@ -48,16 +44,15 @@ th.sort-button-group-wrapper { margin-left: -1px; } -.sort-button:active { - transform: none; -} - .sort-button:hover { background: #eeeeee; } +.sort-button:active { + background: #cccccc; +} + .sort-button[data-is-active]{ background: var(--lightgreen); - transform: none; color: black; } From 6e534fd9680f23d74c4960987ca6b1ac4a53b9f4 Mon Sep 17 00:00:00 2001 From: Jerome Dockes Date: Fri, 13 Sep 2024 12:59:33 +0200 Subject: [PATCH 10/11] add tests --- skrub/_reporting/_data/templates/report.js | 27 +++++++++-------- .../_data/templates/summary-statistics.html | 2 +- .../cypress/e2e/summary-statistics.cy.js | 29 +++++++++++++++++++ 3 files changed, 45 insertions(+), 13 deletions(-) create mode 100644 skrub/_reporting/js_tests/cypress/e2e/summary-statistics.cy.js diff --git a/skrub/_reporting/_data/templates/report.js b/skrub/_reporting/_data/templates/report.js index a3942aa2b..047cf3601 100644 --- a/skrub/_reporting/_data/templates/report.js +++ b/skrub/_reporting/_data/templates/report.js @@ -436,8 +436,8 @@ if (customElements.get('skrub-table-report') === undefined) { b => b.addEventListener("click", e => this.sort(e))); } - getVal(row, colIdx) { - const td = row.querySelectorAll("td")[colIdx]; + getVal(row, tableColIdx) { + const td = row.querySelectorAll("td")[tableColIdx]; if (!td.hasAttribute("data-value")) { return td.textContent; } @@ -448,9 +448,10 @@ if (customElements.get('skrub-table-report') === undefined) { return value; } - compare(rowA, rowB, colIdx, ascending) { - let valA = this.getVal(rowA, colIdx); - let valB = this.getVal(rowB, colIdx); + compare(rowA, rowB, tableColIdx, ascending) { + let valA = this.getVal(rowA, tableColIdx); + let valB = this.getVal(rowB, tableColIdx); + // NaNs go at the bottom regardless of sorting order if(typeof(valA) === "number" && typeof(valB) === "number"){ if(isNaN(valA) && !isNaN(valB)){ return 1; @@ -459,11 +460,14 @@ if (customElements.get('skrub-table-report') === undefined) { return -1; } } + // When the values are equal, keep the original dataframe column + // order if (!(valA > valB || valB > valA)) { - valA = Number(rowA.dataset.columnIdx); - valB = Number(rowB.dataset.columnIdx); + valA = Number(rowA.dataset.dataframeColumnIdx); + valB = Number(rowB.dataset.dataframeColumnIdx); return valA - valB; } + // Sort if (!ascending) { [valA, valB] = [valB, valA]; } @@ -471,18 +475,17 @@ if (customElements.get('skrub-table-report') === undefined) { } sort(event) { - const headerRow = this.elem.querySelector("thead tr"); - const colHeaders = Array.from(headerRow.querySelectorAll("th")); - const colIdx = colHeaders.findIndex(th => Array.from(th.querySelectorAll("button")) - .includes(event.target)); + const colHeaders = Array.from(this.elem.querySelectorAll("thead tr th")); + const tableColIdx = colHeaders.indexOf(event.target.closest("th")); const body = this.elem.querySelector("tbody"); const rows = Array.from(body.querySelectorAll("tr")); const ascending = event.target.dataset.direction === "ascending"; - rows.sort((a, b) => this.compare(a, b, colIdx, ascending)); + rows.sort((a, b) => this.compare(a, b, tableColIdx, ascending)); this.elem.querySelectorAll("button").forEach(b => b.removeAttribute("data-is-active")); event.target.dataset.isActive = ""; + body.innerHTML = ""; for (let r of rows) { body.appendChild(r); diff --git a/skrub/_reporting/_data/templates/summary-statistics.html b/skrub/_reporting/_data/templates/summary-statistics.html index cf23edd5c..151cfd897 100644 --- a/skrub/_reporting/_data/templates/summary-statistics.html +++ b/skrub/_reporting/_data/templates/summary-statistics.html @@ -42,7 +42,7 @@ {% for column in summary.columns %} + data-dataframe-column-idx="{{ loop.index0 }}"> diff --git a/skrub/_reporting/js_tests/cypress/e2e/summary-statistics.cy.js b/skrub/_reporting/js_tests/cypress/e2e/summary-statistics.cy.js new file mode 100644 index 000000000..4e1586c19 --- /dev/null +++ b/skrub/_reporting/js_tests/cypress/e2e/summary-statistics.cy.js @@ -0,0 +1,29 @@ +describe('test sorting the summary stats columns', () => { + it('sorts the table when clicking arrows', () => { + cy.get('@report').find('[data-test="summary-statistics-tab"]') + .click(); + cy.get('@report').find('.summary-stats-table').as('table'); + cy.get('@table').find('tbody tr').first().should('have.attr', + 'data-column-name', 'gender'); + cy.get('@report').contains('Column name').as('colName'); + cy.get('@colName').parent().find('button').first().as('colNameButton').click(); + cy.get('@colNameButton').should('have.attr', 'data-is-active'); + cy.get('@table').find('tbody tr').first().should('have.attr', + 'data-column-name', 'assignment_category'); + cy.get('@report').find('th').contains('Unique values').as( + 'unique'); + cy.get('@unique').parent().find('button').first().as('uniqueButton').click(); + cy.get('@uniqueButton').should('have.attr', 'data-is-active'); + cy.get('@colNameButton').should('not.have.attr', 'data-is-active'); + cy.get('@table').find('tbody tr').first().should('have.attr', + 'data-column-name', 'gender'); + cy.get('@table').find('tbody tr').last().should('have.attr', + 'data-column-name', 'year_first_hired'); + cy.get('@unique').parent().find('button').first().next() + .click(); + cy.get('@table').find('tbody tr').first().should('have.attr', + 'data-column-name', 'date_first_hired'); + cy.get('@table').find('tbody tr').last().should('have.attr', + 'data-column-name', 'year_first_hired'); + }); +}); From 4f626ca1934903d300ba416c31097a19c2a936be Mon Sep 17 00:00:00 2001 From: Jerome Dockes Date: Fri, 13 Sep 2024 13:21:16 +0200 Subject: [PATCH 11/11] better icons --- .../templates/icons/sort-alpha-down-alt.svg | 5 +++ .../_data/templates/icons/sort-alpha-down.svg | 4 ++ .../templates/icons/sort-numeric-down-alt.svg | 4 ++ .../templates/icons/sort-numeric-down.svg | 5 +++ .../_data/templates/summary-statistics.css | 2 +- .../_data/templates/summary-statistics.html | 38 +++++++++++-------- 6 files changed, 42 insertions(+), 16 deletions(-) create mode 100644 skrub/_reporting/_data/templates/icons/sort-alpha-down-alt.svg create mode 100644 skrub/_reporting/_data/templates/icons/sort-alpha-down.svg create mode 100644 skrub/_reporting/_data/templates/icons/sort-numeric-down-alt.svg create mode 100644 skrub/_reporting/_data/templates/icons/sort-numeric-down.svg diff --git a/skrub/_reporting/_data/templates/icons/sort-alpha-down-alt.svg b/skrub/_reporting/_data/templates/icons/sort-alpha-down-alt.svg new file mode 100644 index 000000000..85e53eb49 --- /dev/null +++ b/skrub/_reporting/_data/templates/icons/sort-alpha-down-alt.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/skrub/_reporting/_data/templates/icons/sort-alpha-down.svg b/skrub/_reporting/_data/templates/icons/sort-alpha-down.svg new file mode 100644 index 000000000..9fbb5fd87 --- /dev/null +++ b/skrub/_reporting/_data/templates/icons/sort-alpha-down.svg @@ -0,0 +1,4 @@ + + + + diff --git a/skrub/_reporting/_data/templates/icons/sort-numeric-down-alt.svg b/skrub/_reporting/_data/templates/icons/sort-numeric-down-alt.svg new file mode 100644 index 000000000..feb44528f --- /dev/null +++ b/skrub/_reporting/_data/templates/icons/sort-numeric-down-alt.svg @@ -0,0 +1,4 @@ + + + + diff --git a/skrub/_reporting/_data/templates/icons/sort-numeric-down.svg b/skrub/_reporting/_data/templates/icons/sort-numeric-down.svg new file mode 100644 index 000000000..9aecf482f --- /dev/null +++ b/skrub/_reporting/_data/templates/icons/sort-numeric-down.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/skrub/_reporting/_data/templates/summary-statistics.css b/skrub/_reporting/_data/templates/summary-statistics.css index d572b98b9..47446b04a 100644 --- a/skrub/_reporting/_data/templates/summary-statistics.css +++ b/skrub/_reporting/_data/templates/summary-statistics.css @@ -33,7 +33,7 @@ th.sort-button-group-wrapper { border: 1px solid #aaa; background: #e0e0e0; color: #222; - padding: var(--tiny); + padding: var(--micro); } .sort-button-group > .sort-button:focus-visible { diff --git a/skrub/_reporting/_data/templates/summary-statistics.html b/skrub/_reporting/_data/templates/summary-statistics.html index 151cfd897..7777b29f8 100644 --- a/skrub/_reporting/_data/templates/summary-statistics.html +++ b/skrub/_reporting/_data/templates/summary-statistics.html @@ -1,4 +1,4 @@ -{% macro th(name, ascending, descending) %} +{% macro th(name, ascending, descending, is_numeric) %} {% endmacro %} -{% macro th1(name, low, high) %} -{{ th(name, "from columns with " + low + " to columns with " + high, "from columns with " + high + " to columns with " + low) }} +{% macro th1(name, low, high, is_numeric) %} +{{ th(name, "from columns with " + low + " to columns with " + high, "from columns with " + high + " to columns with " + low, is_numeric) }} {% endmacro %}
- {{ th("Column", "from first column to last column", "from last column to first column") }} - {{ th("Column name", "by column name from A to Z", "by column name from Z to A") }} - {{ th("dtype", "by dtype from A to Z", "by dtype from Z to A") }} - {{ th1("Null values", "the fewest null values", "the most null values") }} - {{ th1("Unique values", "the fewest unique values", "the most unique values") }} - {{ th1("Mean", "the lowest mean", "the highest mean") }} - {{ th1("Std", "the lowest standard deviation", "the highest standard deviation") }} - {{ th1("Min", "the lowest minimum value", "the highest minimum value") }} - {{ th1("Median", "the lowest median", "the highest median") }} - {{ th1("Max", "the lowest maximum value", "the highest maximum value") }} + {{ th("Column", "from first column to last column", "from last column to first column", True) }} + {{ th("Column name", "by column name from A to Z", "by column name from Z to A", False) }} + {{ th("dtype", "by dtype from A to Z", "by dtype from Z to A", False) }} + {{ th1("Null values", "the fewest null values", "the most null values", True) }} + {{ th1("Unique values", "the fewest unique values", "the most unique values", True) }} + {{ th1("Mean", "the lowest mean", "the highest mean", True) }} + {{ th1("Std", "the lowest standard deviation", "the highest standard deviation", True) }} + {{ th1("Min", "the lowest minimum value", "the highest minimum value", True) }} + {{ th1("Median", "the lowest median", "the highest median", True) }} + {{ th1("Max", "the lowest maximum value", "the highest maximum value", True) }}
{{ loop.index0 }}{{ loop.index0 }} + {{ column.name }} {{ column.dtype }} + {{ column.null_count }} ({{ column.null_proportion | format_percent }}) {{ column.n_unique }} ({{ column.unique_proportion | format_percent }}) + + {{ column.n_unique }} ({{ column.unique_proportion | format_percent }}) {{ column["mean"] | format_number }}{{ column["standard_deviation"] | format_number }} + {{ column["mean"] | format_number }} + {{ column["standard_deviation"] | format_number }} {{ column.quantiles[0.0] | format_number }}{{ column.quantiles[0.5] | format_number }}{{ column.quantiles[1.0] | format_number }} + {{ column.quantiles[0.0] | format_number }} + {{ column.quantiles[0.5] | format_number }} + {{ column.quantiles[1.0] | format_number }}{{ column.min | format_number }} + {{ column.min | format_number }} {{ column.max | format_number }} + {{ column.max | format_number }}
{{ loop.index0 }} {{ column.name }} {% if name %} {{ name }} @@ -6,18 +6,26 @@