Я знаю, что это выходит за рамки возможностей большинства сообществ, но мы — научное сообщество, использующее Python и множество графиков (Matplotlib), которыми мы обмениваемся друг с другом через Discourse.
Было бы потрясающе иметь возможность делиться интерактивными графиками вместо статических JPG/PNG.
Рассмотрим этот пример:
import matplotlib.pyplot as plt
import mpld3
import numpy as np
Fs = 4000
f = 100
sample = 200
x = np.arange(sample)
y = np.sin(2 * np.pi * f * x / Fs)
fig, ax = plt.subplots(1,1)
ax.plot(x, y, marker=".")
html_str = mpld3.fig_to_html(fig)
Html_file= open("index.html","w")
Html_file.write(html_str)
Html_file.close()
Вы сможете открыть файл index.html, и он покажет это (только что он будет ИНТЕРАКТИВНЫМ…)
Описанный вами метод был бы возможен с помощью пользовательского плагина, объединяющего плагин в стиле markdown-it и, возможно, удобное хранилище объектов для HTML-файлов. Однако я бы проявил осторожность в вопросах безопасности, позволяя выполнять код, введённый пользователем, в любой части сервера. Discourse уже проделывает большую работу, чтобы обезопасить посты от HTML и JS для безопасного разбора на стороне сервера.
Возможно, вам лучше попробовать внедрить интерпретатор Python прямо в браузер и запускать код на стороне клиента, минуя весь процесс создания HTML. JupyterLite позволит запускать JupyterLab в браузере с интерфейсом. Согласно документации, можно настроить автоматическое выполнение кода при создании iframe. Вы можете передавать код с помощью пользовательского плагина HighlightJS, который создаст интерактивную кнопку для любого блока кода Python, или настроить автоматический запуск.
Таким образом, процесс будет выглядеть так:
Пользователь видит пост с блоком кода Python.
При наведении курсора на блок кода появляется кнопка, позволяющая запустить код в браузере.
Пользователь нажимает на кнопку, что создаёт iframe с JupyterLite под блоком кода и импортирует код из этого блока.
Поскольку это будет просто плагин HighlightJS, создающий iframe для JupyterLite, всё можно реализовать в рамках компонента темы, без необходимости написания серверного кода.
Одно замечание: JupyterLite описывается как не полностью соответствующий JupyterLab, и я не уверен, как он обрабатывает импорт пакетов, поэтому, возможно, вам придётся размещать его самостоятельно. JupyterLite использует Pyodide, который поддерживает любые wheel-пакеты из PyPI, поэтому проблем быть не должно.
Я считаю, что риск для безопасности не так велик, если index.html выполняется на стороне клиента (в браузере пользователя, а не на сервере Discourse).
Кроме того, преимущество подхода mpld3 заключается в том, что это один файл без зависимостей. Если вы запускаете сырой Python, вам также нужно иметь возможность загружать все зависимости, такие как CSV-файлы, файлы данных и т. д., которые являются источником данных для построения графиков.
Тем не менее, возможность запускать сырые скрипты Python внутри поста Discourse была бы просто восхитительной!
Ой! Я полностью неправильно понял, как будет генерироваться HTML. Если пользователь заранее генерирует HTML, вы можете предложить ему встроить его через iframe с внешнего сайта, предварительно добавив домен в белый список.
Например, CodePen, который должен быть разрешён по умолчанию:
<iframe height="300" width="800" style="width: 100%;" scrolling="no" title="mplD3 example, actually working" src="https://codepen.io/gully/embed/BawMGr?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
See the Pen <a href="https://codepen.io/gully/pen/BawMGr">
mplD3 example, actually working</a> by gully (<a href="https://codepen.io/gully">@gully</a>)
on <a href="https://codepen.io">CodePen</a>.
</iframe>
Это действительно здорово!
У меня есть несколько вопросов:
Как вы думаете, это будет работать с ipympl? (Иначе графики не будут интерактивными, что лишает весь смысл)
Как вы думаете, это можно будет использовать с базовой папкой проекта, где мы сможем установить переменную окружения PYTHONPATH перед запуском Jupyter, чтобы пользователи могли импортировать функции и зависимости из подключенного проекта?
И да, у меня есть бюджет, если это разумно и осуществимо, и если это можно будет внести как открытое исходное решение для всего сообщества Discourse.
@Alteras Спасибо, это решение действительно простое и работает, если вы найдете способ загрузить файл “index.heml” на Discourse (что легко сделать, разрешив загрузку .html) и отобразить его в коде iframe. Единственная проблема в том, что на самом деле это не работает… когда я пытаюсь это сделать, файл просто скачивается вместо того, чтобы отображаться в iframe. Возможно, существует мета-тег, который скажет iframe показывать файл, а не скачивать его?
Ах, понятно. По умолчанию Discourse устанавливает для всех вложений, не являющихся изображениями, заголовок Content-Disposition со значением «attachment», что заставляет браузер воспринимать их только как файлы для загрузки.