Как анимировать точки на графике функций в Racket? - PullRequest
4 голосов
/ 20 сентября 2019

Я делаю визуализацию с графическим интерфейсом для генетического алгоритма и хочу иметь возможность построить функцию максимизации и точки каждого поколения индивидуумов над этой функцией.Для каждого поколения я хочу, чтобы только точки были стерты, а следующие были нанесены на график уже существующей функции.

Используя функцию 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))))

Примечание: точки выше были сгенерированы случайным образом и не соответствуют выводу генетического алгоритма, поэтому нет функции, которая могла бы соответствовать этим координатам.

Я ожидаю построить график функции за этимиточки, чтобы увидеть, как происходит максимизация.

1 Ответ

2 голосов
/ 23 сентября 2019

Здесь много чего просят.Но, по сути, вы хотите поместить свой график на не совсем белый фон, таким образом, вы можете поместить что-то еще (в данном случае график функции) в фоновом режиме.Вы можете сделать это с помощью параметра 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.

И теперь нам нужно обновить функцию рисования, чтобы нарисовать этот график на фоне:

(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 Очевидно, это зависит от деталей того, что вы рассчитываете, и от того, как быстро вы хотите нарисовать это.Это может быть достаточно быстро.;)

...