Bigger matplot figure in a ScrolledWindow or ScrolledPanel - python

I'd like plot a figure(having many subfigures) in a scrolledwindow(or scrolledpanel).
figure width depends on the width of window and figure height is calculated like width * 2.
if the height of window ls less than width * 2, scrollbar of window is enabled.
with the following code, I checked the size of figure, canvas and window.
the height of figure and figure is bigger than the height of window. but scrollbar is not enabled.
I tried with boxsizer also, but it did not work.
Can you make this code work?
from matplotlib.backends.backend_wxagg import \
FigureCanvasWxAgg as FigureCanvas, \
NavigationToolbar2WxAgg as NavigationToolbar
from matplotlib.figure import Figure
import numpy as np
import wx
from wx.lib.scrolledpanel import ScrolledPanel
class MyFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=title,
pos=wx.DefaultPosition, size=wx.Size(200, 300))
# self.T_panel = wx.Panel(self)
# self.T_wd = wx.ScrolledWindow(self.T_panel, -1, wx.DefaultPosition,
# wx.DefaultSize, wx.VSCROLL|wx.ALWAYS_SHOW_SB)
self.T_wd = ScrolledPanel(self, -1, size=wx.Size(200, 300))
self.Bind(wx.EVT_SIZE, self.onSize)
self.T_wd.SetupScrolling()
self.T_fig = Figure((5.0,5.0), dpi=80)
self.T_canvas = FigureCanvas(self.T_wd, -1, self.T_fig)
self.graph = self.T_fig.add_subplot(111)
self.T_wd.Layout()
def onSize(self, event):
size = event.GetSize()
x = np.arange(5)
y = np.random.rand(5) * 5.
self.T_fig.set_size_inches(size[0]/80., size[0]/40.)
self.T_canvas.SetSize((size[0], size[0]*2))
self.graph.hold(False)
self.graph.plot(x,y)
self.T_canvas.draw()
self.T_wd.SetSize(size)
self.T_wd.SetupScrolling()
print 'event size', size
print 'fig size', self.T_fig.get_size_inches()*80
print 'canvas size', self.T_canvas.GetSize()
print 'window(panel) wize', self.T_wd.GetSize()
print ''
class my_App(wx.App):
def OnInit(self):
frame = MyFrame(None, title = 'test')
frame.Show(True)
self.SetTopWindow(frame)
return True
my_App().MainLoop()

Related

Different matlibplots for different popup choices in wx

