浏览代码

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 asyncio
 import io
 import io
 import os
 import os
@@ -11,8 +13,22 @@ from ..element import Element
 
 
 try:
 try:
     if os.environ.get('MATPLOTLIB', 'true').lower() == 'true':
     if os.environ.get('MATPLOTLIB', 'true').lower() == 'true':
+        import matplotlib.figure
         import matplotlib.pyplot as plt
         import matplotlib.pyplot as plt
         optional_features.register('matplotlib')
         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:
 except ImportError:
     pass
     pass
 
 
@@ -57,3 +73,30 @@ class Pyplot(Element):
         while self.client.id in Client.instances:
         while self.client.id in Client.instances:
             await asyncio.sleep(1.0)
             await asyncio.sleep(1.0)
         plt.close(self.fig)
         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',
     'list',
     'log',
     'log',
     'markdown',
     'markdown',
+    'matplotlib',
     'menu',
     'menu',
     'menu_item',
     'menu_item',
     'mermaid',
     'mermaid',
@@ -179,6 +180,7 @@ from .elements.pagination import Pagination as pagination
 from .elements.plotly import Plotly as plotly
 from .elements.plotly import Plotly as plotly
 from .elements.progress import CircularProgress as circular_progress
 from .elements.progress import CircularProgress as circular_progress
 from .elements.progress import LinearProgress as linear_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.pyplot import Pyplot as pyplot
 from .elements.query import Query as query
 from .elements.query import Query as query
 from .elements.radio import Radio as radio
 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,
 from . import (aggrid_documentation, circular_progress_documentation, code_documentation, doc, echart_documentation,
                editor_documentation, highchart_documentation, json_editor_documentation, leaflet_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')
 doc.title('*Data* Elements')
 
 
@@ -15,6 +15,7 @@ if optional_features.has('highcharts'):
 doc.intro(echart_documentation)
 doc.intro(echart_documentation)
 if optional_features.has('matplotlib'):
 if optional_features.has('matplotlib'):
     doc.intro(pyplot_documentation)
     doc.intro(pyplot_documentation)
+    doc.intro(matplotlib_documentation)
     doc.intro(line_plot_documentation)
     doc.intro(line_plot_documentation)
 if optional_features.has('plotly'):
 if optional_features.has('plotly'):
     doc.intro(plotly_documentation)
     doc.intro(plotly_documentation)