0
votes

I want to develop a GUI application that allows me to plot candlestick bars, and then to manually draw lines on the plot.

I am working on Linux, so would prefer a solution that is cross platform, or at least runs on Linux. I tend to use Python a lot, and have used C# (with mono on Linux) in the past. I have done some research and it seems to suggest that wxPython or PyQwt (both used in conjunction with matplotlib) would be the way to go. Ihave to admit that I am biased toward Python, since a lot of my existing scripts are in Python. However, C# has a good GUI library and if it is the better tool in this instance, then I will be willing to use it instead of the Python based solutions.

The requirements of the application are as follows:

  1. Plot candlesticks
  2. Displaying the coordinates under the mouse as the cursor moves about
  3. Scrolling the plot left/right
  4. zoom in/out
  5. Redraw plot when window is resized
  6. Change granularity of plotted graph
  7. Manually draw lines on chart (for current granularity)
  8. Show/hide lines for a particular granularity on the plot
  9. Programatically access the manually drawn lines
  10. Save plot to file as an image

Since wxPython, PyQwt and C# (generally speaking) are new to me, I would like to know which:

  • is the best approach for implementing the above requirements
  • represents the shallowest learning curve

A snippet showing a barebones skeleton to get me started (using either wxPython, pyQt, pyQwt or C#) would be very helpful.

2
It is doable in any standard GUI library and I do not think it really matters which one you use. They usually provide similar tools and interfaces. I have recently used matplotlib and it may match all your needs. - Fenikso

2 Answers

0
votes

Quick and simple example in wxPython:

import wx
import math
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas

class Graph(wx.Panel):
    def __init__(self, *args, **kwargs):
        wx.Panel.__init__(self, *args, **kwargs)
        self.figure = Figure()
        self.canvas = FigureCanvas(self, -1, self.figure)
        self.Bind(wx.EVT_SIZE, self.OnSize)

    def OnSize(self, event):
        size = self.GetSize()
        self.canvas.SetSize(size)

    def Draw(self):
        self.figure.clear()
        self.subplot = self.figure.add_subplot(111)
        x = [a*(math.pi/50) for a in range(100)]
        y = [self.f(a) for a in x]
        self.subplot.plot(x, y)
        self.canvas.draw()

    def DrawCosine(self, e):
        self.f = math.cos
        self.Draw()

    def DrawSine(self, e):
        self.f = math.sin
        self.Draw()        


class MainWindow(wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)

        self.panel = wx.Panel(self)
        self.button1 = wx.Button(self.panel, label="Sine")
        self.button2 = wx.Button(self.panel, label="Cosine")
        self.graph = Graph(self.panel)
        self.graph.DrawSine(None)

        self.button1.Bind(wx.EVT_BUTTON, self.graph.DrawSine)
        self.button2.Bind(wx.EVT_BUTTON, self.graph.DrawCosine)

        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer2 = wx.BoxSizer()

        self.sizer.Add(self.graph, 1, wx.ALL | wx.EXPAND)
        self.sizer2.Add(self.button1, 1, wx.ALL | wx.EXPAND)
        self.sizer2.Add(self.button2, 1, wx.ALL | wx.EXPAND)
        self.sizer.Add(self.sizer2, 0, wx.ALL | wx.EXPAND)

        self.panel.SetSizerAndFit(self.sizer)  
        self.Show()

app = wx.App(False)
win = MainWindow(None)
app.MainLoop()

But based on your requirements maybe using (or slightly redesigning) pyplot would be just good enough:

import wx
import math
from matplotlib import pyplot

class MainWindow(wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)

        self.panel = wx.Panel(self)
        self.button1 = wx.Button(self.panel, label="Sine")
        self.button2 = wx.Button(self.panel, label="Cosine")

        self.button1.Bind(wx.EVT_BUTTON, self.DrawSine)
        self.button2.Bind(wx.EVT_BUTTON, self.DrawCosine)

        self.sizer = wx.BoxSizer()

        self.sizer.Add(self.button1)
        self.sizer.Add(self.button2)

        self.panel.SetSizerAndFit(self.sizer)  
        self.Show()

    def Draw(self):
        x = [a*(math.pi/50) for a in range(100)]
        y = [self.f(a) for a in x]
        pyplot.plot(x, y)
        pyplot.grid(True, which='both', axis="both")
        pyplot.show()

    def DrawCosine(self, e):
        self.f = math.cos
        self.Draw()

    def DrawSine(self, e):
        self.f = math.sin
        self.Draw() 

app = wx.App(False)
win = MainWindow(None)
app.MainLoop()
0
votes

wxpython is much better for your purpose. A very good tutorial exists which covers most of the basics here.