I am making a simple gui for a signal generator with wx. I want to display a small plot of say a sine wave when the option "Sine" is chosen, and a plot of a square wave when "Square" is chosen from the menu. I am a newbie in python, and therefore the classes and inheritance of these is difficult for me.
In the (much stripped down) code i have a variable 'wave' inside the class 'ServelPanel' that holds which wavetype is chosen. However, when I try and plot the waveform in the MainFrame class, I cannot for the life of me retrieve the 'wave'-variable. I have tried to inherit classes, set the 'wave'-variable global, and am out of ideas.
import wx, random, math, os
from pyo import *
from numpy import arange, sin, pi, sign
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 matplotlib.pyplot as plt
class BasePanel(wx.Panel):
def __init__(self, parent, title):
wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER)
self.SetMaxSize((230,150))
self.sliders = []
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.titleSizer = wx.BoxSizer(wx.HORIZONTAL)
self.close = wx.StaticText(self, id=-1, label="X")
self.close.Bind(wx.EVT_LEFT_DOWN, self.MouseDown)
self.titleSizer.Add(self.close, 0, wx.LEFT, 5)
self.title = wx.StaticText(self, id=-1, label=title)
off = (210 - self.title.GetSize()[0]) / 2
self.titleSizer.Add(self.title, 0, wx.LEFT, off)
self.sizer.Add(self.titleSizer, 0, wx.BOTTOM|wx.TOP, 4)
class ServerPanel(wx.Panel):
def __init__(self, parent, colour="#DDDDE7"):
wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER)
self.SetBackgroundColour(colour)
self.SetMinSize((230,250))
self.fileformat = self.wavetype = 0
self.title = wx.StaticText(self, id=-1, label="--- Simple Wave
Generator ---", pos=(40,5))
font, psize = self.title.GetFont(),
self.title.GetFont().GetPointSize()
font.SetPointSize(psize-2)
self.waveText =
wx.StaticText(self,id=-1,label="Waveform",pos(15,60))
self.popupWave = wx.Choice(self, id=wx.ID_ANY, pos=(13,70),
size(70,20), choices=["Sine","Square"])
self.popupWave.Bind(wx.EVT_CHOICE, self.changeWave)
objs = [self.waveText]
for obj in objs:
obj.SetFont(font)
def changeWave(self, evt):
global wave
wave = evt.GetInt()
if wave == 1: wave = 2
self.wavetype = wave
class MainFrame(wx.Frame,ServerPanel):
def __init__(self, parent=None, title=u"Sine Test", size=(250,300)):
wx.Frame.__init__(self, parent, id=-1, title=title, size=size)
self.server = Server().boot()
self.sizer = wx.FlexGridSizer(4,4,0,0)
self.panel = wx.Panel(self)
self.serverPanel = ServerPanel(self.panel)
self.sizer.Add(self.serverPanel)
self.panel.SetSizer(self.sizer)
pan = CanvasPanel(self.panel)
pan.draw()
self.Show()
class CanvasPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, id=-1, pos=wx.Point(100,60),
size=wx.Size(80, 50))
figsize = (80*1.0/80, 50*1.0/80)
self.figure = Figure(figsize, dpi=80)
self.axes = self.figure.add_subplot(111)
self.axes.set_axis_off()
self.canvas = FigureCanvas(self, -1, self.figure)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.canvas,1,wx.LEFT | wx.TOP | wx.GROW)
self.SetSizer(self.sizer)
self.Fit()
def draw(self):
t = arange(0.0, 3.0, 0.01)
s = sin(2 * pi * t)
self.axes.plot(t, s)
def drawSqr(self):
t = arange(0.0, 3.0, 0.01)
s = sign(sin(2 * pi * t))
self.axes.plot(t, s)
mainFrame = MainFrame()
app.MainLoop()
Ps: I know the "minimal working example" is not really minimal, but it's what I could get working for the moment. Please excuse a novice.
In the example I have hard coded a drawing to show in the MainFrame class, so you see where the drawing should be.
If we boil your code down a bit, remove un-needed classes, use sizers rather than mixing sizers and positional statements, clean up the indentation issues, remove undeclared items and unused imports.
We get something along these lines.
import wx
from numpy import arange, sin, pi, sign
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure
class MainFrame(wx.Frame):
def __init__(self, parent=None, title=u"Sine Test", size=(250,300)):
wx.Frame.__init__(self, parent, id=-1, title=title, size=size)
self.panel = wx.Panel(self,-1,style=wx.SUNKEN_BORDER)
self.panel.SetBackgroundColour("#DDDDE7")
self.panel.SetMinSize((230,250))
self.wavetype = 0
self.title = wx.StaticText(self.panel, id=-1, label="--- Simple Wave Generator ---")
font, psize = self.title.GetFont(), self.title.GetFont().GetPointSize()
font.SetPointSize(psize-2)
self.waveText = wx.StaticText(self.panel,id=-1,label="Waveform")
self.popupWave = wx.Choice(self.panel, id=wx.ID_ANY, size=(70,30), choices=["Sine","Square"])
self.popupWave.Bind(wx.EVT_CHOICE, self.changeWave)
self.pan = CanvasPanel(self)
self.sizer = wx.GridBagSizer(hgap=5,vgap=5)
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.title, pos=(0,0), span=(1,4), flag = wx.ALL|wx.ALIGN_CENTER)
self.sizer.Add(self.waveText, pos=(2,0), flag = wx.ALL)
self.sizer.Add(self.popupWave, pos=(3,0), flag = wx.ALL)
self.sizer.Add(self.pan, pos=(3,1), span=(3,3), flag = wx.ALL|wx.EXPAND)
self.panel.SetSizer(self.sizer)
self.main_sizer.Add(self.panel,1,wx.EXPAND)
self.SetSizer(self.main_sizer)
self.popupWave.SetSelection(0)
self.pan.wavetype = self.popupWave.GetSelection()
self.pan.draw()
self.Show()
def changeWave(self, evt):
wave = evt.GetSelection()
self.pan.wavetype = wave
self.pan.draw()
class CanvasPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, id=-1, size=wx.Size(80, 50))
figsize = (80*1.0/80, 50*1.0/80)
self.figure = Figure(figsize, dpi=80)
self.wavetype = parent.wavetype
self.axes = self.figure.add_subplot(111)
self.axes.set_axis_off()
self.canvas = FigureCanvas(self, -1, self.figure)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.canvas,1,wx.LEFT | wx.TOP | wx.GROW)
self.SetSizer(self.sizer)
self.Fit()
def draw(self):
#Clear any previous data
self.axes.clear()
self.axes.set_axis_off()
#Plot new wave
if self.wavetype == 0:
t = arange(0.0, 3.0, 0.01)
s = sin(2 * pi * t)
self.axes.plot(t, s)
else:
t = arange(0.0, 3.0, 0.01)
s = sign(sin(2 * pi * t))
self.axes.plot(t, s)
self.Layout()
app=wx.App()
mainFrame = MainFrame()
app.MainLoop()
It may not be exactly what you are after, so feel free to play with it!

