Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
06327d9
npm create anywidget@latest
mwouts Sep 12, 2024
0cc5032
npm install dt_for_itables --save
mwouts Sep 12, 2024
1612d72
Implement the widget
mwouts Sep 12, 2024
1c3bd55
Add init function
mwouts Sep 12, 2024
ced4f83
Move the widget to itables.widget
mwouts Sep 12, 2024
c8a4349
Document the ITable widget
mwouts Sep 12, 2024
6adc936
Include itables_anywidget in build
mwouts Sep 13, 2024
c78d2ab
Add traitlets as a dependency of itables[widget]
mwouts Sep 14, 2024
33d72ca
Add selected rows
mwouts Sep 14, 2024
5c90db3
Update the row selection in the table using model
mwouts Sep 14, 2024
8a38e3b
Recreate the table when the dt_args change
mwouts Sep 15, 2024
6535398
fixup pyproject.toml
mwouts Sep 15, 2024
9905861
The value of the streamlit component is the list of selected rows
mwouts Sep 15, 2024
527bf67
Add anywidget to the environment
mwouts Sep 15, 2024
b310a18
fix typo
mwouts Sep 15, 2024
c9ad57d
WIP get_selected_rows_after_downsampling
mwouts Sep 15, 2024
73eb70e
fix tests
mwouts Sep 15, 2024
4c69e5e
Sync data and table def with destroy_and_recreate
mwouts Sep 15, 2024
757be18
Passing the data through dt_args seems to be faster
mwouts Sep 16, 2024
75002c3
Selected rows conversion in JS
mwouts Sep 16, 2024
78737cb
Add back [tool.hatch.build.targets.sdist] and [tool.hatch.build.targe…
mwouts Sep 17, 2024
f4cfd6d
Selected rows in Streamlit
mwouts Sep 17, 2024
f4fa8cb
Fix selected rows
mwouts Sep 21, 2024
ac5d1a0
New functions set/get_selected_rows
mwouts Sep 21, 2024
36c06a7
Pass filtered_row_count explicitly
mwouts Sep 21, 2024
74e2678
table_id rather than tableId
mwouts Sep 21, 2024
279324f
selected rows and offline mode in Shiny apps
mwouts Sep 21, 2024
3c0b978
Set the initial row selection in shiny inputs
mwouts Sep 22, 2024
be6af4c
Document init_itables and selected_rows
mwouts Sep 22, 2024
1b22cf8
New df property and setter, make some traits private
mwouts Sep 22, 2024
2f7ee96
Version 2.2.0
mwouts Sep 22, 2024
47aae31
Print shiny version if test fails
mwouts Sep 22, 2024
d96c3dd
Require shiny>=1.0 in tests
mwouts Sep 22, 2024
9df679e
Install shiny>=1 when Python>3.7
mwouts Sep 22, 2024
c8661ce
Skip test if recent shiny is not available
mwouts Sep 22, 2024
a177e4a
Update the documentation
mwouts Sep 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ jobs:
if: matrix.polars
run: pip install -e .[polars]

- name: Install shiny
if: matrix.python-version != '3.7'
run: pip install "shiny>=1.0"

- name: Uninstall jinja2
if: matrix.uninstall_jinja2
run: pip uninstall jinja2 -y
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,6 @@ dt_bundle.css

# Streamlit package
src/itables/itables_for_streamlit

# Jupyter Widget
src/itables/widget/static
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ repos:
rev: v1.16.2
hooks:
- id: jupytext
exclude: dt_for_itables/
exclude: packages/
types: ["markdown"]
args: ["--pipe", "isort {} --treat-comment-as-code '# %%' --profile black", "--pipe", "black", "--check", "ruff check {} --ignore E402"]
additional_dependencies:
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
[![Conda Version](https://img.shields.io/conda/vn/conda-forge/itables.svg)](https://anaconda.org/conda-forge/itables)
[![pyversions](https://img.shields.io/pypi/pyversions/itables.svg)](https://pypi.python.org/pypi/itables)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Jupyter Widget](https://img.shields.io/badge/Jupyter-Widget-F37626.svg?style=flat&logo=Jupyter)](https://mwouts.github.io/itables/ipywidgets.html)
[![Streamlit App](https://static.streamlit.io/badges/streamlit_badge_black_red.svg)](https://itables.streamlit.app)

This packages changes how Pandas and Polars DataFrames are rendered in Jupyter Notebooks.
Expand Down Expand Up @@ -48,7 +49,7 @@ and then render any DataFrame as an interactive table that you can sort, search
If you prefer to render only selected DataFrames as interactive tables, use `itables.show` to show just one Series or DataFrame as an interactive table:
![show](docs/show_df.png)

Since `itables==1.0.0`, the [jQuery](https://jquery.com/) and [DataTables](https://datatables.net/) libraries and CSS
Since ITables v1.0, the [jQuery](https://jquery.com/) and [DataTables](https://datatables.net/) libraries and CSS
are injected in the notebook when you execute `init_notebook_mode` with its default argument `connected=False`.
Thanks to this the interactive tables will work even without a connection to the internet.

Expand All @@ -63,6 +64,7 @@ You can also use ITables in [Quarto](https://mwouts.github.io/itables/quarto.htm

ITables works well in VS Code, both in Jupyter Notebooks and in interactive Python sessions.

Last but not least, ITables is also available in
[Streamlit](https://mwouts.github.io/itables/streamlit.html) or
[Shiny](https://mwouts.github.io/itables/shiny.html) applications.
Last but not least, ITables is also available as
- a [Jupyter Widget](https://mwouts.github.io/itables/ipywidgets.html)
- a [Streamlit](https://mwouts.github.io/itables/streamlit.html) component,
- and it also works in [Shiny](https://mwouts.github.io/itables/shiny.html) applications.
19 changes: 17 additions & 2 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
ITables ChangeLog
=================

2.2.0 (2024-09-22)
------------------

**Added**
- ITables has a Jupyter Widget ([#267](https://github.com/mwouts/itables/issues/267)). Our widget was developed and packaged using [AnyWidget](https://anywidget.dev/) which I highly recommend!
- The selected rows are now available in the apps. Use either the `selected_rows` attribute of the `ITable` widget, the returned value of the Streamlit `interactive_table` component, or the `{table_id}_selected_rows` input in Shiny ([#208](https://github.com/mwouts/itables/issues/208), [#250](https://github.com/mwouts/itables/issues/250))
- ITables works offline in Shiny applications too - just add `ui.HTML(init_itables())` to your application

**Changed**
- The `tableId` argument of `to_html_datatable` has been renamed to `table_id`

**Fixed**
- The dependencies of the Streamlit component have been updated ([#320](https://github.com/mwouts/itables/issues/320))


2.1.5 (2024-09-08)
------------------

Expand All @@ -10,7 +25,7 @@ ITables ChangeLog
- We have improved the function that determines whether a dark theme is being used ([#294](https://github.com/mwouts/itables/issues/294))
- We have adjusted the generation of the Polars sample dataframes to fix the CI ([Polars-18130](https://github.com/pola-rs/polars/issues/18130))
- The test on the Shiny app fallbacks to `ui.nav_panel` when `ui.nav` is not available
- The dependencies of the streamlit component have been updated ([#313](https://github.com/mwouts/itables/issues/313), [#315](https://github.com/mwouts/itables/issues/315))
- The dependencies of the Streamlit component have been updated ([#313](https://github.com/mwouts/itables/issues/313), [#315](https://github.com/mwouts/itables/issues/315))


2.1.4 (2024-07-03)
Expand All @@ -35,7 +50,7 @@ ITables ChangeLog
an automatic horizontal scrolling in Jupyter, Jupyter Book and also Streamlit if the table is too wide ([#282](https://github.com/mwouts/itables/pull/282)).

**Fixed**
- The dependencies of the streamlit components have been updated to fix a vulnerability in `ws` ([Alert 1](https://github.com/mwouts/itables/security/dependabot/1))
- The dependencies of the Streamlit components have been updated to fix a vulnerability in `ws` ([Alert 1](https://github.com/mwouts/itables/security/dependabot/1))


2.1.1 (2024-06-08)
Expand Down
14 changes: 11 additions & 3 deletions docs/extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,12 @@ only the selected rows are exported
```{code-cell}
:tags: [full-width]

show(df, select=True, buttons=["copyHtml5", "csvHtml5", "excelHtml5"])
show(
df,
select=True,
selected_rows=[2, 4, 5],
buttons=["copyHtml5", "csvHtml5", "excelHtml5"],
)
```

```{tip}
Expand All @@ -283,8 +288,11 @@ however cell selection is not taken into account when exporting the data.
```

```{tip}
At the moment it is not possible to get the selected rows back in Python. Please subscribe to
[#250](https://github.com/mwouts/itables/issues/250) to get updates on this topic.
It is possible to get the updated `selected_rows` back in Python but for this you will have to use,
instead of `show`, either
- the `ITable` [Jupyter Widget](ipywidgets.md)
- the `interactive_table` [Streamlit component](streamlit.md)
- or `DT` in a [Shiny app](shiny.md).
```

## RowGroup
Expand Down
120 changes: 117 additions & 3 deletions docs/ipywidgets.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,118 @@
# IPyWidgets
---
jupytext:
formats: md:myst
notebook_metadata_filter: -jupytext.text_representation.jupytext_version
text_representation:
extension: .md
format_name: myst
format_version: 0.13
kernelspec:
display_name: itables
language: python
name: itables
---

ITables does not come as a [Jupyter Widget](https://ipywidgets.readthedocs.io) at the moment.
You are welcome to subscribe or contribute to [#267](https://github.com/mwouts/itables/issues/267).
# Jupyter Widget

ITables is available as a [Jupyter Widget](https://ipywidgets.readthedocs.io) since v2.2.

## The `ITable` widget

The `ITable` widget has a few dependencies (essentially [AnyWidget](https://anywidget.dev),
a great widget development framework!) that you can install with
```bash
pip install itables[widget]
```

The `ITable` class accepts the same arguments as the `show` method, but
the `df` argument is optional.

```{code-cell}
from itables.sample_dfs import get_dict_of_test_dfs
from itables.widget import ITable

df = get_dict_of_test_dfs()["int_float_str"]

table = ITable(df, selected_rows=[0, 2, 5], select=True)
table
```

## The `selected_rows` traits

The `selected_rows` attribute of the `ITable` object provides a view on the
rows that have been selected in the table (remember to pass `select=True`
to activate the row selection). You can use it to either retrieve
or change the current row selection:

```{code-cell}
table.selected_rows
```

```{code-cell}
table.selected_rows = [3, 4]
```

## The `df` property

Use it to retrieve the table data:

```{code-cell}
table.df.iloc[table.selected_rows]
```

or to update it

```{code-cell}
table.df = df.head(6)
```

```{tip}
`ITable` will raise an `IndexError` if the `selected_rows` are not consistent with the
updated data. If you need to update the two simultaneously, use `table.update(df, selected_rows=...)`, see below.
```

## The `caption`, `style` and `classes` traits

You can update these traits from Python, e.g.

```{code-cell}
table.caption = "numbers and strings"
```

## The `update` method

Last but not least, you can update the `ITable` arguments simultaneously using the `update` method:

```{code-cell}
table.update(df.head(20), selected_rows=[7, 8])
```

## Limitations

Compared to `show`, the `ITable` widget has the same limitations as the [Streamlit component](streamlit.md#limitations),
e.g. structured headers are not available, you can't pass JavaScript callback, etc.

The good news is that if you only want to _display_ the table, you do not need
the `ITables` widget. Below is an example in which we use `show` to display a different
table depending on the value of a drop-down component:

```python
import ipywidgets as widgets
from itables import show
from itables.sample_dfs import get_dict_of_test_dfs

def use_show_in_interactive_output(table_name: str):
show(
sample_dfs[table_name],
caption=table_name,
)

sample_dfs = get_dict_of_test_dfs()
table_selector = widgets.Dropdown(options=sample_dfs.keys(), value="int_float_str")

out = widgets.interactive_output(
use_show_in_interactive_output, {"table_name": table_selector}
)

widgets.VBox([table_selector, out])
```
1 change: 1 addition & 0 deletions docs/quick_start.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ kernelspec:
[![Conda Version](https://img.shields.io/conda/vn/conda-forge/itables.svg)](https://anaconda.org/conda-forge/itables)
[![pyversions](https://img.shields.io/pypi/pyversions/itables.svg)](https://pypi.python.org/pypi/itables)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Jupyter Widget](https://img.shields.io/badge/Jupyter-Widget-F37626.svg?style=flat&logo=Jupyter)](ipywidgets.md)
[![Streamlit App](https://static.streamlit.io/badges/streamlit_badge_black_red.svg)](https://itables.streamlit.app)
<a class="github-button" href="https://github.com/mwouts/itables" data-icon="octicon-star" data-show-count="true"></a>
<script src="https://buttons.github.io/buttons.js"></script>
Expand Down
14 changes: 11 additions & 3 deletions docs/shiny.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@ You can use ITables in Web applications generated with [Shiny](https://shiny.rst
from shiny import ui

from itables.sample_dfs import get_countries
from itables.shiny import DT
from itables.shiny import DT, init_itables

df = get_countries(html=False)
ui.HTML(DT(df))
# Load the datatables library and css from the ITables package
# (use connected=True if you prefer to load it from the internet)
ui.HTML(init_itables(connected=False))

# Render the table with DT
ui.HTML(DT(get_countries(html=False)))
```

If you enable row selection and set an id on your table, e.g. `DT(df, table_id="my_table", select=True)` then
ITables will provide the list of selected rows at `input.my_table_selected_rows()` (replace `my_table` with your
own table id).

See also our [tested examples](https://github.com/mwouts/itables/tree/main/tests/sample_python_apps).
13 changes: 7 additions & 6 deletions docs/streamlit.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ We have a sample application available at https://itables.streamlit.app (source
style="height: 600px; width: 100%;"></iframe>
```

## Selected rows

This feature was added in ITables v2.2.0.

Use the `selected_rows: list[int]` argument from `interactive_table` to
select rows when the table is first displayed. Add `select=True` to let the user modify the selection. Then, the `interactive_table` component returns a dict, with a key `"selected_rows"` that points to the updated selection.

## Limitations

In most cases, you will be able to use `interactive_table` in a
Expand Down Expand Up @@ -42,9 +49,3 @@ A sample application is available at https://to-html-datatable.streamlit.app (so
<iframe src="https://to-html-datatable.streamlit.app?embed=true"
style="height: 600px; width: 100%;"></iframe>
```

## Future developments

ITables' Streamlit component might see the following developments in the future
- Return the selected cells
- Make the table editable (will require a DataTable [editor license](https://editor.datatables.net/purchase/))
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ dependencies:
- ghp-import
- shiny
- streamlit
- anywidget
- pip:
- world_bank_data
4 changes: 4 additions & 0 deletions packages/dt_for_itables/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 2.0.13 (2024-09-22)

- We have added two functions `set_selected_rows` and `get_selected_rows` to set and retrieve selected rows

# 2.0.12 (2024-09-08)

- We have added the datetime extension for DataTables ([#288](https://github.com/mwouts/itables/issues/288))
Expand Down
4 changes: 2 additions & 2 deletions packages/dt_for_itables/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/dt_for_itables/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dt_for_itables",
"version": "2.0.12",
"version": "2.0.13",
"description": "DataTables bundle for itables",
"main": "src/index.js",
"typings": "src/index.d.js",
Expand Down
20 changes: 20 additions & 0 deletions packages/dt_for_itables/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,26 @@ import 'datatables.net-select-dt/css/select.dataTables.min.css';

import './index.css';

DataTable.get_selected_rows = function (dt, filtered_row_count) {
// Here the selected rows are for the datatable.
// We convert them back to the full table
let data_row_count = dt.rows().count();
let bottom_half = data_row_count / 2;
return Array.from(dt.rows({ selected: true }).indexes().map(
i => (i < bottom_half ? i : i + filtered_row_count)));
}

DataTable.set_selected_rows = function (dt, filtered_row_count, selected_rows) {
let data_row_count = dt.rows().count();
let bottom_half = data_row_count / 2;
let top_half = bottom_half + filtered_row_count;
let full_row_count = data_row_count + filtered_row_count;
selected_rows = Array.from(selected_rows.filter(i => i >= 0 && i < full_row_count && (i < bottom_half || i >= top_half)).map(
i => (i < bottom_half) ? i : i - filtered_row_count));
dt.rows().deselect();
dt.rows(selected_rows).select();
}

export { DataTable, DateTime, jQuery };

export default DataTable;
29 changes: 29 additions & 0 deletions packages/itables_anywidget/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# itables_anywidget

## Installation

```sh
pip install itables_anywidget
```

## Development installation

Create a virtual environment and and install itables_anywidget in *editable* mode with the
optional development dependencies:

```sh
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
```

You then need to install the JavaScript dependencies and run the development server.

```sh
npm install
npm run dev
```

Open `example.ipynb` in JupyterLab, VS Code, or your favorite editor
to start developing. Changes made in `js/` will be reflected
in the notebook.
Empty file.
Loading