wx Graphing Widget

Amir Taaki wrote:

I have made a graph plotting widget for wxPython

Have you looked at some of the existing solutions to build from, like wxPyPlot and Matplotlib?

Also take a look at wx.lib.floatcanvas You could use it to do this, or, if not, you could get ideas from it. It's double buffered, and doesn't have much in the way of flicker. Feel free to ask me any questions you have about it.

Also, make sure you look at the DoubleBufferedWindow example in the Wiki.

Now, any of you that run it will notice horrible flickering as you move the mouse, drag a selection box .etc

When you want to draw a selection box, you should just draw it with a wx.ClientDC, using mode XOR and a BlackPen. Don't try to put the selection box in your buffer and keep re-drawing it. See wx.lib.floatcanvas.FloatCanvas.py for an example.

In the OnDraw function I have done this

if abs(time.time() - self.last_time):
       return

That's just going to make a big delay, and isn't really solving the problem.

I haven't had time to really look to much into your code, but I have a few suggestions:

1) use 4 spaces instead of tabs to indent. It's more or less a python standard.

2) use:

import wx

rather than

from wxPython.wx import *

If you do that, all the wxSomething names will be wx.Something instead.

3) You've got a problem with your mouse Capture. Make sure the capture is released! I think you should always release the capture on a MouseUp

4) Never call OnPaint outside of a Paint event. See the Double Buffer demo in the Wiki for how to do it right.

That should get you started.

NOTE: if you send me a note, I can send you the latest version of FloatCanvas, which includes a demo for editing objects, which should tell you all you need to know to use FloatCanvas to do this.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                          
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

About the import wx, I don't really see why the C++ wxWidgets library
doesn't use namespaces yet the python version has to (and the wxPython
demo hasn't even been updated to take this change into consideration
when all it would take, would be a s/wx/wx\./). To be honest I'm not
seeing namespace pollution happening just yet with the wx prefix :wink:

wxPython users don't /have/ to. However, following the zen of:
    Namespaces are one honking great idea -- let's do more of those!
... suggests that wx.Name is better than wxName, and most wxPython users
would tend to agree. Further, since all of the demos have been
converted to the wx namespace, along with basically every piece of code
(I've not translated some myself, mostly because 'sed s/wx/wx\./'
doesn't always work - search for the demo conversion wiki).

And even though python recommends using 4 spaces, I personally find 8
space tabs clearer to read and easier to edit, so until I am forced to
switch to python 2.6 I will probably carry on, as is.

It's about interoperability. If you are planning to share your code
with the rest of the world, the majority of the rest of the world uses 4
spaces without tabs. If you are planning on not sharing, then you only
need to deal with interoperability like this when recieving and/or
sending code for questions, like you already have.

- Josiah

···

Amir Taaki <genjix@gmail.com> wrote:

Oops, I didn't finish the sentence...

... it seems likely that at some point wxName will be deprecated in
favor of wx.Name, and support for wxName will be removed.

- Josiah

···

Josiah Carlson <jcarlson@uci.edu> wrote:

Amir Taaki <genjix@gmail.com> wrote:
> About the import wx, I don't really see why the C++ wxWidgets library
> doesn't use namespaces yet the python version has to (and the wxPython
> demo hasn't even been updated to take this change into consideration
> when all it would take, would be a s/wx/wx\./). To be honest I'm not
> seeing namespace pollution happening just yet with the wx prefix :wink:

wxPython users don't /have/ to. However, following the zen of:
    Namespaces are one honking great idea -- let's do more of those!
... suggests that wx.Name is better than wxName, and most wxPython users
would tend to agree. Further, since all of the demos have been
converted to the wx namespace, along with basically every piece of code
(I've not translated some myself, mostly because 'sed s/wx/wx\./'
doesn't always work - search for the demo conversion wiki).

Amir Taaki wrote:

Thank you so very much for your reply - it was most helpful.

You're quite welcome.

Yes I had looked at Matplotlib, SciPy and PyPlotter. wxPyPlot looks
promising but it doesn't look like its made for graph editing.

No, but it's fairly simple, why write the whole thing when all you need to write is the editing part? Even if you don't' use it, you can get ideas from it.

On the other hand, the float canvas sounds most promising, but I can't
seem to find any working links and the wxPython floatcanvas demo
throws with

genjix@amir /usr/share/doc/wxPython-2.4.2.4/demo $ python demo.py
Traceback (most recent call last):
  File "/usr/share/doc/wxPython-2.4.2.4/demo/Main.py", line 528, in OnSelChanged
    self.RunDemo(itemText)
  File "/usr/share/doc/wxPython-2.4.2.4/demo/Main.py", line 556, in RunDemo
    module = __import__(itemText, globals())
  File "/usr/share/doc/wxPython-2.4.2.4/demo/FloatCanvas.py", line 39, in ?
    from wxPython.lib import floatcanvas
  File "/usr/lib/python2.4/site-packages/wx-2.6-gtk2-ansi/wxPython/lib/floatcanvas.py",
line 9, in ?
    Circle = wx.lib.floatcanvas.Circle
AttributeError: 'module' object has no attribute 'Circle'
genjix@amir /usr/share/doc/wxPython-2.4.2.4/demo $

wxPython 2.4.2.4 is pretty old. I could have sworn FloatCanvas worked in that version, but who knows? I do have the last version that worked with 2.4.2 archived at work, if you want me to send it to you.

You could also comment out the section of code that's throwing that error and see if you can get it to run. However, I have added a LOT to FloatCanvas since that version. I don't remember exactly the state of the event binding, but I'm pretty sure it's improved.

2.4.2 is a pretty old version. You really, really want to upgrade!

About the import wx, I don't really see why the C++ wxWidgets library
doesn't use namespaces yet the python version has to (and the wxPython
demo hasn't even been updated to take this change into consideration
when all it would take, would be a s/wx/wx\./).

The demo has been updated in newer versions.

Name spaces are a inherent part of Python -- they are tacked on, and for some odd reason, little used in C++. When the switch was made for wxPython, the wxWidgets folks were talking about using name spaces for C++ also, but backward compatibility won out.

I know calling OnPaint is a problem, but what should I be doing
instead? How force a redraw (I don't just want to redraw the buffer).

If you are changing the Buffer, you can then blit it to the screen yourself with a wxClientDC. Also, you should NEVER call OnPaint yourself, but there are times when a Refresh() and/or Update is called for.

Here's the key, however. When you are drawing something that is not intended to be persistent, like the selection box (some call it a rubber band box), you don't need to draw to the buffer at all. You can just draw to the screen. Take a look in the floatcanvas code to see how this is done. Here's some code cut out of FloatCanvas and trimmed for simplicity, that should give you the idea:

     def LeftDownEvent(self,event):
                 self.StartRBBox = array( event.GetPosition() )
                 self.PrevRBBox = None
                 self.CaptureMouse()

     def LeftUpEvent(self,event):
       if self.HasCapture():
             self.ReleaseMouse()

     def MotionEvent(self,event):
         if ( event.Dragging() and
              event.LeftIsDown() and
              not (self.StartRBBox is None):

             xy0 = self.StartRBBox
             xy1 = array( event.GetPosition() )
             wh = xy1 - xy0

             dc = wx.ClientDC(self)
             dc.BeginDrawing()
             dc.SetPen(wx.Pen('WHITE', 2, wx.SHORT_DASH))
             dc.SetBrush(wx.TRANSPARENT_BRUSH)
             dc.SetLogicalFunction(wx.XOR)
             if self.PrevRBBox:
                 ## This restores the screen to the original image.
                 dc.DrawRectanglePointSize(*self.PrevRBBox)
             self.PrevRBBox = ( xy0, wh )
             dc.DrawRectanglePointSize( *self.PrevRBBox )
             dc.EndDrawing()

In fact, in my FloatCanvas based polygon editor (ask me and I can send it, but it's 2.6 only), I do a similar thing while moving points int eh polygon. I draw directly to the screen to show the moving segments and only update the buffered image after the Mouse is released.

Maybe I should use OpenGL? (I am using OpenGL in my app anyway, so
maybe I could benefit from the hw accel)

I'm not sure you'd get any benefit unless you are doing something 3-d, but if you're using it anyway, and you're comfortable with it, it might make sense.

if self.HasCapture():
  self.ReleaseMouse()

Is this sufficient? or should I be doing

That should do it.

self.ReleaseMouse()

It should be, but I think you get an error if you call this when the Mouse isn't captured.

Thank you for taking your time to reply.

Good luck. If you can move to 2.6.*, ask me for the latest FloatCanvas, it should make this pretty simple.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                          
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Amir Taaki wrote:

On the other hand, the float canvas sounds most promising,

it is different than those in that is designed to b a library with which to build your own way of viewing data.

I am using wxPython 2.6, but since portage keeps wxPython-docs as a seperate package and the newest version of those are 2.6...
Maybe I will download wxPython 2.6 just for the docs :slight_smile:

I think the demo and docs are separate packages anyway. You really don't want to use old docs!

Yes, well I had been having some reservations about this myself and in the end went with wxA syntax rather than wx.A since everyone else seemed to be doing it.

We all were with version 2.4.*, but not many people still do. Mostly newbies that are getting confused by old docs and examples.

Say I stop dragging the box... How does this know to before a repaint blanking the screen?

I don't understand that question.

As far as I can tell the OnPaint call is only called when the screen needs to update (?), therefore in the above code when I stop dragging the box remains?

You can refresh the screen yourself with a wxClientDC, or a call to Refresh(). In the FloatCanvas case, when the user lifts the Mouse, they have zoomed the image, so it all gets re-drawn anyway.

What happens to the previous drawn box as well?

Thats what this does:
              if self.PrevRBBox:
> ## This restores the screen to the original image.
> dc.DrawRectanglePointSize(*self.PrevRBBox)

If you draw the same thing twice with XOR, you get back what you started with.

yes please, float canvas looks the most useful :slight_smile: Any and all demos would be good.

I'll send it along to you in a separate email.

demo/FloatCanvas.py?
The fixdc module fixes the DC API for wxPython2.5.1.6

I've gotten rid of that, it was only needed for one version that no one should be using now anyway.

Thank you again, you are being most helpful :slight_smile: Since I've been bothering you all this time, I just thought it would be only fair to show you what I've been working on this for :slight_smile:

http://sourceforge.net/project/screenshots.php?group_id=152980 (in case you're wondering)

That looks pretty cool!

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov