График и уценка рядом в Jupyter Notebook

Я хочу отобразить график и уценку рядом в Jupyter Notebook (для использования в RISE), используя matplotlib. Я нашел следующий ответ, в котором используется plotly,

Покажите интерактивный график и текст Markdown рядом в Jupyter

и просто изменил его, добавив несколько элементов matplotlib

from ipywidgets import widgets, Layout
from IPython.display import display, Javascript, Markdown as md
import numpy as np
import matplotlib.pyplot as plt

def func(x, a, b, c, d):
    return a + b*np.exp(c*x + d)

the_x = np.arange(0, 10, 0.5)
the_y = func(the_x, 1, 1, -1, 2)

fig, ax = plt.subplots()
ax.plot(the_x, the_y)

len_x = len(the_x)

mdout = md(f"""There are {len_x} **elements** of both `the_x`, and `the_y`;

Those values are plotted on the diagram on the left""")


box_layout = Layout(display='flex',
                    flex_flow='row',
                    justify_content='space-around',
                    width='auto'
                   )

hbox1 = widgets.Box(children=[fig, widgets.HTML(mdout._repr_markdown_())], layout=box_layout)
display(hbox1)

Но это не работает со следующим сообщением об ошибке:

TraitError: The 'children' trait of a Box instance contains an Instance of a TypedTuple which expected a Widget, not the Figure <Figure size 640x480 with 1 Axes>.

это примерно вторая строка снизу.

Кто-нибудь может помочь?


65
1

Ответ:

Решено

В моих руках следующий вариант вашего кода работает как следующий шаг (окончательный вариант см. в разделе «Обновление» ниже):

#based on https://stackoverflow.com/q/78670150/8508004, and adapting to put matplotlib in a widget from https://stackoverflow.com/a/51060721/8508004 (which I think was adapted in some ways from https://github.com/jupyter-widgets/ipywidgets/issues/2821)
from ipywidgets import widgets, Layout
from IPython.display import display, Javascript, Markdown as md
import numpy as np
import matplotlib.pyplot as plt

left_widget = widgets.Output()
def func(x, a, b, c, d):
    return a + b*np.exp(c*x + d)

the_x = np.arange(0, 10, 0.5)
the_y = func(the_x, 1, 1, -1, 2)

with left_widget:
    fig, ax = plt.subplots()
    ax.plot(the_x, the_y)
    plt.show(fig)

len_x = len(the_x)

mdout = md(f"""There are {len_x} **elements** of both `the_x`, and `the_y`;
Those values are plotted on the diagram on the left""")

box_layout = Layout(display='flex',
                    flex_flow='row',
                    justify_content='space-around',
                    width='auto'
                   )

hbox1 = widgets.Box(children=[left_widget, widgets.HTML(mdout._repr_markdown_())], layout=box_layout)
display(hbox1)

Единственным реальным изменением была упаковка объекта графика Matplotlib в контекст виджета Output() ipywidget, который «может захватывать и отображать стандартный вывод, стандартный вывод и расширенный вывод, сгенерированный IPython», а затем использование этого виджета в качестве левой стороны для перечисленных дочерних элементов. в поле ipywidget. (Найдите код, относящийся к left_widget, чтобы увидеть отличия от исходного предоставленного кода.)

Связанные ресурсы:


ОБНОВЛЯТЬ:

Чтобы учесть тот факт, что источник адаптированного решения не включал обработку отображения необработанного кода уценки как полностью визуализированного уценки в области справа, я теперь добавил обработку этого. Вам потребуется установить пакеты для первых двух подходов, которые я предлагаю. (Для markdown2 я поместил команду в связанные блокноты: «Установите ее из работающих блокнотов Juyter с помощью %conda install -c conda-forge markdown2 или %pip install markdown2».).
Первые два решения фактически добавляют рендеринг еще одного элемента уценки, чтобы показать, что их можно быстрее адаптировать. И на самом деле, если вам не нужен текст между обратными кавычками, отображаемый как стиль «код», вы можете выполнить стиль без использования CSS. Подробную информацию см. в сопутствующем блокноте Jupyter, указанном в нижней части этого раздела для получения дополнительной информации. информация.
(На самом деле CSS, используемый в первых двух вариантах, может быть проще, но я поместил здесь полную информацию о CSS для всех элементов, чтобы убедиться, что он работает в полной мере.)

Предлагаемое решение А:

#based on https://stackoverflow.com/q/78670150/8508004, and adapting to put matplotlib in a widget from https://stackoverflow.com/a/51060721/8508004 (which I think was adapted in some ways from https://github.com/jupyter-widgets/ipywidgets/issues/2821)
from ipywidgets import widgets, Layout, HTML
from IPython.display import display
import numpy as np
import matplotlib.pyplot as plt
import markdown

left_widget = widgets.Output()
def func(x, a, b, c, d):
    return a + b*np.exp(c*x + d)

the_x = np.arange(0, 10, 0.5)
the_y = func(the_x, 1, 1, -1, 2)

with left_widget:
    fig, ax = plt.subplots()
    ax.plot(the_x, the_y)
    plt.show(fig)

len_x = len(the_x)

md_content = f"""# (Markdown Heading Rendered) RESULTS:

There are {len_x} **elements** of both `the_x`, and `the_y`;
Those values are plotted on the diagram on the left"""

box_layout = Layout(display='flex',
                    flex_flow='row',
                    justify_content='space-around',
                    width='auto'
                   )
html_content = markdown.markdown(md_content)
markdown_widget = HTML(
    value=f"""
    <style>
    .markdown-body {{
        font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
        font-size: 16px;
        line-height: 1.5;
        word-wrap: break-word;
    }}
    .markdown-body h1 {{
        padding-bottom: .3em;
        font-size: 2em;
        border-bottom: 1px solid #eaecef;
    }}
    .markdown-body strong {{
        font-weight: 600;
    }}
    .markdown-body code {{
        padding: .2em .4em;
        margin: 0;
        font-size: 85%;
        background-color: rgba(27,31,35,.05);
        border-radius: 3px;
    }}
    </style>
    <div class = "markdown-body">
    {html_content}
    </div>
    """
)
hbox1 = widgets.Box(children=[left_widget, markdown_widget], layout=box_layout)
display(hbox1)

Предлагаемое решение Б:

#based on https://stackoverflow.com/q/78670150/8508004, and adapting to put matplotlib in a widget from https://stackoverflow.com/a/51060721/8508004 (which I think was adapted in some ways from https://github.com/jupyter-widgets/ipywidgets/issues/2821)
from ipywidgets import widgets, Layout
import numpy as np
import matplotlib.pyplot as plt
import markdown2

left_widget = widgets.Output()
def func(x, a, b, c, d):
    return a + b*np.exp(c*x + d)

the_x = np.arange(0, 10, 0.5)
the_y = func(the_x, 1, 1, -1, 2)

with left_widget:
    fig, ax = plt.subplots()
    ax.plot(the_x, the_y)
    plt.show(fig)

len_x = len(the_x)

md_content = f"""# (Markdown Heading Rendered) RESULTS:

There are {len_x} **elements** of both `the_x`, and `the_y`;
Those values are plotted on the diagram on the left"""

box_layout = Layout(display='flex',
                    flex_flow='row',
                    justify_content='space-around',
                    width='auto'
                   )

html_content = markdown2.markdown(md_content)
markdown_widget = widgets.HTML(
    value=f"""
    <style>
    .markdown-body {{
        font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
        font-size: 16px;
        line-height: 1.5;
        word-wrap: break-word;
    }}
    .markdown-body h1 {{
        padding-bottom: .3em;
        font-size: 2em;
        border-bottom: 1px solid #eaecef;
    }}
    .markdown-body strong {{
        font-weight: 600;
    }}
    .markdown-body code {{
        padding: .2em .4em;
        margin: 0;
        font-size: 85%;
        background-color: rgba(27,31,35,.05);
        border-radius: 3px;
    }}
    </style>
    <div class = "markdown-body">
    {html_content}
    </div>
    """
)
hbox1 = widgets.Box(children=[left_widget, markdown_widget], layout=box_layout)
display(hbox1)

Предлагаемое решение C:

from ipywidgets import widgets, Layout
import numpy as np
import matplotlib.pyplot as plt

left_widget = widgets.Output()
def func(x, a, b, c, d):
    return a + b*np.exp(c*x + d)

the_x = np.arange(0, 10, 0.5)
the_y = func(the_x, 1, 1, -1, 2)

with left_widget:
    fig, ax = plt.subplots()
    ax.plot(the_x, the_y)
    plt.show(fig)

len_x = len(the_x)

md_content = f"""There are {len_x} **elements** of both `the_x`, and `the_y`;
Those values are plotted on the diagram on the left"""

box_layout = Layout(display='flex',
                    flex_flow='row',
                    justify_content='space-around',
                    width='auto'
                   )

def simple_markdown_to_html(text):
    # Handle bold text
    text = text.replace('**', '<strong>', 1).replace('**', '</strong>', 1)
    # Handle inline code
    while '`' in text:
        text = text.replace('`', '<code>', 1).replace('`', '</code>', 1)
    return text

html_content = simple_markdown_to_html(md_content)

markdown_widget = widgets.HTML(
    value=f"""
    <style>
    .markdown-body {{
        font-family: Arial, sans-serif;
        padding: 10px;
    }}
    .markdown-body strong {{
        font-weight: bold;
    }}
    .markdown-body code {{
        background-color: #f0f0f0;
        padding: 2px 4px;
        border-radius: 3px;
        font-family: monospace;
    }}
    </style>
    <div class = "markdown-body">
    {html_content}
    </div>
    """
)

hbox1 = widgets.Box(children=[left_widget, markdown_widget], layout=box_layout)
display(hbox1)

Для получения полной информации просмотрите код и результат, полученный с начальной точки, в файле блокнота Jupyter лучше всего смотреть здесь.

Связанные ресурсы для преобразования текста и оформления уценки: