I would like to know how to perform the following pseudocode in python when embedding a matplotlib figure inside of a wxPython FigureCanvasWxAgg instance:
the following items need to be used:
---- IMPORTS THAT CAN BE USED ----
import wx
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
-------------------------------------------------------
main_canvas;
shadow_canvas;
big_plot [a matplotlib figure instance with one big plot in it -- like the one you would make with figure.add_subplots(1,1,1)];
small_subplots [a matplotlib figure instance with, say, 2 subplots in it -- you would make with figure.add_subplots(2,1,i), where 1<=i<=2]
a function called SwapView(main_canvas,shadow_canvas,big_plot,small_subplots) that essentially swaps the figure that is currently in shadow_canvas with the one in main_canvas (so keep switching between the one with a big plot and the one with many small plots)
a function UpdateDisplay() that dynamically updates the display every time you call SwapView()
******* PSEUDOCODE *******
main_canvas.show()
shadow_canvas.hide()
main_canvas has big_plot initially
shadow_canvas has small_subplots initially
if big_plot in main_canvas:
SwapView(...) ---> should put big_plot in shadow_canvas and small_subplots in the main_canvas
else:
SwapView(...) ---> should put the small_subplots in shadow_canvas and the big_plot in main_canvas
UpdateDisplay()
******* END OF CODE *******
Here is my initial attempt at this code and unfortunately I can't find a way to find which figure is the one currently displayed.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import numpy as np
import wx
import time
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
class myframe(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,parent = None, id = -1, title = 'LoadFigure()', size = (800,800))
self.figurePanel = FigurePanel(parent = self)
canvas1 = self.figurePanel.canvas
canvas2 = self.figurePanel.enlarged_canvas
fig1 = self.figurePanel.enlarged_figure
fig2 = self.figurePanel.figure
fig1.set_canvas(canvas1) #enlarged_fig resides in canvas1
fig2.set_canvas(canvas2) #fig resides in canvas2
#Show both canvases ---> canvas2 will override canvas1, but when canvas2 hides canvas1 should show
canvas2.Show()
canvas1.Show()
self.Show()
print "Starting to swap displays!"
time.sleep(1)
for i in range(10):
print "run: %d"%i
self.SwapView(big_plot = fig1,small_plots = fig2,main_canvas = canvas1,shadow_canvas = canvas2)
time.sleep(1)
def SwapView(self,big_plot,small_plots,main_canvas,shadow_canvas):
'''
Keep swapping the main_canvas with the shadow_canvas to show either fig1 or fig2.
Initially, big_plot has main_canvas and small_plots have shadow_canvas
'''
wx.Yield()
print list(main_canvas)
print list(big_plot.get_children())
time.sleep(2)
for child in big_plot.get_children():
if child == main_canvas:
print 'big_plot has main_canvas'
big_plot.set_canvas(shadow_canvas)
small_plots.set_canvas(main_canvas)
main_canvas.draw()
wx.Yield()
main_canvas.Show()
else:
print 'big_plot has shadow_canvas'
for child in small_plots.get_children():
if child == main_canvas:
print 'small_plots has main_canvas'
small_plots.set_canvas(shadow_canvas)
big_plot.set_canvas(main_canvas)
main_canvas.draw()
wx.Yield()
main_canvas.Show()
else:
print 'small_plots has shadow_canvas'
class FigurePanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.figPanel = self
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.figure = Figure(figsize = (8,6.1), dpi =60)
self.ax = self.figure.add_subplot(1,1,1)
self.ax.plot([1,2,3],[1,2,3])
self.enlarged_figure = Figure(figsize = (8,6.1), dpi = 60)
self.ax1 = self.enlarged_figure.add_subplot(2,1,1)
self.ax2 = self.enlarged_figure.add_subplot(2,1,2)
self.ax1.plot([1,2,3],[1,4,9])
self.ax2.plot([1,2,3],[1,4,9])
self.canvas = FigureCanvas(self, -1, self.figure)
self.enlarged_canvas = FigureCanvas(self,-1,self.enlarged_figure)
self.Layout()
self.Fit()
if __name__ == "__main__":
app = wx.App(False)
fr = myframe()
app.MainLoop()
For anyone that might need it, here's the solution that I came up with:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import numpy as np
import wx
import time
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
class myframe(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,parent = None, id = -1, title = 'SWAP!', size = (480,390))
self.figurePanel = FigurePanel(parent = self)
self.canvas1 = self.figurePanel.canvas
self.canvas2 = self.figurePanel.enlarged_canvas
self.fig1 = self.figurePanel.enlarged_figure
self.fig2 = self.figurePanel.figure
self.fig1.set_canvas(self.canvas1) #enlarged_fig resides in canvas1
self.canvas1.Show()
self.Show()
self.canvas2.mpl_connect("button_release_event",self.OnLoadFigure) #Enable the detection of mouseclicks for the plots in the plotting window
print "Click anywhere on the figure to swap the plots!"
self.display = 1
def OnLoadFigure(self,event = None):
print "Tried to load figure"
if event != None:
self.display = self.SwapView(big_plot = self.fig1 ,small_plots = self.fig2 , display = self.display, main_canvas = self.canvas1 , shadow_canvas = 0)
def SwapView(self,big_plot = None,display = -1, small_plots = None,main_canvas = None,shadow_canvas = None):
'''
Keep swapping the main_canvas with the shadow_canvas to show either fig1 or fig2.
Initially, big_plot has main_canvas and small_plots have shadow_canvas
'''
wx.Yield()
print display
if display == 1: #Show the big plot
print 'big_plot showing'
big_plot.set_canvas(main_canvas)
main_canvas.Show()
time.sleep(0.01) #Fastest time you can pick
wx.Yield()
else:
print 'small_plots showing'
main_canvas.Hide()
wx.Yield()
self.Refresh(canvas = main_canvas)
display = not(display)
return display
def Refresh(self,canvas = None,figure = None):
wx.Yield()
if canvas != None:
print "draw"
canvas.draw()
self.Update()
self.figurePanel.Update()
wx.Yield()
class FigurePanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.figPanel = self
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.figure = Figure(figsize = (8,6.1), dpi =60)
self.ax = self.figure.add_subplot(1,1,1)
self.ax.plot([1,2,3],[1,2,3])
self.enlarged_figure = Figure(figsize = (8,6.1), dpi = 60)
self.ax1 = self.enlarged_figure.add_subplot(2,1,1)
self.ax2 = self.enlarged_figure.add_subplot(2,1,2)
self.ax1.plot([1,2,3],[1,4,9])
self.ax2.plot([1,2,3],[1,4,9])
self.canvas = FigureCanvas(self, -1, self.figure)
self.enlarged_canvas = FigureCanvas(self,-1,self.enlarged_figure)
self.Layout()
self.Fit()
if __name__ == "__main__":
app = wx.App(False)
fr = myframe()
app.MainLoop()
To make the display change, click on the figure.
Related
I need to update an imshow() figure packed in tkinter. Here's a code example:
import matplotlib
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import tkinter as tk
import random
matplotlib.use('TkAgg')
def get_data():
return [[random.randint(1, 100), random.randint(1, 100)], [random.randint(1, 100), random.randint(1, 100)]]
class MainWindow:
def __init__(self, window):
self.window = window
self.figureCanvas = FigureCanvas(self.window)
self.button = tk.Button(window, text="Update", command=self._button_command)
self.button.pack()
self._pack_figure()
def _button_command(self):
self.figureCanvas.data = get_data()
self.figureCanvas.plot()
def _pack_figure(self):
canvas = FigureCanvasTkAgg(self.figureCanvas.figure, master=self.window)
canvas.get_tk_widget().pack()
canvas.draw()
class FigureCanvas:
data = []
def __init__(self, window):
self.window = window
self.figure = Figure(figsize=(6, 6))
self._create_plot_object()
def _create_plot_object(self):
self.axes = self.figure.add_subplot(111)
self.plot_object = self.axes.imshow([[0, 0], [0, 0]])
def update(self):
self.plot_object.set_data(self.data)
_window = tk.Tk()
_window.title("Snapshot")
start = MainWindow(_window)
_window.mainloop()
It plots the first image [[0, 0], [0, 0]] fine, but it doesn't re-draw after the image data has updated by plot_object.set_data(self.data)
Update
I have tried calling the following functions under FigureCanvas.update():
matplotlib.backend_bases.FigureCanvasBase(self.figure).draw_idle()
self.axes.redraw_in_frame()
A correct version of the code could look like this. I got rid of the false FigureCanvas and put everything in one class (sure you can use different classes, but don't name them confusingly). Also several other issues are fixed here (e.g. not calling the callback, supplying min and max color values).
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import tkinter as tk
def get_data():
return np.random.randint(1,100,size=(2,2))
class MainWindow:
def __init__(self, window):
self.window = window
self.button = tk.Button(window, text="Update", command=self._button_command )
self.button.pack()
self._pack_figure()
self._create_plot_object()
def _button_command(self):
self.data = get_data()
self.plot()
def _pack_figure(self):
self.figure = Figure(figsize=(6, 6))
self.canvas = FigureCanvasTkAgg(self.figure, master=self.window)
self.canvas.get_tk_widget().pack()
def _create_plot_object(self):
axes = self.figure.add_subplot(111)
self.plot_object = axes.imshow([[0, 0], [0, 0]], vmin=0, vmax=100)
def plot(self):
self.plot_object.set_data(self.data)
self.canvas.draw_idle()
_window = tk.Tk()
_window.title("Snapshot")
start = MainWindow(_window)
_window.mainloop()
I'd like to be able to drag and drop a file on my Matplotlib plot, and do something with said file (like open and plot it!). Unfortunately, while my script handles a few event using:
fig.canvas.mpl_connect('button_release_event', self.btn_release)
and the like, I can't find anything that will return the path of a file dropped on it.
I'm not quite at the level where I want to create GUIs with embedded plots, so if there is a solution without doing that, I would prefer it.
You seem to wish a drop_file_event was handled by mpl_connect ; unfortunately this is not the case according to the documentation (and it is a case a bit specific for a generalist plotting library anyway).
However, it is not so difficult to implement your own GUI handling drop event. Here below an example mostly based on embedding_in_wx2 and adding a wx.FileDropTarget.
# Used to guarantee to use at least Wx2.8
import wxversion
wxversion.ensureMinimal('2.8')
import numpy as np
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
class MyFileDropTarget(wx.FileDropTarget):
def __init__(self, window):
wx.FileDropTarget.__init__(self)
self.window = window
def OnDropFiles(self, x, y, filenames):
fig = self.window.figure
inaxes = fig.get_axes()[0]
h_pix = int(fig.get_figheight() * fig.get_dpi()) # fig height in pixels
message = "%d file(s) dropped at (%d,%d):\n" % (len(filenames), x, y)
for file in filenames:
message += file + "\n"
inaxes.annotate(message, (x, h_pix-y), xycoords='figure pixels')
self.window.draw()
class CanvasPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.figure = Figure()
self.axes = self.figure.add_subplot(111)
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.add_toolbar()
self.Fit()
win_target = self.canvas
dt = MyFileDropTarget(win_target)
win_target.SetDropTarget(dt)
def draw(self):
t = np.linspace(0.0, 2., 100)
s = np.sin(2 * np.pi * t)
self.axes.plot(t, s)
def add_toolbar(self):
self.toolbar = NavigationToolbar2Wx(self.canvas)
self.toolbar.Realize()
if wx.Platform == '__WXMAC__':
# Mac platform (OSX 10.3, MacPython) does not seem to cope with
# having a toolbar in a sizer. This work-around gets the buttons
# back, but at the expense of having the toolbar at the top
self.SetToolBar(self.toolbar)
else:
# On Windows platform, default window size is incorrect, so set
# toolbar width to figure width.
tw, th = self.toolbar.GetSizeTuple()
fw, fh = self.canvas.GetSizeTuple()
# By adding toolbar in sizer, we are able to put it at the bottom
# of the frame - so appearance is closer to GTK version.
# As noted above, doesn't work for Mac.
self.toolbar.SetSize(wx.Size(fw, th))
self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
# update the axes menu on the toolbar
self.toolbar.update()
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = wx.Frame(None, title='File drop test')
panel = CanvasPanel(frame)
panel.draw()
frame.Show()
app.MainLoop()
I have an issue with graphing data within wxPython - this code below works but it's not exactly right: For now I plot random numbers which are multiples of an entry box, this is done every 100ms.
My issue is that the entire history of numbers is shown as a pose is a (say) running window of 25 samples. I initially tried redrawing the graph on each collection of 100 samples, something like, if( length(data)%100 ): drawGraph but again this didn't look correct.
Thoughts and suggestions welcome.
My code:
print( "\n- Please Wait -- Importing Matplotlib and Related Modules...\n" )
import random
import matplotlib
import numpy
import wx
import u3
import numpy as np
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 TemperaturePanel( wx.Panel ) :
def __init__( self, parent, position ) :
wx.Panel.__init__( self, parent, pos=position, size=(800,320) )
# initialize matplotlib
self.figure = matplotlib.figure.Figure( None, facecolor="white" )
self.canvas = matplotlib.backends.backend_wxagg.FigureCanvasWxAgg( self, -1, self.figure )
self.axes = self.figure.add_subplot(111)
self.axes.grid(True, color="gray")
self.axes.set_xbound( (0,5) )
self.axes.set_ybound( (3,80) )
self.axes.set_xlabel( "Minutes" )
self.axes.set_ylabel( "Temperature ($^\circ$C)" )
self.axes = self.figure.add_subplot(111)
self.axes.grid(True, color="gray")
self._SetSize()
self.Bind( wx.EVT_SIZE, self._SetSize )
self.TemperatureData = []
def updateTemperature(self, value):
self.TemperatureData.append( value )
length = len(self.TemperatureData)
x = np.arange( length )
y = np.array(self.TemperatureData)
yMin = round(min(y)) - 2
yMax = round(max(y)) + 2
self.axes.plot(x,y, "-k")
self.axes.set_ybound( (yMin,yMax) )
self.canvas = FigureCanvas(self, -1, self.figure)
#-----------------------------------------------------------------------------------
def _SetSize( self, event=None ):
pixels = self.GetSize()
self.SetSize( pixels )
self.canvas.SetSize( pixels )
dpi = self.figure.get_dpi()
self.figure.set_size_inches( float( pixels[0] ) / dpi,float( pixels[1] ) / dpi )
#------------------------------------------------------------------------------------
class MainWindow(wx.Frame):
def __init__(self, parent):
#wx.Frame.__init__(self, *args, **kwargs)
wx.Frame.__init__(self, parent, title="Graph Issue", size=(1000,600))
self.panel = wx.Panel(self)
self.spin = wx.SpinCtrl(self.panel)
self.button = wx.Button(self.panel, label="Update")
self.stop = wx.Button(self.panel, label="Stop")
self.sizer = wx.BoxSizer()
self.sizer.Add(self.spin)
self.sizer.Add(self.button)
self.sizer.Add(self.stop)
self.TemperatureGraph = TemperaturePanel( self, position=(20, 50) )
self.panel.SetSizerAndFit(self.sizer)
self.Show()
# Use EVT_CHAR_HOOK on Frame insted of wx.EVT_KEY_UP on SpinCtrl
# to disable "on Enter go to next widget" functionality
self.Bind(wx.EVT_CHAR_HOOK, self.OnKey)
self.button.Bind(wx.EVT_BUTTON, self.OnUpdate)
self.stop.Bind(wx.EVT_BUTTON, self.OnStop)
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
self.Bind(wx.EVT_TIMER, self.updateTemperature, self.timer)
self.timer.Start(100)
self.value = 0
def OnKey(self, e):
if e.GetKeyCode() == wx.WXK_RETURN: # Is the key ENTER?
self.value = self.spin.GetValue() # Read SpinCtrl and set internal value
else: # Else let the event out of the handler
e.Skip()
def OnUpdate(self, e):
self.value = self.spin.GetValue() # Read SpinCtrl and set internal value
def OnTimer(self, e):
# Show internal value
print(self.value)
def updateTemperature(self, e):
Temperature = self.value*random.uniform(-1,1) # obtain currnt temperature
self.TemperatureGraph.updateTemperature(Temperature) # add temperature to graph
def OnStop(self, e):
self.timer.Stop()
self.Destroy()
app = wx.App(False)
win = MainWindow(None)
app.MainLoop()
If I understood the question correctly, you need 25 last temperature values only to be shown in your graph instead of all history of values. If that's what you want, then in the updateTemperature subroutine only the last 25 values should be plotted:
if length < 25:
x = np.arange(length)
y = np.array(self.TemperatureData)
else:
x = np.arange(length-25, length)
y = np.array(self.TemperatureData)[-25:]
To make the plot look better, x axis can be adjusted the same way you do it with y axis:
xMin = 0 if length < 25 else length-25
xMax = 25 if length < 25 else length
self.axes.set_xbound( (xMin,xMax) )
If the plot looks OK to you, and the issue is about the memory leak that causes the graph to freeze after ~200 iterations, that's due to the creation of FigureCanvas on every temperature update. Instead, you can re-use your existing FigureCanvas, changing the last line of updateTemperature to
self.canvas.draw()
I'm developing a simple demonstration GUI for a multi-lateral ultrasonic rangefinder. A device captures ultrasonic signals from several different sensors, performs time of flight processing on these signals, then uses the range information of detected targets to localize an object in 2D cartesian coordinates.
I'd like to create a wxPython GUI, which uses matplotlib to display each of the sensors signals and plot the target locations. I've found some example code which has roughly the same layout that I'd like to have, and have removed some of the code's unnecessary components. The python code is below:
import sys,os,csv
import numpy as N
import wx
import matplotlib
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import \
FigureCanvasWxAgg as FigCanvas, \
NavigationToolbar2WxAgg as NavigationToolbar
class FinalProject(wx.Frame):
title = ' Ultrasound Demo '
def __init__(self):
wx.Frame.__init__(self, None, -1, self.title)
self.create_menu()
self.create_status_bar()
self.create_main_panel()
def create_menu(self):
self.menubar = wx.MenuBar()
menu_file = wx.Menu()
m_expt = menu_file.Append(-1, "&Save plot\tCtrl-S", "Save plot to file")
self.Bind(wx.EVT_MENU, self.on_save_plot, m_expt)
menu_file.AppendSeparator()
m_exit = menu_file.Append(-1, "E&xit\tCtrl-X", "Exit")
self.Bind(wx.EVT_MENU, self.on_exit, m_exit)
self.menubar.Append(menu_file, "&File")
self.SetMenuBar(self.menubar)
def create_main_panel(self):
self.panel = wx.Panel(self)
self.dpi = 100
self.fig = Figure((9.5, 5.0), dpi=self.dpi)
self.canvas = FigCanvas(self.panel, -1, self.fig)
# self.axes1 = self.fig.add_subplot2grid((2,2), (0,0))
self.axes1 = self.fig.add_subplot(2,1,1)
# self.axes2 = self.fig.add_subplot2grid((2,2), (1,0))
self.axes2 = self.fig.add_subplot(2,1,2)
self.toolbar = NavigationToolbar(self.canvas)
self.vbox = wx.BoxSizer(wx.VERTICAL)
self.vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
self.vbox.AddSpacer(10)
self.hbox = wx.BoxSizer(wx.HORIZONTAL)
flags = wx.ALIGN_LEFT | wx.ALL | wx.ALIGN_CENTER_VERTICAL
self.panel.SetSizer(self.vbox)
self.vbox.Fit(self)
def create_status_bar(self):
self.statusbar = self.CreateStatusBar()
def on_draw_button1(self, event):
self.axes1.clear()
self.axes2.clear()
i = N.arange(0,4,1)
q = i
w = N.arange(-4,0,1)
self.axes1.plot(q,i,'red')
self.axes2.plot(w,i,'yellow')
self.canvas.draw()
def on_draw_button2(self, event):
self.axes1.clear()
self.axes2.clear()
a = [0,1,2,3,4,]
b = [5.5,4.5,3.5,2.5,1.5]
c = [7.5,2.5,4,6.8,10.6]
self.axes1.plot(b,a,'purple')
self.axes2.plot(c,a,'black')
self.canvas.draw()
def on_save_plot(self, event):
file_choices = "PNG (*.png)|*.png"
dlg = wx.FileDialog(
self,
message="Save plot as...",
defaultDir=os.getcwd(),
defaultFile="plot.png",
wildcard=file_choices,
style=wx.SAVE)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
self.canvas.print_figure(path, dpi=self.dpi)
self.flash_status_message("Saved to %s" % path)
def on_exit(self, event):
self.Destroy()
if __name__ == '__main__':
app = wx.PySimpleApp()
app.frame = FinalProject()
app.frame.Show()
app.MainLoop()
del app
So, this code would be useful for displaying two captured signals, and it's relatively easy to add additional subplots, provided they exist on a symmetrical grid, but what I would like to do is add a third subplot to the right of these two plots which spans the height of both.
To be clear what I would like to do is add a third subplot to the right of the existing plots the height of which is equal to the current canvas height.
Reading through the matplotlib documentation it looks like the appropriate function to do this would be plt.subplot2grid(). Unfortunately I get errors when I attempt to use this function to define the current subplots (the code I attempted to use is commented out below:
self.axes1 = self.fig.add_subplot2grid((2,2), (0,0)))
Has anyone else attempted this? Any ideas on where I might be going wrong?
Thanks!
Sounds like you have already figured out something to do what you wanted.
To be explicit, there is nothing specific about the fact that you are using WX python in this example - essentially the question boils down to how one would go about adding an axes to a figure which has the same height as two other axes.
This can be done very simply with:
import matplotlib.pyplot as plt
ax1 = plt.subplot(2, 2, 1)
ax2 = plt.subplot(2, 2, 3)
ax3 = plt.subplot(1, 2, 2)
plt.show()
HTH
I'm trying to edit an example I found that embeds a mataplot into a wx frame.
When I execute the code it works:
-reads in data from CSV containing date,frequency on each line (e.g. "2009-01-10, 100")
-draws the chart correctly in the wx frame.
However, I'm trying to figure out how to make the x axis show dates from the csv data not 1,2,4,5,6.. I was able to do this correctly in another python program I have using:
plt.xticks(range(len(dates)), (dates), rotation=45)
but cant figure out how to do something similar here..
#!/usr/bin/env python
"""
An example of how to use wx or wxagg in an application with the new
toolbar - comment out the setA_toolbar line for no toolbar
"""
# Used to guarantee to use at least Wx2.8
import wxversion
wxversion.ensureMinimal('2.8')
import csv
from numpy import arange, sin, pi
import matplotlib
# uncomment the following to use wx rather than wxagg
#matplotlib.use('WX')
#from matplotlib.backends.backend_wx import FigureCanvasWx as FigureCanvas
# comment out the following to use wx rather than wxagg
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 wx
class CanvasFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,None,-1,
'CanvasFrame',size=(550,350))
self.SetBackgroundColour(wx.NamedColor("WHITE"))
self.figure = Figure()
with open('c:\\charts.csv', 'rb') as n:
reader = csv.reader(n)
dates = []
freq = []
for row in reader:
values = row[0].split(',')
dates.append(values[0])
freq.append(values[1])
self.axes = self.figure.add_subplot(111)
false_x = [x for x in range(len(dates))]
self.axes.plot(false_x,freq, 'o-')
##self.axes.plot(t,s)
# self.axes.plot.xticks(range(len(dates)), (dates), rotation=45)
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()
self.add_toolbar() # comment this out for no toolbar
def add_toolbar(self):
self.toolbar = NavigationToolbar2Wx(self.canvas)
self.toolbar.Realize()
if wx.Platform == '__WXMAC__':
# Mac platform (OSX 10.3, MacPython) does not seem to cope with
# having a toolbar in a sizer. This work-around gets the buttons
# back, but at the expense of having the toolbar at the top
self.SetToolBar(self.toolbar)
else:
# On Windows platform, default window size is incorrect, so set
# toolbar width to figure width.
tw, th = self.toolbar.GetSizeTuple()
fw, fh = self.canvas.GetSizeTuple()
# By adding toolbar in sizer, we are able to put it at the bottom
# of the frame - so appearance is closer to GTK version.
# As noted above, doesn't work for Mac.
self.toolbar.SetSize(wx.Size(fw, th))
self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
# update the axes menu on the toolbar
self.toolbar.update()
def OnPaint(self, event):
self.canvas.draw()
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()
Thanks in advance for the help!
Here is the code of xticks():
def xticks(*args, **kwargs):
ax = gca()
if len(args)==0:
locs = ax.get_xticks()
labels = ax.get_xticklabels()
elif len(args)==1:
locs = ax.set_xticks(args[0])
labels = ax.get_xticklabels()
elif len(args)==2:
locs = ax.set_xticks(args[0])
labels = ax.set_xticklabels(args[1], **kwargs)
else: raise TypeError('Illegal number of arguments to xticks')
if len(kwargs):
for l in labels:
l.update(kwargs)
draw_if_interactive()
return locs, silent_list('Text xticklabel', labels)
and you called it as following:
plt.xticks(range(len(dates)), (dates), rotation=45)
so you can use the code in xticks() that deal with len(args)==2. Add the following two lines after calling self.axes.plot(...) in your code:
self.axes.set_xticks(range(len(dates)))
self.axes.set_xticklabels(dates, rotation=45)