matplotlib Embedded in wxPython with Navigation Toolbar Coordinates

I've come across and implemented a few scripts with matplotlib figures embedded in a wxPython panel. The embedding of the actual plot is fine but when I add a navigation toolbar NavigationToolbar2WxAgg much of the toolbar functionality is lost. I can pan and zoom, but there are no coordinates displayed, and the default shortcut keys do not work. The same behavior occurs in embedding_in_wx4_sgskip.py from the example/user_interfaces folder for matplotlib:
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 matplotlib as mpl
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.fmt_xdata = lambda x: "{0:f}".format(x)
self.axes.fmt_ydata = lambda x: "{0:f}".format(x)
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()
How do I restore or add this functionality to my navigation bar?
You can put this code here:
#Create 'Position Display'
self.Text = wx.StaticText( self, wx.ID_ANY, u" Available Channels ", wx.DefaultPosition, wx.DefaultSize, 0 )
self.Text.Wrap( -1 )
mouseMoveID = self.canvas.mpl_connect('motion_notify_event',
self.onMotion)
Before you create your sizer. Then add this to the end of your init definition:
self.sizer.Add(self.Text,0, wx.LEFT | wx.EXPAND)
Finally, add this function to capture mouse movement on the frame:
def onMotion(self, evt):
"""This is a bind event for the mouse moving on the MatPlotLib graph
screen. It will give the x,y coordinates of the mouse pointer.
"""
xdata = evt.xdata
ydata = evt.ydata
try:
x = round(xdata,4)
y = round(ydata,4)
except:
x = ""
y = ""
self.Text.SetLabelText("%s (s), %s" % (x,y))
This is what worked for me, good luck!

Matplotlib/wxpython: co-ordinate values not showing up in status bar

