This is the first post! I look forward to working with you!
There is an opportunity to draw a graph in real time in the GUI, and it is a summary at that time. Since the GUI used wxpython, I used wx.lib.plot in the same wx module. I had a hard time finding articles on the time axis, so I hope you find it helpful.
mac OS python 3.8.5 wxpython 4.1.0
python
import wx
import wx.lib
import wx.lib.plot as plot
Arrange in the order of wx.Frame-> wx.Panel-> plot.Canvas.
python
import wx
import wx.lib
import wx.lib.plot as plot
#Used for graph drawing
import random
#Value to draw
x_val = list(range(10))
y_val = [random.randint(0, 10) for i in range(10)] # 0~10 random values up to 10
# [(x1, y1), (x2, y2),...(xn, yn)]Transformed to pass to the graph in the format
xy_val = list(zip(x_val, y_val))
class MainFrame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(500, 500))
#panel creation
self.panel = wx.Panel(self, -1)
#graph creation
self.plotter = plot.PlotCanvas(self, -1)
#Create a line to display&drawing
line = plot.PolyLine(xy_val)
gc = plot.PlotGraphics([line])
self.plotter.Draw(gc)
#sizer creation&Installation
sizer = wx.GridSizer(1, 1, gap=(0, 0))
sizer.Add(self.plotter, flag=wx.EXPAND)
self.SetSizer(sizer)
#Display GUI in the center of the screen
self.Center()
self.Show()
def main():
app = wx.App()
MainFrame(None, -1, 'WxLibPlot')
app.MainLoop()
if __name__ == '__main__':
main()
result
Add graph title, legend, label Enable zoom or drag function Change font size, line color and weight
Zoom and drag cannot coexist, so enabling one disables the other.
Change the code below self.plotter = plot.PlotCanvas (self, -1) in the above code.
python
self.plotter.enableLegend = True #Set the legend display to True
self.plotter.fontSizeTitle = 18 #Set the font size of the graph title to 18.(Default=15)
self.plotter.fontSizeLegend = 18 #Set the font size of the legend to 18.(Default=7)
self.plotter.fontSizeAxis = 18 #xy label,Set the font size of the coordinates to 18.(Default=10)
#Enable the zoom or drag function. Only one can be enabled
# self.plotter.enableZoom = True
self.plotter.enableDrag = True
#Create a line to display&drawing()
line = plot.PolyLine(xy_val, legend='sample', colour='red', width=4) #Added legend text, changed line color to red and thickness to 4
gc = plot.PlotGraphics([line], 'WxLibPlot', 'xaxis', 'yaxis') #Graph title and xy label added
result Drag is enabled.
Use wx.Timer to draw a line graph that takes a random value every second. This time, we have added a button to control the start and end of the plot.
python
import wx
import wx.lib
import wx.lib.plot as plot
#Used for graph drawing
import random
class MainFrame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(500, 500))
#panel creation
self.panel = wx.Panel(self, -1)
#Button for start and stop measurement
self.start_button = wx.Button(self, -1, label='start')
self.stop_button = wx.Button(self, -1, label='stop')
#graph creation
self.plotter = plot.PlotCanvas(self, -1)
#Initial value of plot point
self.x_val = 0
self.xy_val = []
self.plotter.enableLegend = True #Set the legend display to True
self.plotter.fontSizeTitle = 18 #Set the font size of the graph title to 18.(Default=15)
self.plotter.fontSizeLegend = 18 #Set the font size of the legend to 18.(Default=7)
self.plotter.fontSizeAxis = 18 #xy label,Set the font size of the coordinates to 18.(Default=10)
#Enable the zoom or drag function. Only one can be enabled
# self.plotter.enableZoom = True
# self.plotter.enableDrag = True
#Create a line to display&drawing()
line = plot.PolyLine(self.xy_val, legend='sample', colour='red', width=2) #Added legend text, changed line color to red and thickness to 4
gc = plot.PlotGraphics([line], 'RealTimePlot', 'xaxis', 'yaxis') #Graph title and xy label added
self.plotter.Draw(gc)
#Create a frame timer
self.timer = wx.Timer(self)
#sizer creation&Installation
sizer1 = wx.FlexGridSizer(2, 1, gap=(0, 0)) #Sizar for arranging 2 rows and 1 column graph and sizer2
sizer2 = wx.GridSizer(1, 2, gap=(0, 0)) #Sizar for arranging buttons in 1 row and 2 columns
sizer1.Add(self.plotter, flag=wx.EXPAND) # flag=wx.EXPAND:Extend the width and height to the maximum
sizer1.Add(sizer2, flag=wx.ALIGN_RIGHT) # flag=wx.ALIGN_RIGHT:Installed to the right
sizer1.AddGrowableCol(0) #Extend the width of the first row to the maximum
sizer1.AddGrowableRow(0) #Extend the height of the first line to the maximum
#Button installation
sizer2.Add(self.start_button)
sizer2.Add(self.stop_button)
self.SetSizer(sizer1)
#Events
self.start_button.Bind(wx.EVT_BUTTON, self.graph_start)
self.stop_button.Bind(wx.EVT_BUTTON, self.graph_stop)
self.Bind(wx.EVT_TIMER, self.graph_plot)
#Display GUI in the center of the screen
self.Center()
self.Show()
def graph_start(self, event):
self.plotter.Clear() #Initialize the graph
self.x_val, self.xy_val = 0, [] # x_val, xy_Initialize val
self.timer.Start(1000)
def graph_stop(self, event):
self.timer.Stop()
def graph_plot(self, event):
y_val = random.randint(0, 100)
self.xy_val.append((self.x_val, y_val))
line = plot.PolyLine(self.xy_val, legend='sample', colour='red', width=2)
gc = plot.PlotGraphics([line], 'RealTimePlot', 'xaxis', 'yaxis')
self.plotter.Draw(gc)
self.x_val += 1
def main():
app = wx.App()
MainFrame(None, -1, 'WxLibPlot')
app.MainLoop()
if __name__ == '__main__':
main()
result The reason why it turns white once after pressing the start button is because the graph is initialized.
The drawing method changes by changing the attribute called xSpec
python
self.plotter.xSpec = 'auto' # or 'min', int, (min, max), 'none'
From the top, it will be'auto','min', int, (min, max). 'auto' is the default. If you assign an integer type, the behavior is the same as'min', but the coordinates are fixed. In the above example, the graph is divided into 4 parts and the coordinates are displayed on the boundary.
'none' is omitted because it only erases the x-axis and label.
This is the part I wanted to write the most. Immediately, I will write the code and the result. The time interval is 1 second.
python
import datetime as dt
import random
import wx
import wx.lib
import wx.lib.plot as plot
class TimeAxisPlot(plot.PlotCanvas):
def __init__(self, parent, id):
plot.PlotCanvas.__init__(self, parent, id)
#Define layout relationships
self.enableLegend = True
self.fontSizeLegend = 18
self.fontSizeAxis = 18
self.xSpec = 4
self.startDate = dt.datetime.now()
self.data = []
line = plot.PolyLine(self.data, legend='sample', colour='red')
gc = plot.PlotGraphics([line], 'TimeAxisPlot', 'time', 'yaxis')
self.Draw(gc)
def _xticks(self, *args):
ticks = plot.PlotCanvas._xticks(self, *args)
# ticks = [(Plot points,Character to display), (),...()]
new_ticks = []
for tick in ticks:
t = tick[0]
time_value = self.startDate + dt.timedelta(seconds=t)
time_value_str = time_value.strftime('%H:%M:%S')
new_ticks.append([t, time_value_str])
# new_ticks = [(Plot points,Times of Day), (),...()]
#Change the displayed characters to time
return new_ticks
class MainFrame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(500, 500))
#panel creation
self.panel = wx.Panel(self, -1)
#Button for start and stop measurement
self.start_button = wx.Button(self, -1, label='start')
self.stop_button = wx.Button(self, -1, label='stop')
#graph creation
self.plotter = TimeAxisPlot(self, -1)
#Initial value of plot point
self.x_val = 0
self.xy_val = []
self.plotter.enableLegend = True #Set the legend display to True
self.plotter.fontSizeTitle = 18 #Set the font size of the graph title to 18.(Default=15)
self.plotter.fontSizeLegend = 18 #Set the font size of the legend to 18.(Default=7)
self.plotter.fontSizeAxis = 18 #xy label,Set the font size of the coordinates to 18.(Default=10)
#Create a line to display&drawing()
line = plot.PolyLine(self.xy_val, legend='sample', colour='red', width=2) #Added legend text, changed line color to red and thickness to 4
gc = plot.PlotGraphics([line], 'RealTimePlot', 'xaxis', 'yaxis') #Graph title and xy label added
self.plotter.Draw(gc)
#Create a frame timer
self.timer = wx.Timer(self)
#sizer creation&Installation
sizer1 = wx.FlexGridSizer(2, 1, gap=(0, 0)) #Sizar for arranging 2 rows and 1 column graph and sizer2
sizer2 = wx.GridSizer(1, 2, gap=(0, 0)) #Sizar for arranging buttons in 1 row and 2 columns
sizer1.Add(self.plotter, flag=wx.EXPAND) # flag=wx.EXPAND:Extend the width and height to the maximum
sizer1.Add(sizer2, flag=wx.ALIGN_RIGHT) # flag=wx.ALIGN_RIGHT:Installed to the right
sizer1.AddGrowableCol(0) #Extend the width of the first row to the maximum
sizer1.AddGrowableRow(0) #Extend the height of the first line to the maximum
#Button installation
sizer2.Add(self.start_button)
sizer2.Add(self.stop_button)
self.SetSizer(sizer1)
#Events
self.start_button.Bind(wx.EVT_BUTTON, self.graph_start)
self.stop_button.Bind(wx.EVT_BUTTON, self.graph_stop)
self.Bind(wx.EVT_TIMER, self.graph_plot)
#Display GUI in the center of the screen
self.Center()
self.Show()
def graph_start(self, event):
self.plotter.Clear() #Initialize the graph
self.x_val, self.xy_val = 0, [] # x_val, xy_Initialize val
self.timer.Start(1000)
def graph_stop(self, event):
self.timer.Stop()
def graph_plot(self, event):
y_val = random.randint(0, 100)
self.xy_val.append((self.x_val, y_val))
line = plot.PolyLine(self.xy_val, legend='sample', colour='red', width=2)
gc = plot.PlotGraphics([line], 'RealTimePlot', 'xaxis', 'yaxis')
self.plotter.Draw(gc)
self.x_val += 1
def main():
app = wx.App()
MainFrame(None, -1, 'TimeAxisPlot')
app.MainLoop()
if __name__ == '__main__':
main()
result
Inherit plot.Canvas to create a new class, overriding the x-axis method. here,
python
def _xticks(self, *args):
ticks = plot.PlotCanvas._xticks(self, *args)
# ex)ticks = [(0, '0.0'), (0.5, '0.5'), (1.0, '1.0'), (1.5, '1.5'), (2.0, '2.0')]
# [(x coordinate(float)), (x coordinateに表示する文字(str))...]
ticks returns [(x coordinate (float)), (character to display in x coordinate (str)) ...]. The time axis is created by changing the displayed characters to the time.
Method Create a tuple of coordinates and time and append to the empty list new_ticks ex) Start time: 0:00, ticks = [(0, '0.0'), (0.5, '0.5'), (1.0, '1.0'), (1.5, '1.5'), (2.0, '2.0' )]time
for sentence 1st
python
new_ticks = []
for tick in ticks: #Loop with the acquired ticks
#0th tuple(x coordinate point)Get
t = tick[0]
time_value = self.startDate + dt.timedelta(seconds=t)
time_value_str = time_value.strftime('%H:%M:%S')
new_ticks.append([t, time_value_str])
# new_ticks = [(Plot points,Times of Day), (),...()]
#Change the displayed characters to time
return new_ticks
Thank you for reading. As I noticed during execution, the fastest drawing speed was about 0.05s. Note that the execution speed did not change even if the timer interval was shorter than this.
official wx.lib.plot — wxPython Phoenix 4.1.1a1 documentation
Reference for real-time drawing wxPython: Draw animation and graph at the same time
Time axis reference [Note] Customize the y-axis scale of the plot ─ wxPython wxPython-users - wx.lib.plot custom labels?
Recommended Posts