Problem using plot-snip in racket 6.2

84 views
Skip to first unread message

Alex Harsanyi

unread,
Jul 24, 2015, 3:57:13 AM7/24/15
to Racket Developers

Hi,

I'm using the plot-snip function to have interactive plots inside other GUI elements in my application.  This worked fine under Racket 6.1.1 but fails under Racket 6.2 (bot versions are 64 bit on Windows).  The program below illustrates the problem:  the function `working` creates a plot window using plot-frame.  The plot is resized correctly and the interactive zoom works as expected.  The function `not-working` tries to do the same, but creates the plot using plot-snip than adds it to a snip canvas.  It does essentially what plot-frame does, without the error checking (I copied out the functions from he plot package).  With this version, the plot is not resized correctly inside the window and zoom in and out does not work correctly.   Both functions work as expected under Racket version 6.1.1.

The program makes use of snip-canvas% which is in unstable/gui, but as far as I can tell, it has not changed between the two versions.

Does anyone know what needs to be done to get this to work, or is this a bug in the plot package?

Thanks,
Alex.

#lang racket/gui
(require plot)
(require unstable/gui/snip)

;; snip-frame% and make-snip-frame are copied from
;; C:\Program Files\Racket\share\pkgs\plot-gui-lib\plot\private\gui\gui.rkt