I have a simple matplotlib plot integrated with wxPython, and for some reason the x/y co-ordinates are not showing up under the status bar (the co-ordinates that show when you move the mouse), they used to appear but cannot get it to happen anymore. Any ideas why this may be possible? (I've also tried setting the format_coord attribute manually but that doesn't seem to work).
I think it's wx doing something funny, since if I just create a matplotlib plot in a new Python shell it works fine. Example code is below:
#Subclassing WX Panel Class to be able to integrate matplotlib into it
class p1(wx.Panel):
def __init__(self, parent, frame):
#Initialize WX Panel
wx.Panel.__init__(self, parent, -1, size=(50,50))
#Set up Figure/Canvas
self.frame = frame
self.figure = Figure()
self.canvas = FigureCanvas(self, -1, self.figure)
#Set up Matplotlib Toolbar
self.chart_toolbar = NavigationToolbar2Wx(self.canvas)
tw,th = self.chart_toolbar.GetSizeTuple()
fw,fh = self.canvas.GetSizeTuple()
self.chart_toolbar.SetSize(wx.Size(fw, th))
self.chart_toolbar.Realize()
graphs_sizer = wx.BoxSizer(wx.VERTICAL)
graphs_sizer.Add(self.canvas, 20, flag=wx.EXPAND, border=5)
graphs_sizer.Add(self.chart_toolbar, 1, flag=wx.ALIGN_CENTER, border=5)
self.SetSizer(graphs_sizer)
def plot(self):
self.axs1 = self.figure.add_subplot(1,1,1)
self.axs1.plot([1,2,3,4,5],color='blue')
class TestFrame(wx.Frame):
def __init__(self, parent, title):
#Initialize WX Frame
wx.Frame.__init__(self, parent, title=title, size=(1000,800))
#Create Splitter Window and Add Left/Right Panels
self.splitterWindow = wx.SplitterWindow(self)
self.panel1 = p1(self.splitterWindow, self)
self.panel2 = wx.Panel(self.splitterWindow)
self.splitterWindow.SplitVertically(self.panel1, self.panel2, 700)
#Create Status Bar
self.statusbar = self.CreateStatusBar()
#Plot
self.panel1.plot()
app = wx.App(redirect=False)
frame = TestFrame(None, "Test")
frame.Show(True)
app.MainLoop()
whereas something as simple as this works fine:
plt.plot([1,2,3,4,5])
plt.show()
It is easier for people to help if you make the code complete, i.e. with the imports in your case.
Note that you don't need the "SetSize" stuff for the toolbar, IIRC that was only needed with some wxPython versions on MAC.
To get the mouse coordinates you need to connect an event, that might be done out of the box with plt.plot.
Doc for the events is here: http://matplotlib.org/users/event_handling.html
import wx
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
#Subclassing WX Panel Class to be able to integrate matplotlib into it
class p1(wx.Panel):
def __init__(self, parent, frame):
#Initialize WX Panel
wx.Panel.__init__(self, parent, -1, size=(50,50))
#Set up Figure/Canvas
self.frame = frame
self.figure = Figure()
self.canvas = FigureCanvas(self, -1, self.figure)
#Set up Matplotlib Toolbar
self.chart_toolbar = NavigationToolbar2Wx(self.canvas)
self.chart_toolbar.Realize()
graphs_sizer = wx.BoxSizer(wx.VERTICAL)
graphs_sizer.Add(self.canvas, 20, flag=wx.EXPAND, border=5)
graphs_sizer.Add(self.chart_toolbar, 1, flag=wx.ALIGN_CENTER, border=5)
self.SetSizer(graphs_sizer)
def plot(self):
self.axs1 = self.figure.add_subplot(1,1,1)
self.axs1.plot([1,2,3,4,5],color='blue')
class TestFrame(wx.Frame):
def __init__(self, parent, title):
#Initialize WX Frame
wx.Frame.__init__(self, parent, title=title, size=(1000,800))
#Create Splitter Window and Add Left/Right Panels
self.splitterWindow = wx.SplitterWindow(self)
self.panel1 = p1(self.splitterWindow, self)
self.panel2 = wx.Panel(self.splitterWindow)
self.splitterWindow.SplitVertically(self.panel1, self.panel2, 700)
#Create Status Bar
self.statusbar = self.CreateStatusBar()
#Plot
self.panel1.plot()
mouseMoveID = self.panel1.canvas.mpl_connect('motion_notify_event',
self.onMotion)
def onMotion(self, evt):
x = evt.x
y = evt.y
inaxes = evt.inaxes
xdata = evt.xdata
ydata = evt.ydata
self.statusbar.SetStatusText("%s, %s, %s, %s, %s" % (
x, y, inaxes, xdata, ydata))
app = wx.App(redirect=False)
frame = TestFrame(None, "Test")
frame.Show(True)
app.MainLoop()

embedding matplotlib figure and change its size

