2025, Nov 07 09:02

Логотип в navbar Shiny for Python: как правильно подключить статические файлы

Как добавить логотип в navbar Shiny for Python: раздача статических файлов, папка static и static_assets, корректные ссылки на logo.png для стабильной загрузки.

Вставить логотип в навбар Shiny for Python вроде бы просто, но по умолчанию приложение не отдает файлы с диска, если ему явно не указать, где лежат эти ресурсы. Если путь к изображению не сопоставлен со статическим каталогом, запрос браузера не будет обслужен, и логотип просто не появится.

Минимальный пример, где логотип не отображается

from shiny import App, ui

ui_shell = ui.page_navbar(
    ui.nav_panel("Bar", ui.h2("Bar plot")),
    ui.nav_panel("Map", ui.h2("Cloropleth")),
    ui.nav_spacer(),
    ui.nav_control(ui.input_dark_mode(id="toggle_dm")),
    title=ui.tags.a(ui.tags.img(src="logo.png", height="30px"), "", href="#")
)

app_runner = App(ui_shell, server=None)
if __name__ == "__main__":
    app_runner.run()

Разметка корректна, изображение указано, приложение запускается. Не хватает лишь раздачи статических файлов: среда выполнения не знает, откуда брать logo.png.

Что на самом деле происходит

Статические файлы — изображения, CSS и JavaScript — сервер не публикует автоматически. Нужно объявить папку, которую Shiny будет обслуживать, и подключить её под URL-префиксом. Разметка, ссылающаяся на файл, должна использовать этот префикс, чтобы сервер направлял запросы по адресу назначения.

Решение

Создайте рядом со скриптом папку static и переместите в неё logo.png. В коде приложения определите путь к этой папке через pathlib, обращайтесь к изображению с путём, начинающимся с static/, и передайте сопоставление в static_assets при создании App, чтобы сервер понимал, как отдавать эти файлы.

from pathlib import Path
from shiny import App, ui

public_dir = Path(__file__).parent / "static"

ui_shell = ui.page_navbar(
    ui.nav_panel("Bar", ui.h2("Bar plot")),
    ui.nav_panel("Map", ui.h2("Cloropleth")),
    ui.nav_spacer(),
    ui.nav_control(ui.input_dark_mode(id="toggle_dm")),
    title=ui.tags.a(ui.tags.img(src="static/logo.png", height="30px"), "", href="#")
)

app_runner = App(ui_shell, server=None, static_assets={"/static": public_dir})
if __name__ == "__main__":
    app_runner.run()

С такой конфигурацией запросы к путям, начинающимся со static/ в HTML, будут разрешаться в файлы из указанной статической директории.

Почему это важно

Явное управление статическими ресурсами избавляет от сюрпризов в продакшене и при рефакторинге. Приложение становится предсказуемым: сервер публикует контролируемое дерево файлов, а интерфейс ссылается на него через понятный, стабильный URL-путь. Тот же подход масштабируется на дополнительные изображения и любые другие фронтенд‑ресурсы, которые вы добавите позже.

Выводы

Укажите приложению отдельную папку для статики, ссылайтесь на файлы по этому пути в HTML и передайте сопоставление через аргумент static_assets при создании App. После этого логотип и другие ассеты будут загружаться стабильно.

Статья основана на вопросе с StackOverflow от GSandro_Strongs и ответе от Detlef.