mirror of
https://github.com/Estom/notes.git
synced 2026-04-01 18:11:42 +08:00
matplotlib & pandas
This commit is contained in:
59
Python/matplotlab/gallery/user_interfaces/canvasagg.md
Normal file
59
Python/matplotlab/gallery/user_interfaces/canvasagg.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# CanvasAgg演示
|
||||
|
||||
此示例展示了如何直接使用AGG后端创建图像,对于希望完全控制其代码而不使用pylot界面来管理图形、图形关闭等的Web应用程序开发人员来说,这可能是有用的。
|
||||
|
||||
**注意:**没有必要避免使用图形前端 - 只需将后端设置为“Agg”就足够了。
|
||||
|
||||
在这个例子中,我们展示了如何将画布的内容保存到文件,以及如何将它们提取到一个字符串,该字符串可以传递给PIL或放在一个numpy数组中。 后一种功能允许例如使用没有文档到磁盘的cp脚本。
|
||||
|
||||
```python
|
||||
from matplotlib.backends.backend_agg import FigureCanvasAgg
|
||||
from matplotlib.figure import Figure
|
||||
import numpy as np
|
||||
|
||||
fig = Figure(figsize=(5, 4), dpi=100)
|
||||
# A canvas must be manually attached to the figure (pyplot would automatically
|
||||
# do it). This is done by instantiating the canvas with the figure as
|
||||
# argument.
|
||||
canvas = FigureCanvasAgg(fig)
|
||||
|
||||
# Do some plotting.
|
||||
ax = fig.add_subplot(111)
|
||||
ax.plot([1, 2, 3])
|
||||
|
||||
# Option 1: Save the figure to a file; can also be a file-like object (BytesIO,
|
||||
# etc.).
|
||||
fig.savefig("test.png")
|
||||
|
||||
# Option 2: Save the figure to a string.
|
||||
canvas.draw()
|
||||
s, (width, height) = canvas.print_to_buffer()
|
||||
|
||||
# Option 2a: Convert to a NumPy array.
|
||||
X = np.fromstring(s, np.uint8).reshape((height, width, 4))
|
||||
|
||||
# Option 2b: Pass off to PIL.
|
||||
from PIL import Image
|
||||
im = Image.frombytes("RGBA", (width, height), s)
|
||||
|
||||
# Uncomment this line to display the image using ImageMagick's `display` tool.
|
||||
# im.show()
|
||||
```
|
||||
|
||||
## 参考
|
||||
|
||||
此示例中显示了以下函数,方法,类和模块的使用:
|
||||
|
||||
```python
|
||||
import matplotlib
|
||||
matplotlib.backends.backend_agg.FigureCanvasAgg
|
||||
matplotlib.figure.Figure
|
||||
matplotlib.figure.Figure.add_subplot
|
||||
matplotlib.figure.Figure.savefig
|
||||
matplotlib.axes.Axes.plot
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: canvasagg.py](https://matplotlib.org/_downloads/canvasagg.py)
|
||||
- [下载Jupyter notebook: canvasagg.ipynb](https://matplotlib.org/_downloads/canvasagg.ipynb)
|
||||
@@ -0,0 +1,46 @@
|
||||
# 嵌入GTK3 Panzoom
|
||||
|
||||
演示通过pygobject访问GTK3的NavigationToolbar。
|
||||
|
||||
```python
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
from matplotlib.backends.backend_gtk3 import (
|
||||
NavigationToolbar2GTK3 as NavigationToolbar)
|
||||
from matplotlib.backends.backend_gtk3agg import (
|
||||
FigureCanvasGTK3Agg as FigureCanvas)
|
||||
from matplotlib.figure import Figure
|
||||
import numpy as np
|
||||
|
||||
win = Gtk.Window()
|
||||
win.connect("delete-event", Gtk.main_quit)
|
||||
win.set_default_size(400, 300)
|
||||
win.set_title("Embedding in GTK")
|
||||
|
||||
f = Figure(figsize=(5, 4), dpi=100)
|
||||
a = f.add_subplot(1, 1, 1)
|
||||
t = np.arange(0.0, 3.0, 0.01)
|
||||
s = np.sin(2*np.pi*t)
|
||||
a.plot(t, s)
|
||||
|
||||
vbox = Gtk.VBox()
|
||||
win.add(vbox)
|
||||
|
||||
# Add canvas to vbox
|
||||
canvas = FigureCanvas(f) # a Gtk.DrawingArea
|
||||
vbox.pack_start(canvas, True, True, 0)
|
||||
|
||||
# Create toolbar
|
||||
toolbar = NavigationToolbar(canvas, win)
|
||||
vbox.pack_start(toolbar, False, False, 0)
|
||||
|
||||
win.show_all()
|
||||
Gtk.main()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: embedding_in_gtk3_panzoom_sgskip.py](https://matplotlib.org/_downloads/embedding_in_gtk3_panzoom_sgskip.py)
|
||||
- [下载Jupyter notebook: embedding_in_gtk3_panzoom_sgskip.ipynb](https://matplotlib.org/_downloads/embedding_in_gtk3_panzoom_sgskip.ipynb)
|
||||
@@ -0,0 +1,42 @@
|
||||
# 嵌入GTK3
|
||||
|
||||
演示使用通过pygobject访问的GTK3将FigureCanvasGTK3Agg小部件添加到Gtk.ScrolledWindow。
|
||||
|
||||
```python
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
from matplotlib.backends.backend_gtk3agg import (
|
||||
FigureCanvasGTK3Agg as FigureCanvas)
|
||||
from matplotlib.figure import Figure
|
||||
import numpy as np
|
||||
|
||||
win = Gtk.Window()
|
||||
win.connect("delete-event", Gtk.main_quit)
|
||||
win.set_default_size(400, 300)
|
||||
win.set_title("Embedding in GTK")
|
||||
|
||||
f = Figure(figsize=(5, 4), dpi=100)
|
||||
a = f.add_subplot(111)
|
||||
t = np.arange(0.0, 3.0, 0.01)
|
||||
s = np.sin(2*np.pi*t)
|
||||
a.plot(t, s)
|
||||
|
||||
sw = Gtk.ScrolledWindow()
|
||||
win.add(sw)
|
||||
# A scrolled window border goes outside the scrollbars and viewport
|
||||
sw.set_border_width(10)
|
||||
|
||||
canvas = FigureCanvas(f) # a Gtk.DrawingArea
|
||||
canvas.set_size_request(800, 600)
|
||||
sw.add_with_viewport(canvas)
|
||||
|
||||
win.show_all()
|
||||
Gtk.main()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: embedding_in_gtk3_sgskip.py](https://matplotlib.org/_downloads/embedding_in_gtk3_sgskip.py)
|
||||
- [下载Jupyter notebook: embedding_in_gtk3_sgskip.ipynb](https://matplotlib.org/_downloads/embedding_in_gtk3_sgskip.ipynb)
|
||||
@@ -0,0 +1,64 @@
|
||||
# 嵌入Qt
|
||||
|
||||
简单的Qt应用程序嵌入Matplotlib画布。 该程序将使用Qt4和Qt5很好地工作。 通过将MPLBACKEND环境变量设置为“Qt4Agg”或“Qt5Agg”,或者首先导入所需的PyQt版本,可以选择任一版本的Qt(例如)。
|
||||
|
||||
```python
|
||||
import sys
|
||||
import time
|
||||
|
||||
import numpy as np
|
||||
|
||||
from matplotlib.backends.qt_compat import QtCore, QtWidgets, is_pyqt5
|
||||
if is_pyqt5():
|
||||
from matplotlib.backends.backend_qt5agg import (
|
||||
FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
|
||||
else:
|
||||
from matplotlib.backends.backend_qt4agg import (
|
||||
FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
|
||||
from matplotlib.figure import Figure
|
||||
|
||||
|
||||
class ApplicationWindow(QtWidgets.QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._main = QtWidgets.QWidget()
|
||||
self.setCentralWidget(self._main)
|
||||
layout = QtWidgets.QVBoxLayout(self._main)
|
||||
|
||||
static_canvas = FigureCanvas(Figure(figsize=(5, 3)))
|
||||
layout.addWidget(static_canvas)
|
||||
self.addToolBar(NavigationToolbar(static_canvas, self))
|
||||
|
||||
dynamic_canvas = FigureCanvas(Figure(figsize=(5, 3)))
|
||||
layout.addWidget(dynamic_canvas)
|
||||
self.addToolBar(QtCore.Qt.BottomToolBarArea,
|
||||
NavigationToolbar(dynamic_canvas, self))
|
||||
|
||||
self._static_ax = static_canvas.figure.subplots()
|
||||
t = np.linspace(0, 10, 501)
|
||||
self._static_ax.plot(t, np.tan(t), ".")
|
||||
|
||||
self._dynamic_ax = dynamic_canvas.figure.subplots()
|
||||
self._timer = dynamic_canvas.new_timer(
|
||||
100, [(self._update_canvas, (), {})])
|
||||
self._timer.start()
|
||||
|
||||
def _update_canvas(self):
|
||||
self._dynamic_ax.clear()
|
||||
t = np.linspace(0, 10, 101)
|
||||
# Shift the sinusoid as a function of time.
|
||||
self._dynamic_ax.plot(t, np.sin(t + time.time()))
|
||||
self._dynamic_ax.figure.canvas.draw()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
qapp = QtWidgets.QApplication(sys.argv)
|
||||
app = ApplicationWindow()
|
||||
app.show()
|
||||
qapp.exec_()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: embedding_in_qt_sgskip.py](https://matplotlib.org/_downloads/embedding_in_qt_sgskip.py)
|
||||
- [下载Jupyter notebook: embedding_in_qt_sgskip.ipynb](https://matplotlib.org/_downloads/embedding_in_qt_sgskip.ipynb)
|
||||
@@ -0,0 +1,56 @@
|
||||
# 嵌入Tk
|
||||
|
||||
```python
|
||||
import tkinter
|
||||
|
||||
from matplotlib.backends.backend_tkagg import (
|
||||
FigureCanvasTkAgg, NavigationToolbar2Tk)
|
||||
# Implement the default Matplotlib key bindings.
|
||||
from matplotlib.backend_bases import key_press_handler
|
||||
from matplotlib.figure import Figure
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
root = tkinter.Tk()
|
||||
root.wm_title("Embedding in Tk")
|
||||
|
||||
fig = Figure(figsize=(5, 4), dpi=100)
|
||||
t = np.arange(0, 3, .01)
|
||||
fig.add_subplot(111).plot(t, 2 * np.sin(2 * np.pi * t))
|
||||
|
||||
canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea.
|
||||
canvas.draw()
|
||||
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
|
||||
|
||||
toolbar = NavigationToolbar2Tk(canvas, root)
|
||||
toolbar.update()
|
||||
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
|
||||
|
||||
|
||||
def on_key_press(event):
|
||||
print("you pressed {}".format(event.key))
|
||||
key_press_handler(event, canvas, toolbar)
|
||||
|
||||
|
||||
canvas.mpl_connect("key_press_event", on_key_press)
|
||||
|
||||
|
||||
def _quit():
|
||||
root.quit() # stops mainloop
|
||||
root.destroy() # this is necessary on Windows to prevent
|
||||
# Fatal Python Error: PyEval_RestoreThread: NULL tstate
|
||||
|
||||
|
||||
button = tkinter.Button(master=root, text="Quit", command=_quit)
|
||||
button.pack(side=tkinter.BOTTOM)
|
||||
|
||||
tkinter.mainloop()
|
||||
# If you put root.destroy() here, it will cause an error if the window is
|
||||
# closed with the window manager.
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: embedding_in_tk_sgskip.py](https://matplotlib.org/_downloads/embedding_in_tk_sgskip.py)
|
||||
- [下载Jupyter notebook: embedding_in_tk_sgskip.ipynb](https://matplotlib.org/_downloads/embedding_in_tk_sgskip.ipynb)
|
||||
@@ -0,0 +1,64 @@
|
||||
# 嵌入Wx2
|
||||
|
||||
如何在具有新工具栏的应用程序中使用wxagg的示例
|
||||
|
||||
```python
|
||||
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
|
||||
from matplotlib.backends.backend_wx import NavigationToolbar2Wx as NavigationToolbar
|
||||
from matplotlib.figure import Figure
|
||||
|
||||
import numpy as np
|
||||
|
||||
import wx
|
||||
import wx.lib.mixins.inspection as WIT
|
||||
|
||||
|
||||
class CanvasFrame(wx.Frame):
|
||||
def __init__(self):
|
||||
wx.Frame.__init__(self, None, -1,
|
||||
'CanvasFrame', size=(550, 350))
|
||||
|
||||
self.figure = Figure()
|
||||
self.axes = self.figure.add_subplot(111)
|
||||
t = np.arange(0.0, 3.0, 0.01)
|
||||
s = np.sin(2 * np.pi * t)
|
||||
|
||||
self.axes.plot(t, s)
|
||||
self.canvas = FigureCanvas(self, -1, self.figure)
|
||||
|
||||
self.sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.EXPAND)
|
||||
self.SetSizer(self.sizer)
|
||||
self.Fit()
|
||||
|
||||
self.add_toolbar() # comment this out for no toolbar
|
||||
|
||||
def add_toolbar(self):
|
||||
self.toolbar = NavigationToolbar(self.canvas)
|
||||
self.toolbar.Realize()
|
||||
# By adding toolbar in sizer, we are able to put it at the bottom
|
||||
# of the frame - so appearance is closer to GTK version.
|
||||
self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
|
||||
# update the axes menu on the toolbar
|
||||
self.toolbar.update()
|
||||
|
||||
|
||||
# alternatively you could use
|
||||
#class App(wx.App):
|
||||
class App(WIT.InspectableApp):
|
||||
def OnInit(self):
|
||||
'Create the main window and insert the custom frame'
|
||||
self.Init()
|
||||
frame = CanvasFrame()
|
||||
frame.Show(True)
|
||||
|
||||
return True
|
||||
|
||||
app = App(0)
|
||||
app.MainLoop()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: embedding_in_wx2_sgskip.py](https://matplotlib.org/_downloads/embedding_in_wx2_sgskip.py)
|
||||
- [下载Jupyter notebook: embedding_in_wx2_sgskip.ipynb](https://matplotlib.org/_downloads/embedding_in_wx2_sgskip.ipynb)
|
||||
@@ -0,0 +1,149 @@
|
||||
# 嵌入Wx3
|
||||
|
||||
版权所有(C)2003-2004 Andrew Straw和Jeremy O'Donoghue等人
|
||||
|
||||
许可证:此作品根据PSF许可。该文档也应该在 https://docs.python.org/3/license.html 上提供
|
||||
|
||||
这是使用matplotlib和wx的另一个例子。 希望这是功能齐全的:
|
||||
|
||||
- matplotlib工具栏和WX按钮
|
||||
- 完整的wxApp框架,包括小部件交互
|
||||
- XRC(XML wxWidgets资源)文件创建GUI(用XRCed制作)
|
||||
|
||||
这是从embedding_in_wx和dynamic_image_wxagg派生的。
|
||||
|
||||
感谢matplotlib和wx团队创建这样出色的软件!
|
||||
|
||||
```python
|
||||
import matplotlib
|
||||
import matplotlib.cm as cm
|
||||
import matplotlib.cbook as cbook
|
||||
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
|
||||
from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavigationToolbar
|
||||
from matplotlib.figure import Figure
|
||||
import numpy as np
|
||||
|
||||
import wx
|
||||
import wx.xrc as xrc
|
||||
|
||||
ERR_TOL = 1e-5 # floating point slop for peak-detection
|
||||
|
||||
|
||||
matplotlib.rc('image', origin='lower')
|
||||
|
||||
|
||||
class PlotPanel(wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__(self, parent, -1)
|
||||
|
||||
self.fig = Figure((5, 4), 75)
|
||||
self.canvas = FigureCanvas(self, -1, self.fig)
|
||||
self.toolbar = NavigationToolbar(self.canvas) # matplotlib toolbar
|
||||
self.toolbar.Realize()
|
||||
# self.toolbar.set_active([0,1])
|
||||
|
||||
# Now put all into a sizer
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
# This way of adding to sizer allows resizing
|
||||
sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
|
||||
# Best to allow the toolbar to resize!
|
||||
sizer.Add(self.toolbar, 0, wx.GROW)
|
||||
self.SetSizer(sizer)
|
||||
self.Fit()
|
||||
|
||||
def init_plot_data(self):
|
||||
a = self.fig.add_subplot(111)
|
||||
|
||||
x = np.arange(120.0) * 2 * np.pi / 60.0
|
||||
y = np.arange(100.0) * 2 * np.pi / 50.0
|
||||
self.x, self.y = np.meshgrid(x, y)
|
||||
z = np.sin(self.x) + np.cos(self.y)
|
||||
self.im = a.imshow(z, cmap=cm.RdBu) # , interpolation='nearest')
|
||||
|
||||
zmax = np.max(z) - ERR_TOL
|
||||
ymax_i, xmax_i = np.nonzero(z >= zmax)
|
||||
if self.im.origin == 'upper':
|
||||
ymax_i = z.shape[0] - ymax_i
|
||||
self.lines = a.plot(xmax_i, ymax_i, 'ko')
|
||||
|
||||
self.toolbar.update() # Not sure why this is needed - ADS
|
||||
|
||||
def GetToolBar(self):
|
||||
# You will need to override GetToolBar if you are using an
|
||||
# unmanaged toolbar in your frame
|
||||
return self.toolbar
|
||||
|
||||
def OnWhiz(self, evt):
|
||||
self.x += np.pi / 15
|
||||
self.y += np.pi / 20
|
||||
z = np.sin(self.x) + np.cos(self.y)
|
||||
self.im.set_array(z)
|
||||
|
||||
zmax = np.max(z) - ERR_TOL
|
||||
ymax_i, xmax_i = np.nonzero(z >= zmax)
|
||||
if self.im.origin == 'upper':
|
||||
ymax_i = z.shape[0] - ymax_i
|
||||
self.lines[0].set_data(xmax_i, ymax_i)
|
||||
|
||||
self.canvas.draw()
|
||||
|
||||
|
||||
class MyApp(wx.App):
|
||||
def OnInit(self):
|
||||
xrcfile = cbook.get_sample_data('embedding_in_wx3.xrc',
|
||||
asfileobj=False)
|
||||
print('loading', xrcfile)
|
||||
|
||||
self.res = xrc.XmlResource(xrcfile)
|
||||
|
||||
# main frame and panel ---------
|
||||
|
||||
self.frame = self.res.LoadFrame(None, "MainFrame")
|
||||
self.panel = xrc.XRCCTRL(self.frame, "MainPanel")
|
||||
|
||||
# matplotlib panel -------------
|
||||
|
||||
# container for matplotlib panel (I like to make a container
|
||||
# panel for our panel so I know where it'll go when in XRCed.)
|
||||
plot_container = xrc.XRCCTRL(self.frame, "plot_container_panel")
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
# matplotlib panel itself
|
||||
self.plotpanel = PlotPanel(plot_container)
|
||||
self.plotpanel.init_plot_data()
|
||||
|
||||
# wx boilerplate
|
||||
sizer.Add(self.plotpanel, 1, wx.EXPAND)
|
||||
plot_container.SetSizer(sizer)
|
||||
|
||||
# whiz button ------------------
|
||||
whiz_button = xrc.XRCCTRL(self.frame, "whiz_button")
|
||||
whiz_button.Bind(wx.EVT_BUTTON, self.plotpanel.OnWhiz)
|
||||
|
||||
# bang button ------------------
|
||||
bang_button = xrc.XRCCTRL(self.frame, "bang_button")
|
||||
bang_button.Bind(wx.EVT_BUTTON, self.OnBang)
|
||||
|
||||
# final setup ------------------
|
||||
sizer = self.panel.GetSizer()
|
||||
self.frame.Show(1)
|
||||
|
||||
self.SetTopWindow(self.frame)
|
||||
|
||||
return True
|
||||
|
||||
def OnBang(self, event):
|
||||
bang_count = xrc.XRCCTRL(self.frame, "bang_count")
|
||||
bangs = bang_count.GetValue()
|
||||
bangs = int(bangs) + 1
|
||||
bang_count.SetValue(str(bangs))
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = MyApp(0)
|
||||
app.MainLoop()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: embedding_in_wx3_sgskip.py](https://matplotlib.org/_downloads/embedding_in_wx3_sgskip.py)
|
||||
- [下载Jupyter notebook: embedding_in_wx3_sgskip.ipynb](https://matplotlib.org/_downloads/embedding_in_wx3_sgskip.ipynb)
|
||||
@@ -0,0 +1,95 @@
|
||||
# 嵌入Wx4
|
||||
|
||||
如何在具有自定义工具栏的应用程序中使用wxagg的示例。
|
||||
|
||||
```python
|
||||
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
|
||||
from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavigationToolbar
|
||||
from matplotlib.backends.backend_wx import _load_bitmap
|
||||
from matplotlib.figure import Figure
|
||||
|
||||
import numpy as np
|
||||
|
||||
import wx
|
||||
|
||||
|
||||
class MyNavigationToolbar(NavigationToolbar):
|
||||
"""
|
||||
Extend the default wx toolbar with your own event handlers
|
||||
"""
|
||||
ON_CUSTOM = wx.NewId()
|
||||
|
||||
def __init__(self, canvas, cankill):
|
||||
NavigationToolbar.__init__(self, canvas)
|
||||
|
||||
# for simplicity I'm going to reuse a bitmap from wx, you'll
|
||||
# probably want to add your own.
|
||||
self.AddTool(self.ON_CUSTOM, 'Click me', _load_bitmap('back.png'),
|
||||
'Activate custom contol')
|
||||
self.Bind(wx.EVT_TOOL, self._on_custom, id=self.ON_CUSTOM)
|
||||
|
||||
def _on_custom(self, evt):
|
||||
# add some text to the axes in a random location in axes (0,1)
|
||||
# coords) with a random color
|
||||
|
||||
# get the axes
|
||||
ax = self.canvas.figure.axes[0]
|
||||
|
||||
# generate a random location can color
|
||||
x, y = np.random.rand(2)
|
||||
rgb = np.random.rand(3)
|
||||
|
||||
# add the text and draw
|
||||
ax.text(x, y, 'You clicked me',
|
||||
transform=ax.transAxes,
|
||||
color=rgb)
|
||||
self.canvas.draw()
|
||||
evt.Skip()
|
||||
|
||||
|
||||
class CanvasFrame(wx.Frame):
|
||||
def __init__(self):
|
||||
wx.Frame.__init__(self, None, -1,
|
||||
'CanvasFrame', size=(550, 350))
|
||||
|
||||
self.figure = Figure(figsize=(5, 4), dpi=100)
|
||||
self.axes = self.figure.add_subplot(111)
|
||||
t = np.arange(0.0, 3.0, 0.01)
|
||||
s = np.sin(2 * np.pi * t)
|
||||
|
||||
self.axes.plot(t, s)
|
||||
|
||||
self.canvas = FigureCanvas(self, -1, self.figure)
|
||||
|
||||
self.sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
self.sizer.Add(self.canvas, 1, wx.TOP | wx.LEFT | wx.EXPAND)
|
||||
|
||||
self.toolbar = MyNavigationToolbar(self.canvas, True)
|
||||
self.toolbar.Realize()
|
||||
# By adding toolbar in sizer, we are able to put it at the bottom
|
||||
# of the frame - so appearance is closer to GTK version.
|
||||
self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
|
||||
|
||||
# update the axes menu on the toolbar
|
||||
self.toolbar.update()
|
||||
self.SetSizer(self.sizer)
|
||||
self.Fit()
|
||||
|
||||
|
||||
class App(wx.App):
|
||||
def OnInit(self):
|
||||
'Create the main window and insert the custom frame'
|
||||
frame = CanvasFrame()
|
||||
frame.Show(True)
|
||||
|
||||
return True
|
||||
|
||||
app = App(0)
|
||||
app.MainLoop()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: embedding_in_wx4_sgskip.py](https://matplotlib.org/_downloads/embedding_in_wx4_sgskip.py)
|
||||
- [下载Jupyter notebook: embedding_in_wx4_sgskip.ipynb](https://matplotlib.org/_downloads/embedding_in_wx4_sgskip.ipynb)
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
# 嵌入Wx5
|
||||
|
||||
```python
|
||||
import wx
|
||||
import wx.lib.agw.aui as aui
|
||||
import wx.lib.mixins.inspection as wit
|
||||
|
||||
import matplotlib as mpl
|
||||
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
|
||||
from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavigationToolbar
|
||||
|
||||
|
||||
class Plot(wx.Panel):
|
||||
def __init__(self, parent, id=-1, dpi=None, **kwargs):
|
||||
wx.Panel.__init__(self, parent, id=id, **kwargs)
|
||||
self.figure = mpl.figure.Figure(dpi=dpi, figsize=(2, 2))
|
||||
self.canvas = FigureCanvas(self, -1, self.figure)
|
||||
self.toolbar = NavigationToolbar(self.canvas)
|
||||
self.toolbar.Realize()
|
||||
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
sizer.Add(self.canvas, 1, wx.EXPAND)
|
||||
sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
|
||||
self.SetSizer(sizer)
|
||||
|
||||
|
||||
class PlotNotebook(wx.Panel):
|
||||
def __init__(self, parent, id=-1):
|
||||
wx.Panel.__init__(self, parent, id=id)
|
||||
self.nb = aui.AuiNotebook(self)
|
||||
sizer = wx.BoxSizer()
|
||||
sizer.Add(self.nb, 1, wx.EXPAND)
|
||||
self.SetSizer(sizer)
|
||||
|
||||
def add(self, name="plot"):
|
||||
page = Plot(self.nb)
|
||||
self.nb.AddPage(page, name)
|
||||
return page.figure
|
||||
|
||||
|
||||
def demo():
|
||||
# alternatively you could use
|
||||
#app = wx.App()
|
||||
# InspectableApp is a great debug tool, see:
|
||||
# http://wiki.wxpython.org/Widget%20Inspection%20Tool
|
||||
app = wit.InspectableApp()
|
||||
frame = wx.Frame(None, -1, 'Plotter')
|
||||
plotter = PlotNotebook(frame)
|
||||
axes1 = plotter.add('figure 1').gca()
|
||||
axes1.plot([1, 2, 3], [2, 1, 4])
|
||||
axes2 = plotter.add('figure 2').gca()
|
||||
axes2.plot([1, 2, 3, 4, 5], [2, 1, 4, 2, 3])
|
||||
frame.Show()
|
||||
app.MainLoop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: embedding_in_wx5_sgskip.py](https://matplotlib.org/_downloads/embedding_in_wx5_sgskip.py)
|
||||
- [下载Jupyter notebook: embedding_in_wx5_sgskip.ipynb](https://matplotlib.org/_downloads/embedding_in_wx5_sgskip.ipynb)
|
||||
@@ -0,0 +1,249 @@
|
||||
# 嵌入WebAgg
|
||||
|
||||
此示例演示如何在您自己的Web应用程序和框架中嵌入matplotlib WebAgg交互式绘图。
|
||||
基于龙卷风的服务器“侧面”是基于龙卷风的服务器。
|
||||
|
||||
使用的框架必须支持Web套接字。
|
||||
|
||||
``` python
|
||||
import io
|
||||
|
||||
try:
|
||||
import tornado
|
||||
except ImportError:
|
||||
raise RuntimeError("This example requires tornado.")
|
||||
import tornado.web
|
||||
import tornado.httpserver
|
||||
import tornado.ioloop
|
||||
import tornado.websocket
|
||||
|
||||
|
||||
from matplotlib.backends.backend_webagg_core import (
|
||||
FigureManagerWebAgg, new_figure_manager_given_figure)
|
||||
from matplotlib.figure import Figure
|
||||
|
||||
import numpy as np
|
||||
|
||||
import json
|
||||
|
||||
|
||||
def create_figure():
|
||||
"""
|
||||
Creates a simple example figure.
|
||||
"""
|
||||
fig = Figure()
|
||||
a = fig.add_subplot(111)
|
||||
t = np.arange(0.0, 3.0, 0.01)
|
||||
s = np.sin(2 * np.pi * t)
|
||||
a.plot(t, s)
|
||||
return fig
|
||||
|
||||
|
||||
# The following is the content of the web page. You would normally
|
||||
# generate this using some sort of template facility in your web
|
||||
# framework, but here we just use Python string formatting.
|
||||
html_content = """
|
||||
<html>
|
||||
<head>
|
||||
<!-- TODO: There should be a way to include all of the required javascript
|
||||
and CSS so matplotlib can add to the set in the future if it
|
||||
needs to. -->
|
||||
<link rel="stylesheet" href="_static/css/page.css" type="text/css">
|
||||
<link rel="stylesheet" href="_static/css/boilerplate.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/css/fbm.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/jquery/css/themes/base/jquery-ui.min.css" >
|
||||
<script src="_static/jquery/js/jquery-1.11.3.min.js"></script>
|
||||
<script src="_static/jquery/js/jquery-ui.min.js"></script>
|
||||
<script src="mpl.js"></script>
|
||||
|
||||
<script>
|
||||
/* This is a callback that is called when the user saves
|
||||
(downloads) a file. Its purpose is really to map from a
|
||||
figure and file format to a url in the application. */
|
||||
function ondownload(figure, format) {
|
||||
window.open('download.' + format, '_blank');
|
||||
};
|
||||
|
||||
$(document).ready(
|
||||
function() {
|
||||
/* It is up to the application to provide a websocket that the figure
|
||||
will use to communicate to the server. This websocket object can
|
||||
also be a "fake" websocket that underneath multiplexes messages
|
||||
from multiple figures, if necessary. */
|
||||
var websocket_type = mpl.get_websocket_type();
|
||||
var websocket = new websocket_type("%(ws_uri)sws");
|
||||
|
||||
// mpl.figure creates a new figure on the webpage.
|
||||
var fig = new mpl.figure(
|
||||
// A unique numeric identifier for the figure
|
||||
%(fig_id)s,
|
||||
// A websocket object (or something that behaves like one)
|
||||
websocket,
|
||||
// A function called when a file type is selected for download
|
||||
ondownload,
|
||||
// The HTML element in which to place the figure
|
||||
$('div#figure'));
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<title>matplotlib</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="figure">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
|
||||
class MyApplication(tornado.web.Application):
|
||||
class MainPage(tornado.web.RequestHandler):
|
||||
"""
|
||||
Serves the main HTML page.
|
||||
"""
|
||||
|
||||
def get(self):
|
||||
manager = self.application.manager
|
||||
ws_uri = "ws://{req.host}/".format(req=self.request)
|
||||
content = html_content % {
|
||||
"ws_uri": ws_uri, "fig_id": manager.num}
|
||||
self.write(content)
|
||||
|
||||
class MplJs(tornado.web.RequestHandler):
|
||||
"""
|
||||
Serves the generated matplotlib javascript file. The content
|
||||
is dynamically generated based on which toolbar functions the
|
||||
user has defined. Call `FigureManagerWebAgg` to get its
|
||||
content.
|
||||
"""
|
||||
|
||||
def get(self):
|
||||
self.set_header('Content-Type', 'application/javascript')
|
||||
js_content = FigureManagerWebAgg.get_javascript()
|
||||
|
||||
self.write(js_content)
|
||||
|
||||
class Download(tornado.web.RequestHandler):
|
||||
"""
|
||||
Handles downloading of the figure in various file formats.
|
||||
"""
|
||||
|
||||
def get(self, fmt):
|
||||
manager = self.application.manager
|
||||
|
||||
mimetypes = {
|
||||
'ps': 'application/postscript',
|
||||
'eps': 'application/postscript',
|
||||
'pdf': 'application/pdf',
|
||||
'svg': 'image/svg+xml',
|
||||
'png': 'image/png',
|
||||
'jpeg': 'image/jpeg',
|
||||
'tif': 'image/tiff',
|
||||
'emf': 'application/emf'
|
||||
}
|
||||
|
||||
self.set_header('Content-Type', mimetypes.get(fmt, 'binary'))
|
||||
|
||||
buff = io.BytesIO()
|
||||
manager.canvas.figure.savefig(buff, format=fmt)
|
||||
self.write(buff.getvalue())
|
||||
|
||||
class WebSocket(tornado.websocket.WebSocketHandler):
|
||||
"""
|
||||
A websocket for interactive communication between the plot in
|
||||
the browser and the server.
|
||||
|
||||
In addition to the methods required by tornado, it is required to
|
||||
have two callback methods:
|
||||
|
||||
- ``send_json(json_content)`` is called by matplotlib when
|
||||
it needs to send json to the browser. `json_content` is
|
||||
a JSON tree (Python dictionary), and it is the responsibility
|
||||
of this implementation to encode it as a string to send over
|
||||
the socket.
|
||||
|
||||
- ``send_binary(blob)`` is called to send binary image data
|
||||
to the browser.
|
||||
"""
|
||||
supports_binary = True
|
||||
|
||||
def open(self):
|
||||
# Register the websocket with the FigureManager.
|
||||
manager = self.application.manager
|
||||
manager.add_web_socket(self)
|
||||
if hasattr(self, 'set_nodelay'):
|
||||
self.set_nodelay(True)
|
||||
|
||||
def on_close(self):
|
||||
# When the socket is closed, deregister the websocket with
|
||||
# the FigureManager.
|
||||
manager = self.application.manager
|
||||
manager.remove_web_socket(self)
|
||||
|
||||
def on_message(self, message):
|
||||
# The 'supports_binary' message is relevant to the
|
||||
# websocket itself. The other messages get passed along
|
||||
# to matplotlib as-is.
|
||||
|
||||
# Every message has a "type" and a "figure_id".
|
||||
message = json.loads(message)
|
||||
if message['type'] == 'supports_binary':
|
||||
self.supports_binary = message['value']
|
||||
else:
|
||||
manager = self.application.manager
|
||||
manager.handle_json(message)
|
||||
|
||||
def send_json(self, content):
|
||||
self.write_message(json.dumps(content))
|
||||
|
||||
def send_binary(self, blob):
|
||||
if self.supports_binary:
|
||||
self.write_message(blob, binary=True)
|
||||
else:
|
||||
data_uri = "data:image/png;base64,{0}".format(
|
||||
blob.encode('base64').replace('\n', ''))
|
||||
self.write_message(data_uri)
|
||||
|
||||
def __init__(self, figure):
|
||||
self.figure = figure
|
||||
self.manager = new_figure_manager_given_figure(id(figure), figure)
|
||||
|
||||
super().__init__([
|
||||
# Static files for the CSS and JS
|
||||
(r'/_static/(.*)',
|
||||
tornado.web.StaticFileHandler,
|
||||
{'path': FigureManagerWebAgg.get_static_file_path()}),
|
||||
|
||||
# The page that contains all of the pieces
|
||||
('/', self.MainPage),
|
||||
|
||||
('/mpl.js', self.MplJs),
|
||||
|
||||
# Sends images and events to the browser, and receives
|
||||
# events from the browser
|
||||
('/ws', self.WebSocket),
|
||||
|
||||
# Handles the downloading (i.e., saving) of static images
|
||||
(r'/download.([a-z0-9.]+)', self.Download),
|
||||
])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
figure = create_figure()
|
||||
application = MyApplication(figure)
|
||||
|
||||
http_server = tornado.httpserver.HTTPServer(application)
|
||||
http_server.listen(8080)
|
||||
|
||||
print("http://127.0.0.1:8080/")
|
||||
print("Press Ctrl+C to quit")
|
||||
|
||||
tornado.ioloop.IOLoop.instance().start()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: embedding_webagg_sgskip.py](https://matplotlib.org/_downloads/embedding_webagg_sgskip.py)
|
||||
- [下载Jupyter notebook: embedding_webagg_sgskip.ipynb](https://matplotlib.org/_downloads/embedding_webagg_sgskip.ipynb)
|
||||
@@ -0,0 +1,237 @@
|
||||
# 傅立叶演示WX
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
|
||||
import wx
|
||||
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
|
||||
from matplotlib.figure import Figure
|
||||
|
||||
|
||||
class Knob(object):
|
||||
"""
|
||||
Knob - simple class with a "setKnob" method.
|
||||
A Knob instance is attached to a Param instance, e.g., param.attach(knob)
|
||||
Base class is for documentation purposes.
|
||||
"""
|
||||
|
||||
def setKnob(self, value):
|
||||
pass
|
||||
|
||||
|
||||
class Param(object):
|
||||
"""
|
||||
The idea of the "Param" class is that some parameter in the GUI may have
|
||||
several knobs that both control it and reflect the parameter's state, e.g.
|
||||
a slider, text, and dragging can all change the value of the frequency in
|
||||
the waveform of this example.
|
||||
The class allows a cleaner way to update/"feedback" to the other knobs when
|
||||
one is being changed. Also, this class handles min/max constraints for all
|
||||
the knobs.
|
||||
Idea - knob list - in "set" method, knob object is passed as well
|
||||
- the other knobs in the knob list have a "set" method which gets
|
||||
called for the others.
|
||||
"""
|
||||
|
||||
def __init__(self, initialValue=None, minimum=0., maximum=1.):
|
||||
self.minimum = minimum
|
||||
self.maximum = maximum
|
||||
if initialValue != self.constrain(initialValue):
|
||||
raise ValueError('illegal initial value')
|
||||
self.value = initialValue
|
||||
self.knobs = []
|
||||
|
||||
def attach(self, knob):
|
||||
self.knobs += [knob]
|
||||
|
||||
def set(self, value, knob=None):
|
||||
self.value = value
|
||||
self.value = self.constrain(value)
|
||||
for feedbackKnob in self.knobs:
|
||||
if feedbackKnob != knob:
|
||||
feedbackKnob.setKnob(self.value)
|
||||
return self.value
|
||||
|
||||
def constrain(self, value):
|
||||
if value <= self.minimum:
|
||||
value = self.minimum
|
||||
if value >= self.maximum:
|
||||
value = self.maximum
|
||||
return value
|
||||
|
||||
|
||||
class SliderGroup(Knob):
|
||||
def __init__(self, parent, label, param):
|
||||
self.sliderLabel = wx.StaticText(parent, label=label)
|
||||
self.sliderText = wx.TextCtrl(parent, -1, style=wx.TE_PROCESS_ENTER)
|
||||
self.slider = wx.Slider(parent, -1)
|
||||
# self.slider.SetMax(param.maximum*1000)
|
||||
self.slider.SetRange(0, param.maximum * 1000)
|
||||
self.setKnob(param.value)
|
||||
|
||||
sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sizer.Add(self.sliderLabel, 0,
|
||||
wx.EXPAND | wx.ALIGN_CENTER | wx.ALL,
|
||||
border=2)
|
||||
sizer.Add(self.sliderText, 0,
|
||||
wx.EXPAND | wx.ALIGN_CENTER | wx.ALL,
|
||||
border=2)
|
||||
sizer.Add(self.slider, 1, wx.EXPAND)
|
||||
self.sizer = sizer
|
||||
|
||||
self.slider.Bind(wx.EVT_SLIDER, self.sliderHandler)
|
||||
self.sliderText.Bind(wx.EVT_TEXT_ENTER, self.sliderTextHandler)
|
||||
|
||||
self.param = param
|
||||
self.param.attach(self)
|
||||
|
||||
def sliderHandler(self, evt):
|
||||
value = evt.GetInt() / 1000.
|
||||
self.param.set(value)
|
||||
|
||||
def sliderTextHandler(self, evt):
|
||||
value = float(self.sliderText.GetValue())
|
||||
self.param.set(value)
|
||||
|
||||
def setKnob(self, value):
|
||||
self.sliderText.SetValue('%g' % value)
|
||||
self.slider.SetValue(value * 1000)
|
||||
|
||||
|
||||
class FourierDemoFrame(wx.Frame):
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
panel = wx.Panel(self)
|
||||
|
||||
# create the GUI elements
|
||||
self.createCanvas(panel)
|
||||
self.createSliders(panel)
|
||||
|
||||
# place them in a sizer for the Layout
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
sizer.Add(self.canvas, 1, wx.EXPAND)
|
||||
sizer.Add(self.frequencySliderGroup.sizer, 0,
|
||||
wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=5)
|
||||
sizer.Add(self.amplitudeSliderGroup.sizer, 0,
|
||||
wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=5)
|
||||
panel.SetSizer(sizer)
|
||||
|
||||
def createCanvas(self, parent):
|
||||
self.lines = []
|
||||
self.figure = Figure()
|
||||
self.canvas = FigureCanvas(parent, -1, self.figure)
|
||||
self.canvas.callbacks.connect('button_press_event', self.mouseDown)
|
||||
self.canvas.callbacks.connect('motion_notify_event', self.mouseMotion)
|
||||
self.canvas.callbacks.connect('button_release_event', self.mouseUp)
|
||||
self.state = ''
|
||||
self.mouseInfo = (None, None, None, None)
|
||||
self.f0 = Param(2., minimum=0., maximum=6.)
|
||||
self.A = Param(1., minimum=0.01, maximum=2.)
|
||||
self.createPlots()
|
||||
|
||||
# Not sure I like having two params attached to the same Knob,
|
||||
# but that is what we have here... it works but feels kludgy -
|
||||
# although maybe it's not too bad since the knob changes both params
|
||||
# at the same time (both f0 and A are affected during a drag)
|
||||
self.f0.attach(self)
|
||||
self.A.attach(self)
|
||||
|
||||
def createSliders(self, panel):
|
||||
self.frequencySliderGroup = SliderGroup(
|
||||
panel,
|
||||
label='Frequency f0:',
|
||||
param=self.f0)
|
||||
self.amplitudeSliderGroup = SliderGroup(panel, label=' Amplitude a:',
|
||||
param=self.A)
|
||||
|
||||
def mouseDown(self, evt):
|
||||
if self.lines[0].contains(evt)[0]:
|
||||
self.state = 'frequency'
|
||||
elif self.lines[1].contains(evt)[0]:
|
||||
self.state = 'time'
|
||||
else:
|
||||
self.state = ''
|
||||
self.mouseInfo = (evt.xdata, evt.ydata,
|
||||
max(self.f0.value, .1),
|
||||
self.A.value)
|
||||
|
||||
def mouseMotion(self, evt):
|
||||
if self.state == '':
|
||||
return
|
||||
x, y = evt.xdata, evt.ydata
|
||||
if x is None: # outside the axes
|
||||
return
|
||||
x0, y0, f0Init, AInit = self.mouseInfo
|
||||
self.A.set(AInit + (AInit * (y - y0) / y0), self)
|
||||
if self.state == 'frequency':
|
||||
self.f0.set(f0Init + (f0Init * (x - x0) / x0))
|
||||
elif self.state == 'time':
|
||||
if (x - x0) / x0 != -1.:
|
||||
self.f0.set(1. / (1. / f0Init + (1. / f0Init * (x - x0) / x0)))
|
||||
|
||||
def mouseUp(self, evt):
|
||||
self.state = ''
|
||||
|
||||
def createPlots(self):
|
||||
# This method creates the subplots, waveforms and labels.
|
||||
# Later, when the waveforms or sliders are dragged, only the
|
||||
# waveform data will be updated (not here, but below in setKnob).
|
||||
self.subplot1, self.subplot2 = self.figure.subplots(2)
|
||||
x1, y1, x2, y2 = self.compute(self.f0.value, self.A.value)
|
||||
color = (1., 0., 0.)
|
||||
self.lines += self.subplot1.plot(x1, y1, color=color, linewidth=2)
|
||||
self.lines += self.subplot2.plot(x2, y2, color=color, linewidth=2)
|
||||
# Set some plot attributes
|
||||
self.subplot1.set_title(
|
||||
"Click and drag waveforms to change frequency and amplitude",
|
||||
fontsize=12)
|
||||
self.subplot1.set_ylabel("Frequency Domain Waveform X(f)", fontsize=8)
|
||||
self.subplot1.set_xlabel("frequency f", fontsize=8)
|
||||
self.subplot2.set_ylabel("Time Domain Waveform x(t)", fontsize=8)
|
||||
self.subplot2.set_xlabel("time t", fontsize=8)
|
||||
self.subplot1.set_xlim([-6, 6])
|
||||
self.subplot1.set_ylim([0, 1])
|
||||
self.subplot2.set_xlim([-2, 2])
|
||||
self.subplot2.set_ylim([-2, 2])
|
||||
self.subplot1.text(0.05, .95,
|
||||
r'$X(f) = \mathcal{F}\{x(t)\}$',
|
||||
verticalalignment='top',
|
||||
transform=self.subplot1.transAxes)
|
||||
self.subplot2.text(0.05, .95,
|
||||
r'$x(t) = a \cdot \cos(2\pi f_0 t) e^{-\pi t^2}$',
|
||||
verticalalignment='top',
|
||||
transform=self.subplot2.transAxes)
|
||||
|
||||
def compute(self, f0, A):
|
||||
f = np.arange(-6., 6., 0.02)
|
||||
t = np.arange(-2., 2., 0.01)
|
||||
x = A * np.cos(2 * np.pi * f0 * t) * np.exp(-np.pi * t ** 2)
|
||||
X = A / 2 * \
|
||||
(np.exp(-np.pi * (f - f0) ** 2) + np.exp(-np.pi * (f + f0) ** 2))
|
||||
return f, X, t, x
|
||||
|
||||
def setKnob(self, value):
|
||||
# Note, we ignore value arg here and just go by state of the params
|
||||
x1, y1, x2, y2 = self.compute(self.f0.value, self.A.value)
|
||||
# update the data of the two waveforms
|
||||
self.lines[0].set(xdata=x1, ydata=y1)
|
||||
self.lines[1].set(xdata=x2, ydata=y2)
|
||||
# make the canvas draw its contents again with the new data
|
||||
self.canvas.draw()
|
||||
|
||||
|
||||
class App(wx.App):
|
||||
def OnInit(self):
|
||||
self.frame1 = FourierDemoFrame(parent=None, title="Fourier Demo",
|
||||
size=(640, 480))
|
||||
self.frame1.Show()
|
||||
return True
|
||||
|
||||
app = App()
|
||||
app.MainLoop()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: fourier_demo_wx_sgskip.py](https://matplotlib.org/_downloads/fourier_demo_wx_sgskip.py)
|
||||
- [下载Jupyter notebook: fourier_demo_wx_sgskip.ipynb](https://matplotlib.org/_downloads/fourier_demo_wx_sgskip.ipynb)
|
||||
@@ -0,0 +1,94 @@
|
||||
# GTK电子表格
|
||||
|
||||
在应用程序中嵌入matplotlib并与treeview交互以存储数据的示例。双击条目以更新绘图数据。
|
||||
|
||||
```python
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('Gdk', '3.0')
|
||||
from gi.repository import Gtk, Gdk
|
||||
|
||||
from matplotlib.backends.backend_gtk3agg import FigureCanvas
|
||||
# from matplotlib.backends.backend_gtk3cairo import FigureCanvas
|
||||
|
||||
from numpy.random import random
|
||||
from matplotlib.figure import Figure
|
||||
|
||||
|
||||
class DataManager(Gtk.Window):
|
||||
numRows, numCols = 20, 10
|
||||
|
||||
data = random((numRows, numCols))
|
||||
|
||||
def __init__(self):
|
||||
Gtk.Window.__init__(self)
|
||||
self.set_default_size(600, 600)
|
||||
self.connect('destroy', lambda win: Gtk.main_quit())
|
||||
|
||||
self.set_title('GtkListStore demo')
|
||||
self.set_border_width(8)
|
||||
|
||||
vbox = Gtk.VBox(False, 8)
|
||||
self.add(vbox)
|
||||
|
||||
label = Gtk.Label('Double click a row to plot the data')
|
||||
|
||||
vbox.pack_start(label, False, False, 0)
|
||||
|
||||
sw = Gtk.ScrolledWindow()
|
||||
sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
|
||||
sw.set_policy(Gtk.PolicyType.NEVER,
|
||||
Gtk.PolicyType.AUTOMATIC)
|
||||
vbox.pack_start(sw, True, True, 0)
|
||||
|
||||
model = self.create_model()
|
||||
|
||||
self.treeview = Gtk.TreeView(model)
|
||||
self.treeview.set_rules_hint(True)
|
||||
|
||||
# matplotlib stuff
|
||||
fig = Figure(figsize=(6, 4))
|
||||
|
||||
self.canvas = FigureCanvas(fig) # a Gtk.DrawingArea
|
||||
vbox.pack_start(self.canvas, True, True, 0)
|
||||
ax = fig.add_subplot(111)
|
||||
self.line, = ax.plot(self.data[0, :], 'go') # plot the first row
|
||||
|
||||
self.treeview.connect('row-activated', self.plot_row)
|
||||
sw.add(self.treeview)
|
||||
|
||||
self.add_columns()
|
||||
|
||||
self.add_events(Gdk.EventMask.BUTTON_PRESS_MASK |
|
||||
Gdk.EventMask.KEY_PRESS_MASK |
|
||||
Gdk.EventMask.KEY_RELEASE_MASK)
|
||||
|
||||
def plot_row(self, treeview, path, view_column):
|
||||
ind, = path # get the index into data
|
||||
points = self.data[ind, :]
|
||||
self.line.set_ydata(points)
|
||||
self.canvas.draw()
|
||||
|
||||
def add_columns(self):
|
||||
for i in range(self.numCols):
|
||||
column = Gtk.TreeViewColumn(str(i), Gtk.CellRendererText(), text=i)
|
||||
self.treeview.append_column(column)
|
||||
|
||||
def create_model(self):
|
||||
types = [float]*self.numCols
|
||||
store = Gtk.ListStore(*types)
|
||||
|
||||
for row in self.data:
|
||||
store.append(tuple(row))
|
||||
return store
|
||||
|
||||
|
||||
manager = DataManager()
|
||||
manager.show_all()
|
||||
Gtk.main()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: gtk_spreadsheet_sgskip.py](https://matplotlib.org/_downloads/gtk_spreadsheet_sgskip.py)
|
||||
- [下载Jupyter notebook: gtk_spreadsheet_sgskip.ipynb](https://matplotlib.org/_downloads/gtk_spreadsheet_sgskip.ipynb)
|
||||
5
Python/matplotlab/gallery/user_interfaces/index.md
Normal file
5
Python/matplotlab/gallery/user_interfaces/index.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# 将Matplotlib嵌入图形用户界面中
|
||||
|
||||
您可以通过此处的embedding_in_SOMEGUI.py示例将Matplotlib直接嵌入到用户界面中。 目前matplotlib支持wxpython,pygtk,tkinter 和 pyqt4 / 5。
|
||||
|
||||
在将Matplotlib嵌入GUI时,您应该直接使用Matplotlib API而不是pylab / pyplot的继续接口,因此请查看examples / api目录,了解使用API的一些示例代码。
|
||||
133
Python/matplotlab/gallery/user_interfaces/mathtext_wx_sgskip.md
Normal file
133
Python/matplotlab/gallery/user_interfaces/mathtext_wx_sgskip.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# WX中的数学文本
|
||||
|
||||
演示如何将数学文本转换为wx.Bitmap,以便在wxPython的各种控件中显示。
|
||||
|
||||
```python
|
||||
import matplotlib
|
||||
matplotlib.use("WxAgg")
|
||||
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
|
||||
from matplotlib.backends.backend_wx import NavigationToolbar2Wx
|
||||
from matplotlib.figure import Figure
|
||||
import numpy as np
|
||||
|
||||
import wx
|
||||
|
||||
IS_GTK = 'wxGTK' in wx.PlatformInfo
|
||||
IS_WIN = 'wxMSW' in wx.PlatformInfo
|
||||
```
|
||||
|
||||
This is where the "magic" happens.
|
||||
|
||||
```python
|
||||
from matplotlib.mathtext import MathTextParser
|
||||
mathtext_parser = MathTextParser("Bitmap")
|
||||
|
||||
|
||||
def mathtext_to_wxbitmap(s):
|
||||
ftimage, depth = mathtext_parser.parse(s, 150)
|
||||
return wx.Bitmap.FromBufferRGBA(
|
||||
ftimage.get_width(), ftimage.get_height(),
|
||||
ftimage.as_rgba_str())
|
||||
```
|
||||
|
||||
```python
|
||||
functions = [
|
||||
(r'$\sin(2 \pi x)$', lambda x: np.sin(2*np.pi*x)),
|
||||
(r'$\frac{4}{3}\pi x^3$', lambda x: (4.0/3.0)*np.pi*x**3),
|
||||
(r'$\cos(2 \pi x)$', lambda x: np.cos(2*np.pi*x)),
|
||||
(r'$\log(x)$', lambda x: np.log(x))
|
||||
]
|
||||
|
||||
|
||||
class CanvasFrame(wx.Frame):
|
||||
def __init__(self, parent, title):
|
||||
wx.Frame.__init__(self, parent, -1, title, size=(550, 350))
|
||||
|
||||
self.figure = Figure()
|
||||
self.axes = self.figure.add_subplot(111)
|
||||
|
||||
self.canvas = FigureCanvas(self, -1, self.figure)
|
||||
|
||||
self.change_plot(0)
|
||||
|
||||
self.sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
self.add_buttonbar()
|
||||
self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
|
||||
self.add_toolbar() # comment this out for no toolbar
|
||||
|
||||
menuBar = wx.MenuBar()
|
||||
|
||||
# File Menu
|
||||
menu = wx.Menu()
|
||||
m_exit = menu.Append(wx.ID_EXIT, "E&xit\tAlt-X", "Exit this simple sample")
|
||||
menuBar.Append(menu, "&File")
|
||||
self.Bind(wx.EVT_MENU, self.OnClose, m_exit)
|
||||
|
||||
if IS_GTK or IS_WIN:
|
||||
# Equation Menu
|
||||
menu = wx.Menu()
|
||||
for i, (mt, func) in enumerate(functions):
|
||||
bm = mathtext_to_wxbitmap(mt)
|
||||
item = wx.MenuItem(menu, 1000 + i, " ")
|
||||
item.SetBitmap(bm)
|
||||
menu.Append(item)
|
||||
self.Bind(wx.EVT_MENU, self.OnChangePlot, item)
|
||||
menuBar.Append(menu, "&Functions")
|
||||
|
||||
self.SetMenuBar(menuBar)
|
||||
|
||||
self.SetSizer(self.sizer)
|
||||
self.Fit()
|
||||
|
||||
def add_buttonbar(self):
|
||||
self.button_bar = wx.Panel(self)
|
||||
self.button_bar_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
self.sizer.Add(self.button_bar, 0, wx.LEFT | wx.TOP | wx.GROW)
|
||||
|
||||
for i, (mt, func) in enumerate(functions):
|
||||
bm = mathtext_to_wxbitmap(mt)
|
||||
button = wx.BitmapButton(self.button_bar, 1000 + i, bm)
|
||||
self.button_bar_sizer.Add(button, 1, wx.GROW)
|
||||
self.Bind(wx.EVT_BUTTON, self.OnChangePlot, button)
|
||||
|
||||
self.button_bar.SetSizer(self.button_bar_sizer)
|
||||
|
||||
def add_toolbar(self):
|
||||
"""Copied verbatim from embedding_wx2.py"""
|
||||
self.toolbar = NavigationToolbar2Wx(self.canvas)
|
||||
self.toolbar.Realize()
|
||||
# By adding toolbar in sizer, we are able to put it at the bottom
|
||||
# of the frame - so appearance is closer to GTK version.
|
||||
self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
|
||||
# update the axes menu on the toolbar
|
||||
self.toolbar.update()
|
||||
|
||||
def OnChangePlot(self, event):
|
||||
self.change_plot(event.GetId() - 1000)
|
||||
|
||||
def change_plot(self, plot_number):
|
||||
t = np.arange(1.0, 3.0, 0.01)
|
||||
s = functions[plot_number][1](t)
|
||||
self.axes.clear()
|
||||
self.axes.plot(t, s)
|
||||
self.canvas.draw()
|
||||
|
||||
def OnClose(self, event):
|
||||
self.Destroy()
|
||||
|
||||
|
||||
class MyApp(wx.App):
|
||||
def OnInit(self):
|
||||
frame = CanvasFrame(None, "wxPython mathtext demo app")
|
||||
self.SetTopWindow(frame)
|
||||
frame.Show(True)
|
||||
return True
|
||||
|
||||
app = MyApp()
|
||||
app.MainLoop()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: mathtext_wx_sgskip.py](https://matplotlib.org/_downloads/mathtext_wx_sgskip.py)
|
||||
- [下载Jupyter notebook: mathtext_wx_sgskip.ipynb](https://matplotlib.org/_downloads/mathtext_wx_sgskip.ipynb)
|
||||
@@ -0,0 +1,55 @@
|
||||
# Matplotlib与Glade 3
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
from matplotlib.figure import Figure
|
||||
from matplotlib.backends.backend_gtk3agg import (
|
||||
FigureCanvasGTK3Agg as FigureCanvas)
|
||||
import numpy as np
|
||||
|
||||
|
||||
class Window1Signals(object):
|
||||
def on_window1_destroy(self, widget):
|
||||
Gtk.main_quit()
|
||||
|
||||
|
||||
def main():
|
||||
builder = Gtk.Builder()
|
||||
builder.add_objects_from_file(os.path.join(os.path.dirname(__file__),
|
||||
"mpl_with_glade3.glade"),
|
||||
("window1", ""))
|
||||
builder.connect_signals(Window1Signals())
|
||||
window = builder.get_object("window1")
|
||||
sw = builder.get_object("scrolledwindow1")
|
||||
|
||||
# Start of Matplotlib specific code
|
||||
figure = Figure(figsize=(8, 6), dpi=71)
|
||||
axis = figure.add_subplot(111)
|
||||
t = np.arange(0.0, 3.0, 0.01)
|
||||
s = np.sin(2*np.pi*t)
|
||||
axis.plot(t, s)
|
||||
|
||||
axis.set_xlabel('time [s]')
|
||||
axis.set_ylabel('voltage [V]')
|
||||
|
||||
canvas = FigureCanvas(figure) # a Gtk.DrawingArea
|
||||
canvas.set_size_request(800, 600)
|
||||
sw.add_with_viewport(canvas)
|
||||
# End of Matplotlib specific code
|
||||
|
||||
window.show_all()
|
||||
Gtk.main()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: mpl_with_glade3_sgskip.py](https://matplotlib.org/_downloads/mpl_with_glade3_sgskip.py)
|
||||
- [下载Jupyter notebook: mpl_with_glade3_sgskip.ipynb](https://matplotlib.org/_downloads/mpl_with_glade3_sgskip.ipynb)
|
||||
@@ -0,0 +1,55 @@
|
||||
# Pyplot与GTK
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
from matplotlib.figure import Figure
|
||||
from matplotlib.backends.backend_gtk3agg import (
|
||||
FigureCanvasGTK3Agg as FigureCanvas)
|
||||
import numpy as np
|
||||
|
||||
|
||||
class Window1Signals(object):
|
||||
def on_window1_destroy(self, widget):
|
||||
Gtk.main_quit()
|
||||
|
||||
|
||||
def main():
|
||||
builder = Gtk.Builder()
|
||||
builder.add_objects_from_file(os.path.join(os.path.dirname(__file__),
|
||||
"mpl_with_glade3.glade"),
|
||||
("window1", ""))
|
||||
builder.connect_signals(Window1Signals())
|
||||
window = builder.get_object("window1")
|
||||
sw = builder.get_object("scrolledwindow1")
|
||||
|
||||
# Start of Matplotlib specific code
|
||||
figure = Figure(figsize=(8, 6), dpi=71)
|
||||
axis = figure.add_subplot(111)
|
||||
t = np.arange(0.0, 3.0, 0.01)
|
||||
s = np.sin(2*np.pi*t)
|
||||
axis.plot(t, s)
|
||||
|
||||
axis.set_xlabel('time [s]')
|
||||
axis.set_ylabel('voltage [V]')
|
||||
|
||||
canvas = FigureCanvas(figure) # a Gtk.DrawingArea
|
||||
canvas.set_size_request(800, 600)
|
||||
sw.add_with_viewport(canvas)
|
||||
# End of Matplotlib specific code
|
||||
|
||||
window.show_all()
|
||||
Gtk.main()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: mpl_with_glade3_sgskip.py](https://matplotlib.org/_downloads/mpl_with_glade3_sgskip.py)
|
||||
- [下载Jupyter notebook: mpl_with_glade3_sgskip.ipynb](https://matplotlib.org/_downloads/mpl_with_glade3_sgskip.ipynb)
|
||||
@@ -0,0 +1,150 @@
|
||||
# SVG直方图
|
||||
|
||||
演示如何创建交互式直方图,通过单击图例标记隐藏或显示条形图。
|
||||
|
||||
交互性以ecmascript(javascript)编码,并在后处理步骤中插入SVG代码中。 要渲染图像,请在Web浏览器中打开它。 大多数Linux Web浏览器和OSX用户都支持SVG。 Windows IE9支持SVG,但早期版本不支持。
|
||||
|
||||
## 注意
|
||||
|
||||
matplotlib后端允许我们为每个对象分配id。 这是用于描述在python中创建的matplotlib对象的机制以及在第二步中解析的相应SVG构造。 虽然灵活,但它们很难用于大量物体的收集。 可以使用两种机制来简化事情:
|
||||
|
||||
- 系统地将对象分组为SVG \<g\>标签,
|
||||
- 根据每个SVG对象的来源为每个SVG对象分配类。
|
||||
|
||||
例如,不是修改每个单独栏的属性,而是可以将列分组到PatchCollection中,或者将列分配给class =“hist _ ##”属性。
|
||||
|
||||
CSS也可以广泛用于替换整个SVG生成中的重复标记。
|
||||
|
||||
作者:david.huard@gmail.com
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import xml.etree.ElementTree as ET
|
||||
from io import BytesIO
|
||||
import json
|
||||
|
||||
|
||||
plt.rcParams['svg.fonttype'] = 'none'
|
||||
|
||||
# Apparently, this `register_namespace` method works only with
|
||||
# python 2.7 and up and is necessary to avoid garbling the XML name
|
||||
# space with ns0.
|
||||
ET.register_namespace("", "http://www.w3.org/2000/svg")
|
||||
|
||||
# Fixing random state for reproducibility
|
||||
np.random.seed(19680801)
|
||||
|
||||
# --- Create histogram, legend and title ---
|
||||
plt.figure()
|
||||
r = np.random.randn(100)
|
||||
r1 = r + 1
|
||||
labels = ['Rabbits', 'Frogs']
|
||||
H = plt.hist([r, r1], label=labels)
|
||||
containers = H[-1]
|
||||
leg = plt.legend(frameon=False)
|
||||
plt.title("From a web browser, click on the legend\n"
|
||||
"marker to toggle the corresponding histogram.")
|
||||
|
||||
|
||||
# --- Add ids to the svg objects we'll modify
|
||||
|
||||
hist_patches = {}
|
||||
for ic, c in enumerate(containers):
|
||||
hist_patches['hist_%d' % ic] = []
|
||||
for il, element in enumerate(c):
|
||||
element.set_gid('hist_%d_patch_%d' % (ic, il))
|
||||
hist_patches['hist_%d' % ic].append('hist_%d_patch_%d' % (ic, il))
|
||||
|
||||
# Set ids for the legend patches
|
||||
for i, t in enumerate(leg.get_patches()):
|
||||
t.set_gid('leg_patch_%d' % i)
|
||||
|
||||
# Set ids for the text patches
|
||||
for i, t in enumerate(leg.get_texts()):
|
||||
t.set_gid('leg_text_%d' % i)
|
||||
|
||||
# Save SVG in a fake file object.
|
||||
f = BytesIO()
|
||||
plt.savefig(f, format="svg")
|
||||
|
||||
# Create XML tree from the SVG file.
|
||||
tree, xmlid = ET.XMLID(f.getvalue())
|
||||
|
||||
|
||||
# --- Add interactivity ---
|
||||
|
||||
# Add attributes to the patch objects.
|
||||
for i, t in enumerate(leg.get_patches()):
|
||||
el = xmlid['leg_patch_%d' % i]
|
||||
el.set('cursor', 'pointer')
|
||||
el.set('onclick', "toggle_hist(this)")
|
||||
|
||||
# Add attributes to the text objects.
|
||||
for i, t in enumerate(leg.get_texts()):
|
||||
el = xmlid['leg_text_%d' % i]
|
||||
el.set('cursor', 'pointer')
|
||||
el.set('onclick', "toggle_hist(this)")
|
||||
|
||||
# Create script defining the function `toggle_hist`.
|
||||
# We create a global variable `container` that stores the patches id
|
||||
# belonging to each histogram. Then a function "toggle_element" sets the
|
||||
# visibility attribute of all patches of each histogram and the opacity
|
||||
# of the marker itself.
|
||||
|
||||
script = """
|
||||
<script type="text/ecmascript">
|
||||
<![CDATA[
|
||||
var container = %s
|
||||
|
||||
function toggle(oid, attribute, values) {
|
||||
/* Toggle the style attribute of an object between two values.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
oid : str
|
||||
Object identifier.
|
||||
attribute : str
|
||||
Name of style attribute.
|
||||
values : [on state, off state]
|
||||
The two values that are switched between.
|
||||
*/
|
||||
var obj = document.getElementById(oid);
|
||||
var a = obj.style[attribute];
|
||||
|
||||
a = (a == values[0] || a == "") ? values[1] : values[0];
|
||||
obj.style[attribute] = a;
|
||||
}
|
||||
|
||||
function toggle_hist(obj) {
|
||||
|
||||
var num = obj.id.slice(-1);
|
||||
|
||||
toggle('leg_patch_' + num, 'opacity', [1, 0.3]);
|
||||
toggle('leg_text_' + num, 'opacity', [1, 0.5]);
|
||||
|
||||
var names = container['hist_'+num]
|
||||
|
||||
for (var i=0; i < names.length; i++) {
|
||||
toggle(names[i], 'opacity', [1,0])
|
||||
};
|
||||
}
|
||||
]]>
|
||||
</script>
|
||||
""" % json.dumps(hist_patches)
|
||||
|
||||
# Add a transition effect
|
||||
css = tree.getchildren()[0][0]
|
||||
css.text = css.text + "g {-webkit-transition:opacity 0.4s ease-out;" + \
|
||||
"-moz-transition:opacity 0.4s ease-out;}"
|
||||
|
||||
# Insert the script and save to file.
|
||||
tree.insert(0, ET.XML(script))
|
||||
|
||||
ET.ElementTree(tree).write("svg_histogram.svg")
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: svg_histogram_sgskip.py](https://matplotlib.org/_downloads/svg_histogram_sgskip.py)
|
||||
- [下载Jupyter notebook: svg_histogram_sgskip.ipynb](https://matplotlib.org/_downloads/svg_histogram_sgskip.ipynb)
|
||||
100
Python/matplotlab/gallery/user_interfaces/svg_tooltip_sgskip.md
Normal file
100
Python/matplotlab/gallery/user_interfaces/svg_tooltip_sgskip.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# SVG工具提示
|
||||
|
||||
此示例显示如何创建将在Matplotlib面片上悬停时显示的工具提示。
|
||||
|
||||
虽然可以从CSS或javascript创建工具提示,但在这里,我们在matplotlib中创建它,并在将其悬停在修补程序上时简单地切换它的可见性。这种方法提供了对工具提示的位置和外观的完全控制,而代价是预先获得更多的代码。
|
||||
|
||||
另一种方法是将工具提示内容放在SVG对象的Title属性中。然后,使用现有的js/css库,在浏览器中创建工具提示相对简单。内容由title属性决定,外观由CSS决定。
|
||||
|
||||
作者:David Huard
|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
import xml.etree.ElementTree as ET
|
||||
from io import BytesIO
|
||||
|
||||
ET.register_namespace("", "http://www.w3.org/2000/svg")
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
|
||||
# Create patches to which tooltips will be assigned.
|
||||
rect1 = plt.Rectangle((10, -20), 10, 5, fc='blue')
|
||||
rect2 = plt.Rectangle((-20, 15), 10, 5, fc='green')
|
||||
|
||||
shapes = [rect1, rect2]
|
||||
labels = ['This is a blue rectangle.', 'This is a green rectangle']
|
||||
|
||||
for i, (item, label) in enumerate(zip(shapes, labels)):
|
||||
patch = ax.add_patch(item)
|
||||
annotate = ax.annotate(labels[i], xy=item.get_xy(), xytext=(0, 0),
|
||||
textcoords='offset points', color='w', ha='center',
|
||||
fontsize=8, bbox=dict(boxstyle='round, pad=.5',
|
||||
fc=(.1, .1, .1, .92),
|
||||
ec=(1., 1., 1.), lw=1,
|
||||
zorder=1))
|
||||
|
||||
ax.add_patch(patch)
|
||||
patch.set_gid('mypatch_{:03d}'.format(i))
|
||||
annotate.set_gid('mytooltip_{:03d}'.format(i))
|
||||
|
||||
# Save the figure in a fake file object
|
||||
ax.set_xlim(-30, 30)
|
||||
ax.set_ylim(-30, 30)
|
||||
ax.set_aspect('equal')
|
||||
|
||||
f = BytesIO()
|
||||
plt.savefig(f, format="svg")
|
||||
|
||||
# --- Add interactivity ---
|
||||
|
||||
# Create XML tree from the SVG file.
|
||||
tree, xmlid = ET.XMLID(f.getvalue())
|
||||
tree.set('onload', 'init(evt)')
|
||||
|
||||
for i in shapes:
|
||||
# Get the index of the shape
|
||||
index = shapes.index(i)
|
||||
# Hide the tooltips
|
||||
tooltip = xmlid['mytooltip_{:03d}'.format(index)]
|
||||
tooltip.set('visibility', 'hidden')
|
||||
# Assign onmouseover and onmouseout callbacks to patches.
|
||||
mypatch = xmlid['mypatch_{:03d}'.format(index)]
|
||||
mypatch.set('onmouseover', "ShowTooltip(this)")
|
||||
mypatch.set('onmouseout', "HideTooltip(this)")
|
||||
|
||||
# This is the script defining the ShowTooltip and HideTooltip functions.
|
||||
script = """
|
||||
<script type="text/ecmascript">
|
||||
<![CDATA[
|
||||
|
||||
function init(evt) {
|
||||
if ( window.svgDocument == null ) {
|
||||
svgDocument = evt.target.ownerDocument;
|
||||
}
|
||||
}
|
||||
|
||||
function ShowTooltip(obj) {
|
||||
var cur = obj.id.split("_")[1];
|
||||
var tip = svgDocument.getElementById('mytooltip_' + cur);
|
||||
tip.setAttribute('visibility',"visible")
|
||||
}
|
||||
|
||||
function HideTooltip(obj) {
|
||||
var cur = obj.id.split("_")[1];
|
||||
var tip = svgDocument.getElementById('mytooltip_' + cur);
|
||||
tip.setAttribute('visibility',"hidden")
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
"""
|
||||
|
||||
# Insert the script at the top of the file and save it.
|
||||
tree.insert(0, ET.XML(script))
|
||||
ET.ElementTree(tree).write('svg_tooltip.svg')
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: svg_tooltip_sgskip.py](https://matplotlib.org/_downloads/svg_tooltip_sgskip.py)
|
||||
- [下载Jupyter notebook: svg_tooltip_sgskip.ipynb](https://matplotlib.org/_downloads/svg_tooltip_sgskip.ipynb)
|
||||
@@ -0,0 +1,96 @@
|
||||
# 工具管理
|
||||
|
||||
此示例演示如何:
|
||||
|
||||
- 修改工具栏。
|
||||
- 创建工具。
|
||||
- 添加工具。
|
||||
- 删除工具
|
||||
|
||||
可以使用 matplotlib.backend_managers.ToolManager
|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
plt.rcParams['toolbar'] = 'toolmanager'
|
||||
from matplotlib.backend_tools import ToolBase, ToolToggleBase
|
||||
|
||||
|
||||
class ListTools(ToolBase):
|
||||
'''List all the tools controlled by the `ToolManager`'''
|
||||
# keyboard shortcut
|
||||
default_keymap = 'm'
|
||||
description = 'List Tools'
|
||||
|
||||
def trigger(self, *args, **kwargs):
|
||||
print('_' * 80)
|
||||
print("{0:12} {1:45} {2}".format(
|
||||
'Name (id)', 'Tool description', 'Keymap'))
|
||||
print('-' * 80)
|
||||
tools = self.toolmanager.tools
|
||||
for name in sorted(tools):
|
||||
if not tools[name].description:
|
||||
continue
|
||||
keys = ', '.join(sorted(self.toolmanager.get_tool_keymap(name)))
|
||||
print("{0:12} {1:45} {2}".format(
|
||||
name, tools[name].description, keys))
|
||||
print('_' * 80)
|
||||
print("Active Toggle tools")
|
||||
print("{0:12} {1:45}".format("Group", "Active"))
|
||||
print('-' * 80)
|
||||
for group, active in self.toolmanager.active_toggle.items():
|
||||
print("{0:12} {1:45}".format(str(group), str(active)))
|
||||
|
||||
|
||||
class GroupHideTool(ToolToggleBase):
|
||||
'''Show lines with a given gid'''
|
||||
default_keymap = 'G'
|
||||
description = 'Show by gid'
|
||||
default_toggled = True
|
||||
|
||||
def __init__(self, *args, gid, **kwargs):
|
||||
self.gid = gid
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def enable(self, *args):
|
||||
self.set_lines_visibility(True)
|
||||
|
||||
def disable(self, *args):
|
||||
self.set_lines_visibility(False)
|
||||
|
||||
def set_lines_visibility(self, state):
|
||||
gr_lines = []
|
||||
for ax in self.figure.get_axes():
|
||||
for line in ax.get_lines():
|
||||
if line.get_gid() == self.gid:
|
||||
line.set_visible(state)
|
||||
self.figure.canvas.draw()
|
||||
|
||||
|
||||
fig = plt.figure()
|
||||
plt.plot([1, 2, 3], gid='mygroup')
|
||||
plt.plot([2, 3, 4], gid='unknown')
|
||||
plt.plot([3, 2, 1], gid='mygroup')
|
||||
|
||||
# Add the custom tools that we created
|
||||
fig.canvas.manager.toolmanager.add_tool('List', ListTools)
|
||||
fig.canvas.manager.toolmanager.add_tool('Show', GroupHideTool, gid='mygroup')
|
||||
|
||||
|
||||
# Add an existing tool to new group `foo`.
|
||||
# It can be added as many times as we want
|
||||
fig.canvas.manager.toolbar.add_tool('zoom', 'foo')
|
||||
|
||||
# Remove the forward button
|
||||
fig.canvas.manager.toolmanager.remove_tool('forward')
|
||||
|
||||
# To add a custom tool to the toolbar at specific location inside
|
||||
# the navigation group
|
||||
fig.canvas.manager.toolbar.add_tool('Show', 'navigation', 1)
|
||||
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: toolmanager_sgskip.py](https://matplotlib.org/_downloads/toolmanager_sgskip.py)
|
||||
- [下载Jupyter notebook: toolmanager_sgskip.ipynb](https://matplotlib.org/_downloads/toolmanager_sgskip.ipynb)
|
||||
@@ -0,0 +1,70 @@
|
||||
# WX光标演示
|
||||
|
||||
例如,绘制光标并报告WX中的数据坐标。
|
||||
|
||||
```python
|
||||
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
|
||||
from matplotlib.backends.backend_wx import NavigationToolbar2Wx
|
||||
from matplotlib.figure import Figure
|
||||
import numpy as np
|
||||
|
||||
import wx
|
||||
|
||||
|
||||
class CanvasFrame(wx.Frame):
|
||||
def __init__(self, ):
|
||||
wx.Frame.__init__(self, None, -1, 'CanvasFrame', size=(550, 350))
|
||||
|
||||
self.figure = Figure()
|
||||
self.axes = self.figure.add_subplot(111)
|
||||
t = np.arange(0.0, 3.0, 0.01)
|
||||
s = np.sin(2*np.pi*t)
|
||||
|
||||
self.axes.plot(t, s)
|
||||
self.axes.set_xlabel('t')
|
||||
self.axes.set_ylabel('sin(t)')
|
||||
self.figure_canvas = FigureCanvas(self, -1, self.figure)
|
||||
|
||||
# Note that event is a MplEvent
|
||||
self.figure_canvas.mpl_connect(
|
||||
'motion_notify_event', self.UpdateStatusBar)
|
||||
self.figure_canvas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor)
|
||||
|
||||
self.sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
self.sizer.Add(self.figure_canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
|
||||
self.SetSizer(self.sizer)
|
||||
self.Fit()
|
||||
|
||||
self.statusBar = wx.StatusBar(self, -1)
|
||||
self.SetStatusBar(self.statusBar)
|
||||
|
||||
self.toolbar = NavigationToolbar2Wx(self.figure_canvas)
|
||||
self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
|
||||
self.toolbar.Show()
|
||||
|
||||
def ChangeCursor(self, event):
|
||||
self.figure_canvas.SetCursor(wx.Cursor(wx.CURSOR_BULLSEYE))
|
||||
|
||||
def UpdateStatusBar(self, event):
|
||||
if event.inaxes:
|
||||
self.statusBar.SetStatusText(
|
||||
"x={} y={}".format(event.xdata, event.ydata))
|
||||
|
||||
|
||||
class App(wx.App):
|
||||
def OnInit(self):
|
||||
'Create the main window and insert the custom frame'
|
||||
frame = CanvasFrame()
|
||||
self.SetTopWindow(frame)
|
||||
frame.Show(True)
|
||||
return True
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = App(0)
|
||||
app.MainLoop()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: wxcursor_demo_sgskip.py](https://matplotlib.org/_downloads/wxcursor_demo_sgskip.py)
|
||||
- [下载Jupyter notebook: wxcursor_demo_sgskip.ipynb](https://matplotlib.org/_downloads/wxcursor_demo_sgskip.ipynb)
|
||||
Reference in New Issue
Block a user