I had the same problem like here.
It works, but this figure shall not cover the whole frame; so I changed size and position of his panel. Problem now is, that my figure still has the same size of my frame and therefore I only changed the panelsize, my figure gets "cut". How can I solve this?
Example for better understanding: My Frame is 800x600 and my figure shall only have the size 400x300 inside this frame.
edit:
import wx
from numpy import arange, sin, pi
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
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY,
"Pyramid App",size=(800,600),pos=((wx.DisplaySize()[0]-800)/2,(wx.DisplaySize()[1]-600)/2),style= wx.SYSTEM_MENU | wx.CAPTION | wx.MINIMIZE_BOX | wx.CLOSE_BOX)
self.PageThree = pageThree(self)
class pageThree(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent,size=(800,525))
self.myparent=parent
self.pageThree=wx.Panel(self,size=(800,525)) # put some elements at this panel
self.pylabfigure = wx.Panel(self,size=(440,420),pos=(350,105)) # this is the panel for my figure
self.drawPylabFigure()
self.draw()
def drawPylabFigure(self):
self.figure = Figure()
self.axes = self.figure.add_subplot(111)
self.canvas = FigureCanvas(self.pylabfigure, -1, self.figure)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
self.SetSizer(self.sizer)
self.Fit()
def draw(self):
#example drawing
t = arange(0.0, 3.0, 0.01)
s = sin(2 * pi * t)
self.axes.plot(t, s)
if __name__ == "__main__":
app = wx.App()
MainFrame().Show()
app.MainLoop()
This will give you an idea of how to do it.
Main thing to have into account it to put your panels/canvas organized by one sizer.
Also, if the canvas has to fill his side there is not need to put it in a panel.
import wx
from numpy import arange, sin, pi
import matplotlib
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FCW
from matplotlib.figure import Figure
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY,
"Pyramid App",size=(800,600),
pos=((wx.DisplaySize()[0]-800)/2,(wx.DisplaySize()[1]-600)/2),
style=wx.SYSTEM_MENU | wx.CAPTION | wx.MINIMIZE_BOX | wx.CLOSE_BOX)
self.PageThree = pageThree(self)
class pageThree(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent,size=(800,525))
self.myparent=parent
self.pageThree=wx.Panel(self, size=(500,525))
self.drawPyFigure()
self.draw()
def drawPyFigure(self):
self.figure = Figure()
self.axes = self.figure.add_subplot(111)
self.canvas = FCW(self, -1, self.figure)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.pageThree, 0)
sizer.Add(self.canvas, 1, wx.EXPAND)
self.SetSizer(sizer)
self.Fit()
def draw(self):
t = arange(0.0, 3.0, 0.01)
s = sin(2 * pi * t)
self.axes.plot(t, s)
if __name__ == "__main__":
app = wx.App()
MainFrame().Show()
app.MainLoop()
In a nutshell, you want self.figure = Figure(figsize=(400 / 80.0, 300 / 80.0)).
You need to specify the size of the figure (by default 8 inches wide by 6 inches tall) and/or the dpi of the figure (by default, 80 for on-screen display).
However, be aware that the size of the figure on-screen depends purely on the total number of pixels (in other words, width_inches*dpi x height_inches*dpi). For that reason, if we want a figure to be a specific number of pixels, we need to convert that to "inches" (which have nothing to do with the figure's display size if it's displayed on-screen) by dividing the number of pixels by the figure's dpi.

Python/Matplotlib - Quickly Updating Text on Axes

I have a matplotlib figure/canvas in a wxpython window. I want to update some information on the plot as the mouse moves around. I've connected to 'motion_notify_event' to get this information.
In the code below, a lot of random data is plotted and then the x,y location of the cursor is displayed in the statusbar of the window. This is very smooth and works well. However, I really want to display this information at the top of the plot. The behavior I want is shown if you uncomment the last two lines of cbUpdateCursor. However, when this is done, the response time to moving the cursor is terribly slow (because draw gets called and there is a lot of data, but draw must be called or the text doesn't get updated).
How can I speed this up so the cursor position can be displayed on the plot, but not slow it down so much? I think I might need to do something with bbox?
Code:
import wx
import numpy as np
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.figure import Figure
from matplotlib.widgets import Cursor
from matplotlib.backends.backend_wxagg import \
FigureCanvasWxAgg as FigCanvas, \
NavigationToolbar2WxAgg as NavigationToolbar
class wxPlotting(wx.Frame):
title = 'Test'
def __init__(self):
wx.Frame.__init__(self, None, -1, self.title)
self.time = np.arange(10000)
self.data = np.random.random(10000)
self.sb = self.CreateStatusBar()
self.create_main_panel()
self.axes.plot(self.time, self.data)
self.canvas.draw()
def create_main_panel(self):
self.panel = wx.Panel(self)
self.fig = Figure((5.0, 4.0), dpi=100)
self.canvas = FigCanvas(self.panel, -1, self.fig)
self.axes = self.fig.add_subplot(111)
self.text = self.axes.text(0., 1.005, '', transform = self.axes.transAxes)
self.cursor = Cursor(self.axes, useblit=True, color='red')
self.canvas.mpl_connect('motion_notify_event', self.cbUpdateCursor)
self.vbox = wx.BoxSizer(wx.VERTICAL)
self.vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
self.panel.SetSizer(self.vbox)
self.vbox.Fit(self)
def cbUpdateCursor(self, event):
if event.inaxes:
text = 'x = %5.4f, y = %5.4f' % (event.xdata, event.ydata)
self.sb.SetStatusText(text)
#self.text.set_text(text)
#self.canvas.draw()
if __name__ == '__main__':
app = wx.PySimpleApp()
app.frame = wxPlotting()
app.frame.Show()
app.MainLoop()
Basically I want something similar to the text that gets displayed using pyplot, i.e. the bottom right corner when the code below is run:
Code:
import matplotlib.pyplot as plt
plt.plot(range(10000), range(10000))
plt.show()
EDIT:
In my actual program, I want the static text to be within the matplotlib axes, not really above it. So I don't think I can just use a wxpython statictext to display it.
You could use blitting, similar to the animation examples here.
This make a very large performance difference in this case, as only a small portion of the window needs to be redrawn.
Unfortunately, I can't figure out how to get a gray background behind the text when it's redrawn, to match the default figure background behind it... The performance is excellent, though.
As a stand-alone example based on your code above:
import wx
import numpy as np
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.figure import Figure
from matplotlib.widgets import Cursor
from matplotlib.backends.backend_wxagg import \
FigureCanvasWxAgg as FigCanvas, \
NavigationToolbar2WxAgg as NavigationToolbar
class wxPlotting(wx.Frame):
title = 'Test'
def __init__(self):
wx.Frame.__init__(self, None, -1, self.title)
self.time = np.arange(10000)
self.data = np.random.random(10000)
self.sb = self.CreateStatusBar()
self.create_main_panel()
self.axes.plot(self.time, self.data)
self.background = self.canvas.copy_from_bbox(self.fig.bbox)
self.canvas.draw()
def create_main_panel(self):
self.panel = wx.Panel(self)
self.fig = Figure((5.0, 4.0), dpi=100)
self.canvas = FigCanvas(self.panel, -1, self.fig)
self.axes = self.fig.add_subplot(111)
self.text = self.axes.text(0., 1.005, '', transform = self.axes.transAxes, animated=True)
self.cursor = Cursor(self.axes, useblit=True, color='red')
self.canvas.mpl_connect('motion_notify_event', self.cbUpdateCursor)
self.vbox = wx.BoxSizer(wx.VERTICAL)
self.vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
self.panel.SetSizer(self.vbox)
self.vbox.Fit(self)
def cbUpdateCursor(self, event):
if event.inaxes:
text = 'x = %5.4f, y = %5.4f' % (event.xdata, event.ydata)
self.sb.SetStatusText(text)
self.canvas.restore_region(self.background)
self.text.set_text(text)
self.axes.draw_artist(self.text)
self.canvas.blit(self.text.get_window_extent())
if __name__ == '__main__':
app = wx.PySimpleApp()
app.frame = wxPlotting()
app.frame.Show()
app.MainLoop()
You could add a static text box on top, and just update it's label:
import wx
import numpy as np
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.figure import Figure
from matplotlib.widgets import Cursor
from matplotlib.backends.backend_wxagg import \
FigureCanvasWxAgg as FigCanvas, \
NavigationToolbar2WxAgg as NavigationToolbar
class wxPlotting(wx.Frame):
title = 'Test'
def __init__(self):
wx.Frame.__init__(self, None, -1, self.title)
self.time = np.arange(10000)
self.data = np.random.random(10000)
self.sb = self.CreateStatusBar()
self.create_main_panel()
self.axes.plot(self.time, self.data)
self.canvas.draw()
def create_main_panel(self):
self.panel = wx.Panel(self)
self.fig = Figure((5.0, 4.0), dpi=100)
self.canvas = FigCanvas(self.panel, -1, self.fig)
self.axes = self.fig.add_subplot(111)
self.text = self.axes.text(0., 1.005, '', transform = self.axes.transAxes)
self.cursor = Cursor(self.axes, useblit=True, color='red')
self.canvas.mpl_connect('motion_notify_event', self.cbUpdateCursor)
self.vbox = wx.BoxSizer(wx.VERTICAL)
self.cursor_pos = wx.StaticText(self.panel,-1, label="")
self.vbox.Add(self.cursor_pos, 0, wx.LEFT | wx.TOP | wx.GROW)
self.vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
self.panel.SetSizer(self.vbox)
self.vbox.Fit(self)
def cbUpdateCursor(self, event):
if event.inaxes:
text = 'x = %5.4f, y = %5.4f' % (event.xdata, event.ydata)
self.sb.SetStatusText(text)
self.cursor_pos.SetLabel(text)
#self.text.set_text(text)
#self.canvas.draw()
if __name__ == '__main__':
app = wx.PySimpleApp()
app.frame = wxPlotting()
app.frame.Show()
app.MainLoop()

Categories