2025, Oct 01 23:16
Как отобразить списки из DataFrame в таблице NiceGUI и ускорить from_polars
Почему в NiceGUI списки в DataFrame склеиваются в строку и как это исправить: явные колонки, JavaScript‑форматтер и String(value) для быстрого вывода.
Отображение DataFrame со столбцами, содержащими списки, часто отличается в разных UI‑фреймворках. При переносе таблицы из Streamlit в NiceGUI нередко оказывается, что список в ячейке уже не выглядит как список. Вместо этого он склеивается в строку, а стандартное преобразование через from_polars() может заметно тормозить. Задача — получить вывод, более похожий на Streamlit, и при этом сохранить отзывчивость интерфейса.
Что меняется при смене фреймворка
В Streamlit список внутри ячейки DataFrame показывается как список. В NiceGUI те же данные, поданные через ui.table.from_polars, преобразуются так, что столбец со списками склеивается в строку. Сам этап преобразования тоже может быть медленным.
Ниже минимальные примеры на одних и тех же данных.
Streamlit:
import polars as pl
import streamlit as st
records = pl.DataFrame({
    "u": [1, 2, 3],
    "v": [4, 5, 6],
    "w": [[1, 2], [3, 4], [5, 6]],
})
st.write(records)
NiceGUI (поведение по умолчанию):
import polars as pl
from nicegui import ui
records = pl.DataFrame({
    "u": [1, 2, 3],
    "v": [4, 5, 6],
    "w": [[1, 2], [3, 4], [5, 6]],
})
ui.table.from_polars(records)
ui.run()
Почему так происходит
NiceGUI выполняет конвертацию входных данных для таблицы. На практике это означает, что значения-списки в ячейках превращаются в строки для вывода. Если заглянуть в исходники библиотеки (table.py, table.js, dynamic_properties.js), видно JavaScript‑код, который использует рекурсию при преобразовании; это может вносить вклад в замедление. Важно помнить для повседневной работы: стандартное преобразование не сохраняет отображение списков так, как это делает Streamlit, и само по себе может быть затратным.
Как вернуть «списковое» отображение и ускорить работу
API таблицы позволяет повесить форматтер на столбец. Назначив JavaScript‑форматтер для столбца со списками, вы управляете отображением значений и обходите тяжелое преобразование. Простейший вариант — вызвать String(value), в результате в ячейке получится строка с элементами через запятую. При желании форматирование можно доработать.
Нюанс: при таком подходе столбцы нужно объявить явно.
from nicegui import ui
import polars as pl
headers = [
    {"name": "u", "label": "u", "field": "u"},
    {"name": "v", "label": "v", "field": "v"},
    {
        "name": "w",
        "label": "w",
        "field": "w",
        ":format": "value => String(value)",  # отображать значения списков как строку
    },
]
data = pl.DataFrame({
    "u": [1, 2, 3],
    "v": [4, 5, 6],
    "w": [[1, 2], [3, 4], [5, 6]],
})
ui.table.from_polars(df=data, columns=headers)
ui.run()
Так сразу решаются две прикладные задачи: таблица становится отзывчивой, а столбец со списками читаемо выводится в виде значений, разделенных запятыми. Та же идея работает и с pandas при использовании from_pandas().
Зачем это знать
Переход между фреймворками редко бывает «один к одному». Понимание того, как NiceGUI преобразует данные, помогает избежать странного вывода и неожиданных просадок по скорости. Зная, что ячейки со списками конвертируются и что форматирование можно переопределить JavaScript‑форматтером, вы добьетесь результата, близкого к отображению в Streamlit, и сохраните быстрый отклик приложения.
Выводы
Если в NiceGUI столбец со списками склеивается в строку, а from_polars ощущается медленным, объявите столбцы явно и добавьте форматтер для спискового столбца. String(value) — простой прием, который возвращает читаемость и ускоряет отображение; при необходимости форматтер можно настроить под желаемую подачу. Если переключаетесь между polars и pandas, применяйте тот же подход с from_pandas. Проще говоря, задавайте форматирование для списковых столбцов явно — и получите предсказуемый, быстрый результат.