racket/collects/plot/common/legend.rkt
Neil Toronto e90ec4b69f Added unstable/latent-contract
Reorganized contracts
Started exposing customization API in plot/utils
Now dog-fooding customization API in earnest
2011-11-10 12:59:41 -07:00

192 lines
11 KiB
Racket
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#lang racket/base
;; Functions that create legend entries and lists of legend entries.
(require racket/class racket/match racket/list racket/string racket/sequence racket/contract
"contract.rkt"
"contract-doc.rkt"
"format.rkt"
"draw.rkt"
"utils.rkt")
(provide (all-defined-out))
(struct legend-entry (label draw) #:transparent)
;; ===================================================================================================
;; Line legends
(defproc (line-legend-entry [label string?]
[color plot-color/c] [width (>=/c 0)] [style plot-pen-style/c]
) legend-entry?
(legend-entry label (λ (plot-area x-min x-max y-min y-max)
(define y (* 1/2 (+ y-min y-max)))
(send plot-area set-pen color width style)
(send plot-area set-alpha 1)
(send plot-area draw-line (vector x-min y) (vector x-max y)))))
(defproc (line-legend-entries [label string?] [zs (listof real?)] [z-labels (listof string?)]
[colors plot-colors/c] [widths pen-widths/c] [styles plot-pen-styles/c]
) (listof legend-entry?)
(define hash
(for/fold ([hash empty]) ([z (in-list zs)]
[z-label (in-list z-labels)]
[color (in-cycle (maybe-apply/list colors zs))]
[width (in-cycle (maybe-apply/list widths zs))]
[style (in-cycle (maybe-apply/list styles zs))])
(assoc-cons hash (list color width style) z-label)))
(reverse
(for/list ([entry (in-list hash)])
(match-define (cons args vs) entry)
(apply line-legend-entry
(cond [(= 1 (length vs)) (format "~a = ~a" label (first vs))]
[else (format "~a ∈ {~a}" label (string-join (reverse vs) ","))])
args))))
;; ===================================================================================================
;; Rectangle legends
(defproc (rectangle-legend-entry [label string?]
[fill-color plot-color/c] [fill-style plot-brush-style/c]
[line-color plot-color/c] [line-width (>=/c 0)]
[line-style plot-pen-style/c]) legend-entry?
(legend-entry label (λ (plot-area x-min x-max y-min y-max)
(send plot-area set-brush fill-color fill-style)
(send plot-area set-pen line-color line-width line-style)
(send plot-area set-alpha 1)
(send plot-area draw-rectangle (vector x-min y-min) (vector x-max y-max)))))
(defproc (rectangle-legend-entries [label string?] [zs (listof real?)]
[fill-colors plot-colors/c] [fill-styles plot-brush-styles/c]
[line-colors plot-colors/c] [line-widths pen-widths/c]
[line-styles plot-pen-styles/c]) (listof legend-entry?)
(define z-min (first zs))
(define z-max (last zs))
(define digits (digits-for-range z-min z-max))
(define hash
(for/fold ([hash empty]) ([z (in-list zs)]
[fill-color (in-cycle (maybe-apply/list fill-colors zs))]
[fill-style (in-cycle (maybe-apply/list fill-styles zs))]
[line-color (in-cycle (maybe-apply/list line-colors zs))]
[line-width (in-cycle (maybe-apply/list line-widths zs))]
[line-style (in-cycle (maybe-apply/list line-styles zs))])
(define entry-label (real->plot-label z digits))
(assoc-cons hash (list fill-color fill-style line-color line-width line-style) entry-label)))
(reverse
(for/list ([entry (in-list hash)])
(match-define (cons (list fill-color fill-style line-color line-width line-style) vs) entry)
(rectangle-legend-entry (if (= 1 (length vs))
(format "~a = ~a" label (first vs))
(format "~a ∈ {~a}" label (string-join (reverse vs) ",")))
fill-color fill-style line-color line-width line-style))))
;; ===================================================================================================
;; Interval legends
(defproc (interval-legend-entry
[label string?]
[fill-color plot-color/c] [fill-style plot-brush-style/c]
[line-color plot-color/c] [line-width (>=/c 0)] [line-style plot-pen-style/c]
[line1-color plot-color/c] [line1-width (>=/c 0)] [line1-style plot-pen-style/c]
[line2-color plot-color/c] [line2-width (>=/c 0)] [line2-style plot-pen-style/c]
) legend-entry?
(legend-entry label (λ (plot-area x-min x-max y-min y-max)
(send plot-area set-alpha 1)
;; rectangle
(send plot-area set-pen line-color line-width line-style)
(send plot-area set-brush fill-color fill-style)
(send plot-area draw-rectangle (vector x-min y-min) (vector x-max y-max))
;; bottom line
(send plot-area set-pen line1-color line1-width line1-style)
(send plot-area draw-line (vector x-min y-max) (vector x-max y-max))
;; top line
(send plot-area set-pen line2-color line2-width line2-style)
(send plot-area draw-line (vector x-min y-min) (vector x-max y-min)))))
(defproc (interval-legend-entries
[label string?] [zs (listof real?)] [z-labels (listof string?)]
[fill-colors plot-colors/c] [fill-styles plot-brush-styles/c]
[line-colors plot-colors/c] [line-widths pen-widths/c] [line-styles plot-pen-styles/c]
[line1-colors plot-colors/c] [line1-widths pen-widths/c] [line1-styles plot-pen-styles/c]
[line2-colors plot-colors/c] [line2-widths pen-widths/c] [line2-styles plot-pen-styles/c]
) (listof legend-entry?)
(define hash
(for/fold ([hash empty]) ([za (in-list zs)]
[zb (in-list (rest zs))]
[la (in-list z-labels)]
[lb (in-list (rest z-labels))]
[fill-color (in-cycle (maybe-apply/list fill-colors zs))]
[fill-style (in-cycle (maybe-apply/list fill-styles zs))]
[line-color (in-cycle (maybe-apply/list line-colors zs))]
[line-width (in-cycle (maybe-apply/list line-widths zs))]
[line-style (in-cycle (maybe-apply/list line-styles zs))]
[line1-color (in-cycle (maybe-apply/list line1-colors zs))]
[line1-width (in-cycle (maybe-apply/list line1-widths zs))]
[line1-style (in-cycle (maybe-apply/list line1-styles zs))]
[line2-color (in-cycle (maybe-apply/list line2-colors zs))]
[line2-width (in-cycle (maybe-apply/list line2-widths zs))]
[line2-style (in-cycle (maybe-apply/list line2-styles zs))])
(define entry-label (format "[~a,~a]" la lb))
(assoc-cons hash
(list fill-color fill-style line-color line-width line-style
line1-color line1-width line1-style
line2-color line2-width line2-style)
entry-label)))
(reverse
(for/list ([entry (in-list hash)])
(match-define (cons (list fill-color fill-style line-color line-width line-style
line1-color line1-width line1-style
line2-color line2-width line2-style)
vs)
entry)
(interval-legend-entry (format "~a ∈ ~a" label (string-join (reverse vs) " "))
fill-color fill-style line-color line-width line-style
line1-color line1-width line1-style
line2-color line2-width line2-style))))
(defproc (contour-intervals-legend-entries
[label string?] [zs (listof real?)] [z-labels (listof string?)]
[fill-colors plot-colors/c] [fill-styles plot-brush-styles/c]
[line-colors plot-colors/c] [line-widths pen-widths/c] [line-styles plot-pen-styles/c]
[contour-colors plot-colors/c] [contour-widths pen-widths/c]
[contour-styles plot-pen-styles/c]) (listof legend-entry?)
(define n (- (length zs) 2))
(define ccs (append (list 0)
(sequence-take (in-cycle (maybe-apply/list contour-colors zs)) 0 n)
(list 0)))
(define cws (append (list 0)
(sequence-take (in-cycle (maybe-apply/list contour-widths zs)) 0 n)
(list 0)))
(define css (append '(transparent)
(sequence-take (in-cycle (maybe-apply/list contour-styles zs)) 0 n)
'(transparent)))
(interval-legend-entries label zs z-labels
fill-colors fill-styles line-colors line-widths line-styles
ccs cws css (rest ccs) (rest cws) (rest css)))
;; ===================================================================================================
;; Point legends
(defproc (point-legend-entry [label string?] [sym point-sym/c]
[color plot-color/c] [size (>=/c 0)] [line-width (>=/c 0)]) legend-entry?
(legend-entry label (λ (plot-area x-min x-max y-min y-max)
(send plot-area set-pen color line-width 'solid)
(send plot-area set-alpha 1)
(send plot-area draw-glyphs
(list (vector (* 1/2 (+ x-min x-max)) (* 1/2 (+ y-min y-max))))
sym size))))
(defproc (vector-field-legend-entry [label string?] [color plot-color/c]
[line-width (>=/c 0)] [line-style plot-pen-style/c]
) legend-entry?
(legend-entry label (λ (plot-area x-min x-max y-min y-max)
(send plot-area set-pen color line-width line-style)
(send plot-area set-alpha 1)
(send plot-area draw-arrow-glyph
(vector (* 1/2 (+ x-min x-max)) (* 1/2 (+ y-min y-max)))
(* 1/4 (- x-max x-min)) 0))))