首页 > 解决方案 > 如何在 Racket 中的函数图上为点设置动画?

问题描述

我正在为遗传算法制作 GUI 可视化,并希望能够在该函数上绘制最大化函数和每一代个体的点。对于每一代,我只希望删除点,并将下一个点绘制在已经存在的函数图上。

使用该功能plot/dc,我正在实现为每一代个体设置动画,从坐标列表中绘制所有点。但是这个方法每次运行时都会重绘画布。所以我不能在点后面绘制函数本身。我可以列出每一代的功能和要点,但这会浪费资源。

使用此代码,您应该能够模拟我的实际开发状态。

#lang racket

(require racket/gui plot)

(define main-window (new frame% [label "FUNCTION AND POINTS"] [width 200] [height 600]))
(define canvas-panel (new panel% [parent main-window]))
(define function-canvas (new canvas% [parent canvas-panel]))

(define (plot-points list-of-points)
  (for-each
   (λ (population)
     (plot/dc (points population
                      #:x-min 0
                      #:x-max 3
                      #:y-min 0
                      #:y-max 9
                      #:color 'red)
              (send function-canvas get-dc)
              0 0
              (- (send canvas-panel get-width) 40)
              (- (send canvas-panel get-height) 40))
     (sleep/yield 1))
   list-of-points))

(send main-window show #t)

(plot-points '(((1 8) (2 5) (2.5 2))
                 ((2 5) (1.5 6.5) (2 3))
                 ((1.5 3) (2 2) (1.5 3.5))
                 ((2 7) (0.5 1) (2 0.5))
                 ((0.5 9) (0 5) (0.5 0))
                 ((0 1) (1 4.5) (0 8.5))))

注意:上面的点是随机生成的,与遗传算法输出不对应,所以没有一个函数可以匹配这个坐标。

我希望在这些点后面绘制函数图形,以便能够看到发生的最大化。

标签: user-interfaceplotracket

解决方案


这里有很多问题。但本质上你想把你的情节放在一个非全白的背景上,这样你就可以把别的东西(在这种情况下是一个函数情节)放在背景中。您可以使用background-alpha参数执行此操作。

将此行添加到上面的代码中:

(plot-background-alpha 0)

将让这些点不断建立在彼此之上。由于您表示要移动点,因此您还需要在每个“帧”之间清除屏幕,您可以通过将绘图功能更改为:

(define (plot-points list-of-points)
  (for-each
   (λ (population)
     (define dc (send function-canvas get-dc))
     (send dc clear)
     (plot/dc .... elided ....
              dc
              0 0
              (- (send canvas-panel get-width) 40)
              (- (send canvas-panel get-height) 40))
     (sleep/yield 1))
   list-of-points))

现在来绘制你的实际背景。您可以每帧重新计算它,但正如您所指出的那样太慢了。1所以我们可以计算一次,将其渲染为图像,然后重新绘制每个“帧”。假设您在后台想要的函数是 (+ (sin (* 5 x)) 3),您的代码如下所示:

(define plot-func (function (λ (x) (+ (sin (* 5 x)) 3))
                            0 (* 2 pi)))

(define plot-background
  (plot-bitmap plot-func
               #:x-min 0
               #:x-max 3
               #:y-min 0
               #:y-max 9
               #:width (- (send canvas-panel get-width) 40)
               #:height (- (send canvas-panel get-height) 40)))

请注意,get-width调用该方法get-height之前不会存储实际画布的宽度/高度。show

现在我们需要更新 draw 函数来将这个图绘制到背景中:

(define (plot-points list-of-points)
  (for-each
   (λ (population)
     (define dc (send function-canvas get-dc))
     (send dc clear)
     (send dc draw-bitmap plot-background 0 0)
     ... elided ...
     (sleep/yield 1))
   list-of-points))

把它们放在一起给出:

#lang racket

(require racket/gui plot)

(define main-window (new frame% [label "FUNCTION AND POINTS"] [width 200] [height 600]))
(define canvas-panel (new panel% [parent main-window]))
(define function-canvas (new canvas% [parent canvas-panel]))
(send main-window show #t)
(plot-background-alpha 0)

(define plot-func (function (λ (x) (+ (sin (* 5 x)) 3))
                            0 (* 2 pi)))

(define plot-background
  (plot-bitmap plot-func
               #:x-min 0
               #:x-max 3
               #:y-min 0
               #:y-max 9
               #:width (- (send canvas-panel get-width) 40)
               #:height (- (send canvas-panel get-height) 40)))

(define (plot-points list-of-points)
  (for-each
   (λ (population)
     (define dc (send function-canvas get-dc))
     (send dc clear)
     (send dc draw-bitmap plot-background 0 0)
     (plot/dc (points population
                      #:x-min 0
                      #:x-max 3
                      #:y-min 0
                      #:y-max 9
                      #:color 'red)
              dc
              0 0
              (- (send canvas-panel get-width) 40)
              (- (send canvas-panel get-height) 40))
     (sleep/yield 1))
   list-of-points))

(plot-points '(((1 8) (2 5) (2.5 2))
                 ((2 5) (1.5 6.5) (2 3))
                 ((1.5 3) (2 2) (1.5 3.5))
                 ((2 7) (0.5 1) (2 0.5))
                 ((0.5 9) (0 5) (0.5 0))
                 ((0 1) (1 4.5) (0 8.5))))

1显然,这取决于您正在计算的细节以及您想要绘制它的速度。它实际上可能已经足够快了。;)


推荐阅读