(define snip-frame%
  (class frame%
    (define/override (on-traverse-char event)
      (define key-code (send event get-key-code))
      (case key-code
        [(escape)  (send this show #f)]
        [else  (super on-traverse-char event)]))
   
    (super-new)))

(define (make-snip-frame snip width height label)
  (define (make-snip w h) snip)
 
  (define frame
    (new snip-frame% [label label] [width (+ 20 width)] [height (+ 20 height)]))
 
  (new snip-canvas%
       [parent frame]
       [make-snip make-snip]
       [horiz-margin 5] [vert-margin 5]
       [horizontal-inset 5] [vertical-inset 5])
 
  frame)

;; This works as expected when resizing the window and zooming the graph
(define (working)
  (parameterize ([plot-width    150]
                 [plot-height   150]
                 [plot-x-label  #f]
                 [plot-y-label  #f])
    (send (plot-frame (function sqr -2 2)) show #t)))

;; This does not
(define (not-working)
  (parameterize ([plot-width    150]
                 [plot-height   150]
                 [plot-x-label  #f]
                 [plot-y-label  #f])
    ;; this is essentially what plot-frame does sans error checking
    (send (make-snip-frame (plot-snip (function sqr -2 2)) 200 200 "hello") show #t)))

Alex Harsanyi

unread,
Oct 4, 2015, 9:36:36 PM10/4/15
to Racket Developers
Hi,

I posted this question a while ago but I didn't receive any response.  I just retested the code with the current snapshot (6.2.900.17) and it has the same behavior (bug?). 

Could someone please test this code on their machine and at least confirm whether it works correctly or not for them?

If there's a bug in the code below, could you point out what it is?  As I mentioned, the code works fine in 6.1.1 and I cannot find anything that has changed in this area in version 6.2.

Note that in recent Racket snapshots snip-canvas% has moved, so, in the code below, the "(require unstable/gui/snip)" should be replaced with "(require mrlib/snip-canvas)".

Thanks,
Alex.

Vincent St-Amour

unread,
Oct 5, 2015, 4:26:54 PM10/5/15
to Alex Harsanyi, Racket Developers, Neil Toronto
Hi Alex,

Sorry for the late response.

I can confirm the behavior you observed. I don't see anything wrong with
your code at first glance, so I'm not sure what the problem is.

Neil: Any ideas?

Vincent



On Sun, 04 Oct 2015 20:36:35 -0500,
> --
> You received this message because you are subscribed to the Google
> Groups "Racket Developers" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to racket-dev+...@googlegroups.com.
> To post to this group, send email to racke...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/racket-dev/c2517296-2a7a-4e49-b617-21cfac413710%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Alex Harsanyi

unread,
Dec 6, 2015, 6:30:23 AM12/6/15
to Racket Developers, neil.t...@gmail.com, stam...@eecs.northwestern.edu

Hi Vincent,

This is still a problem in Racket 6.3.  I tried to debug the problem but I was unsuccessful.  Tried to use a pasteboard% instead, but the plot-snip% did not work correctly with that either.  Do you have any advice on where to start looking?

What I'm trying to do is embed plot-snip% objects inside a GUI.  Is there a way to do that?  I could only find plot-frame which always creates a new frame.

For reference, this is that application that is affected: https://github.com/alex-hhh/ActivityLog2.  The last Racket version that works with this is 6.1.1

Best Regards,
Alex.

Vincent St-Amour

unread,
Dec 7, 2015, 2:09:43 PM12/7/15
to Alex Harsanyi, Racket Developers, neil.t...@gmail.com, stam...@eecs.northwestern.edu
Alex,

I've looked into this a little bit more, and it looks like the
`not-working` function (which is, as you say, doing essentially the same
thing as `plot-frame`) is actually kind of working, but is actually
stuttering very badly.

An important detail here is that `plot` is written in Typed Racket,
whereas your code uses regular, untyped Racket. Interfacing Typed Racket
and Racket code may involve a lot of dynamic checks, which can have
significant overhead, and cause that kind of stuttering.

*Where* that boundary lies, though, matters a lot.

If you use `plot-frame`, its (typed) implementation uses the (typed)
version of `make-snip-frame` from inside the `plot` library. The
boundary then lies between your driver code and `plot-frame`. That's not
a very heavily trafficked boundary, so the overhead is minimal.

If you use your hand-rolled equivalent of `plot-frame`, you're using
your own, untyped version of `make-snip-frame`, so the boundary lies
between the typed `plot-snip` and your untyped `make-snip-frame`. That
seems to be a more trafficked boundary, hence the stuttering.

(To complicate matters, Neil uses some tricks to add types to
`make-snip-frame` after the fact, without boundary overhead, which is
why the version you copied looked (and kind of was) untyped.)

Just to confirm, I've converted your file to Typed Racket, and used the
typed version of `make-snip-frame`, and the problem goes away.


So the bottom line is, using `pict-snip` from untyped code may be too
slow to be usable. You may want to write the portion of your program
that uses it in Typed Racket.

Vincent

Alex Harsanyi

unread,
Dec 8, 2015, 7:21:17 AM12/8/15
to Racket Developers, alexha...@gmail.com, neil.t...@gmail.com, stam...@eecs.northwestern.edu
Hi Vincent,

Thanks for looking into this.  I changed the code so that make-plot-snip is now typed and the problem goes away.  I will now have to find a way to put this fix into my code, as the solution is not particularly elegant and relies on undocumented features (type-environment and parse-syntax).

I inserted my fixed version below, in case you have any suggestions on how to improve it.

However, I'm not sure I understand your explanation. I was expecting most of the interactions for drawing the window to be between the frame, the plot-canvas and the plot-snip.  The first two objects are created in an untyped environment and the plot-snip, while typed, is inserted into the snip-canvas in an untyped environment as well.  Adding a type declaration to make-plot-snip should not have helped much as the interaction between the snip-canvas and the plot-snip is an untyped-typed boundary.  So basically, adding type declaration to make-plot-snip fixes the problem, but I have no idea why.

Best Regards,
Alex,

#lang typed/racket/gui
(require plot) ; Racket 6.3

;; make-snip-frame is similar to the one in

;; C:\Program Files\Racket\share\pkgs\plot-gui-lib\plot\private\gui\gui.rkt

(module glue typed-racket/base-env/extra-env-lang

  (provide make-snip-frame)
 
  (module types typed/racket/base
    (require (only-in typed/racket/gui Snip% Frame%))
    (provide (all-defined-out))
    (define-type Make-Snip-Frame
      (-> (Instance Snip%)
          Positive-Real
          Positive-Real
          String
          (Instance Frame%))))

  (module untyped-functions racket/gui
    (require mrlib/snip-canvas)
    (provide make-snip-frame)

   
    (define (make-snip-frame snip width height label)
      (define frame
        (new frame% [label label] [width (+ 20 width)] [height (+ 20 height)]))
      (new snip-canvas%
           [parent frame]
           [make-snip (lambda (w h) snip)]

           [horiz-margin 5] [vert-margin 5]
           [horizontal-inset 5] [vertical-inset 5])
      frame))

  (require 'types
           (for-syntax (submod 'types #%type-decl))
           'untyped-functions)

  (type-environment
   [make-snip-frame (parse-type #'Make-Snip-Frame)]))

(require 'glue)


;; This works as expected when resizing the window and zooming the graph
(define (plot-working)

  (parameterize ([plot-width    150]
                 [plot-height   150]
                 [plot-x-label  #f]
                 [plot-y-label  #f])
    (send (plot-frame (function sqr -2 2)) show #t)))

;; This does not work in version 6.2 or newer but works fine in version 6.1.1.
;; Try resizing the frame and zooming the plot to see the problem.  Compare it
;; with the frame produced by `plot-working`
(define (plot-not-working)

  (parameterize ([plot-width    150]
                 [plot-height   150]
                 [plot-x-label  #f]
                 [plot-y-label  #f])
    ;; this is essentially what plot-frame does sans error checking
    (send (make-snip-frame (plot-snip (function sqr -2 2)) 150 150 "hello") show #t)))

Robby Findler

unread,
Dec 8, 2015, 7:42:55 AM12/8/15
to Alex Harsanyi, Racket Developers, Neil Toronto, Vincent St-Amour
Maybe the type on the result of make-plot-snip ends up with types on
the methods of the snip and that makes the typed/untyped boundary be
at the point where those methods are called? (And those methods are
called a lot as the window does its work on callbacks)

Robby
> https://groups.google.com/d/msgid/racket-dev/9969d282-294c-4549-a472-cf2ee94dd653%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages