浏览代码

Merge branch 'main' of github.com:zauberzeug/nicegui

Falko Schindler 1 年之前
父节点
当前提交
eac5a5faa9

+ 43 - 0
nicegui/elements/pyplot.py

@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import asyncio
 import io
 import os
@@ -11,8 +13,22 @@ from ..element import Element
 
 try:
     if os.environ.get('MATPLOTLIB', 'true').lower() == 'true':
+        import matplotlib.figure
         import matplotlib.pyplot as plt
         optional_features.register('matplotlib')
+
+        class MatplotlibFigure(matplotlib.figure.Figure):
+
+            def __init__(self, element: Matplotlib, *args: Any, **kwargs: Any) -> None:
+                super().__init__(*args, **kwargs)
+                self.element = element
+
+            def __enter__(self) -> Self:
+                return self
+
+            def __exit__(self, *_) -> None:
+                self.element.update()
+
 except ImportError:
     pass
 
@@ -57,3 +73,30 @@ class Pyplot(Element):
         while self.client.id in Client.instances:
             await asyncio.sleep(1.0)
         plt.close(self.fig)
+
+
+class Matplotlib(Element):
+
+    def __init__(self, **kwargs: Any) -> None:
+        """Matplotlib
+
+        Create a `Matplotlib <https://matplotlib.org/>`_ element rendering a Matplotlib figure.
+        The figure is automatically updated when leaving the figure context.
+
+        :param kwargs: arguments like `figsize` which should be passed to `matplotlib.figure.Figure <https://matplotlib.org/stable/api/figure_api.html#matplotlib.figure.Figure>`_
+        """
+        if not optional_features.has('matplotlib'):
+            raise ImportError('Matplotlib is not installed. Please run "pip install matplotlib".')
+
+        super().__init__('div')
+        self.figure = MatplotlibFigure(self, **kwargs)
+        self._convert_to_html()
+
+    def _convert_to_html(self) -> None:
+        with io.StringIO() as output:
+            self.figure.savefig(output, format='svg')
+            self._props['innerHTML'] = output.getvalue()
+
+    def update(self) -> None:
+        self._convert_to_html()
+        return super().update()

+ 2 - 0
nicegui/ui.py

@@ -50,6 +50,7 @@ __all__ = [
     'list',
     'log',
     'markdown',
+    'matplotlib',
     'menu',
     'menu_item',
     'mermaid',
@@ -179,6 +180,7 @@ from .elements.pagination import Pagination as pagination
 from .elements.plotly import Plotly as plotly
 from .elements.progress import CircularProgress as circular_progress
 from .elements.progress import LinearProgress as linear_progress
+from .elements.pyplot import Matplotlib as matplotlib
 from .elements.pyplot import Pyplot as pyplot
 from .elements.query import Query as query
 from .elements.radio import Radio as radio

+ 17 - 0
website/documentation/content/matplotlib_documentation.py

@@ -0,0 +1,17 @@
+from nicegui import ui
+
+from . import doc
+
+
+@doc.demo(ui.matplotlib)
+def main_demo() -> None:
+    import numpy as np
+
+    with ui.matplotlib(figsize=(3, 2)).figure as fig:
+        x = np.linspace(0.0, 5.0)
+        y = np.cos(2 * np.pi * x) * np.exp(-x)
+        ax = fig.gca()
+        ax.plot(x, y, '-')
+
+
+doc.reference(ui.matplotlib)

+ 4 - 3
website/documentation/content/section_data_elements.py

@@ -2,9 +2,9 @@ from nicegui import optional_features
 
 from . import (aggrid_documentation, circular_progress_documentation, code_documentation, doc, echart_documentation,
                editor_documentation, highchart_documentation, json_editor_documentation, leaflet_documentation,
-               line_plot_documentation, linear_progress_documentation, log_documentation, plotly_documentation,
-               pyplot_documentation, scene_documentation, spinner_documentation, table_documentation,
-               tree_documentation)
+               line_plot_documentation, linear_progress_documentation, log_documentation, matplotlib_documentation,
+               plotly_documentation, pyplot_documentation, scene_documentation, spinner_documentation,
+               table_documentation, tree_documentation)
 
 doc.title('*Data* Elements')
 
@@ -15,6 +15,7 @@ if optional_features.has('highcharts'):
 doc.intro(echart_documentation)
 if optional_features.has('matplotlib'):
     doc.intro(pyplot_documentation)
+    doc.intro(matplotlib_documentation)
     doc.intro(line_plot_documentation)
 if optional_features.has('plotly'):
     doc.intro(plotly_documentation)