Skip to content

Commit

Permalink
add plot-inset and plot-legend-padding parameters (#124)
Browse files Browse the repository at this point in the history
... to control the amount of space left unused around the plot edge and plot legend.
  • Loading branch information
alex-hhh authored Oct 6, 2023
1 parent b0da526 commit 2417c22
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 35 deletions.
41 changes: 41 additions & 0 deletions plot-doc/plot/scribblings/params.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,27 @@ Amount of ambient light, and whether 3D plots are rendered with diffuse and spec

}

@defparam[plot-inset inset (or/c (>=/c 0) (list (>=/c 0) (>=/c 0) (>=/c 0) (>=/c 0))) #:value 0]{

The amount of space around the plot to leave unused, when calculating plot
layouts for ticks and axis labels. The parameter can be specified as a
single value, which applies to all sides of the plot image, or as a list of
four separate values for the left, right, top, and bottom margins of the
plot image.

One example use for this parameter is to avoid clipping tick marks when
lines for plot elements are very thick, see @racket[plot-line-width] and
@racket[line-width]. In such a case, the end of axis ticks can be drawn
beyond the end point of the line, and might be clipped at the edge of the
drawing region. A non-zero @racket[plot-inset] value can be used to avoid
this clipping.

See also @racket[plot-legend-padding] for an equivalent setting for the plot
legend.

@history[#:added "8.11"]
}

@deftogether[((defparam plot-foreground color plot-color/c #:value 0)
(defparam plot-background color plot-color/c #:value 0))]{
The plot foreground and background color.
Expand Down Expand Up @@ -161,6 +182,26 @@ For example, the value @racket['(columns 1 equal-size)] will place the legend en
@history[#:added "7.9"]
}

@defparam[plot-legend-padding padding (or/c (>=/c 0) (list (>=/c 0) (>=/c 0) (>=/c 0) (>=/c 0))) #:value 0]{

The amount of space to add between the legend entries and the border drawn
around the legend. The parameter can be specified as a single value, which
applies to all sides, or as a list of four separate values for the left,
right, top, and bottom sides of the legend.

One example use for this parameter is to avoid clipping thick lines used in
legend entries, see @racket[plot-line-width] and @racket[line-width]. In
such a case, the end of the lines can be drawn outside the border of the
legend, a non-zero @racket[plot-legend-padding] value can be used to avoid
this situation.

See also @racket[plot-inset] for a similar setting for the entire plot
image.

@history[#:added "8.11"]
}


@defparam[plot-tick-size size (>=/c 0) #:value 10]{
The length of tick lines, in drawing units.
}
Expand Down
8 changes: 6 additions & 2 deletions plot-lib/plot/private/common/parameter-groups.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@
arrow-head-size-or-scale
arrow-head-angle
plot-line-cap
line-cap))
line-cap
plot-inset
plot-legend-padding))

(define-parameter-group plot3d-appearance
(plot3d-samples
Expand Down Expand Up @@ -114,7 +116,9 @@
(U (List '= Nonnegative-Real) Nonnegative-Real)
Nonnegative-Real
Plot-Pen-Cap
Plot-Pen-Cap)
Plot-Pen-Cap
(U Nonnegative-Real (List Nonnegative-Real Nonnegative-Real Nonnegative-Real Nonnegative-Real))
(U Nonnegative-Real (List Nonnegative-Real Nonnegative-Real Nonnegative-Real Nonnegative-Real)))
;;plot3d-appearance
(List Positive-Integer Real Real Nonnegative-Real Boolean Boolean)
;;plot-labels
Expand Down
15 changes: 14 additions & 1 deletion plot-lib/plot/private/common/parameters.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@
(defparam plot-legend-anchor anchor Legend-Anchor 'top-left)
(defparam plot-legend-layout layout Legend-Layout '(columns 1 equal-size))
(defparam2 plot-legend-box-alpha alpha Real Nonnegative-Real 2/3 (unit-ivl 'plot-legend-box-alpha))
(defparam plot-legend-padding
(U
;; A single padding value for all sides
Nonnegative-Real
;; Separate left, right, top, and bottom padding values
(List Nonnegative-Real Nonnegative-Real Nonnegative-Real Nonnegative-Real))
0.0)
(defparam plot-animating? Boolean #f)

(defparam plot-x-axis? Boolean #t)
Expand Down Expand Up @@ -108,7 +115,13 @@
(defparam plot-y-far-tick-label-anchor anchor Anchor 'left)

(defparam plot-decorations? Boolean #t)

(defparam plot-inset
(U
;; A single inset value for all sides
Nonnegative-Real
;; Separate left, right, top, and bottom inset values
(List Nonnegative-Real Nonnegative-Real Nonnegative-Real Nonnegative-Real))
0.0)
(defparam plot-pen-color-map (U Symbol #f) #f)
(defparam plot-brush-color-map (U Symbol #f) #f)

Expand Down
31 changes: 22 additions & 9 deletions plot-lib/plot/private/common/plot-device.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -614,12 +614,17 @@
;; the understanding is that Rect will be the complete dc for a legend outside the plot-area
;; and the plot-area otherwise

(: calculate-legend-parameters (-> (Listof legend-entry) Rect Anchor
(: calculate-legend-parameters (-> (Listof legend-entry)
Rect
Anchor
(U Nonnegative-Real
(List Nonnegative-Real Nonnegative-Real Nonnegative-Real Nonnegative-Real))

(Values Rect (Listof Exact-Rational)
Nonnegative-Exact-Rational (Listof Real) (Listof Real)
Nonnegative-Exact-Rational (Listof Real)
Boolean Nonnegative-Integer)))
(define/private (calculate-legend-parameters legend-entries rect legend-anchor)
(define/private (calculate-legend-parameters legend-entries rect anchor padding)
(define n (length legend-entries))
(define labels (map legend-entry-label legend-entries))
(match-define (vector (ivl x-min x-max) (ivl y-min y-max)) rect)
Expand Down Expand Up @@ -692,21 +697,28 @@

;; top-left corner of legend
(define legend-x-min
(case legend-anchor
(case anchor
[(top-left left bottom-left auto) x-min]
[(top-right right bottom-right) (- x-max legend-x-size)]
[(center bottom top) (- (* 1/2 (+ x-min x-max))
(* 1/2 legend-x-size))]))

(define legend-y-min
(case legend-anchor
(case anchor
[(top-left top top-right auto) y-min]
[(bottom-left bottom bottom-right) (- y-max legend-y-size)]
[(center left right) (- (* 1/2 (+ y-min y-max))
(* 1/2 legend-y-size))]))

(define legend-rect (vector (ivl legend-x-min (+ legend-x-min legend-x-size))
(ivl legend-y-min (+ legend-y-min legend-y-size))))
(define legend-rect
(let-values ([(pad-left pad-right pad-top pad-bottom)
(if (list? padding)
(values (list-ref padding 0) (list-ref padding 1) (list-ref padding 2) (list-ref padding 3))
(values padding padding padding padding))])
(vector (ivl (- legend-x-min pad-left)
(+ legend-x-min legend-x-size pad-right))
(ivl (- legend-y-min pad-top)
(+ legend-y-min legend-y-size pad-bottom)))))

;; per entry x/y left/top corners
(define label-x-mins (for/fold ([mins : (Listof Real) (list (+ legend-x-min horiz-gap))]
Expand All @@ -732,7 +744,7 @@
[else
(raise-argument-error 'draw-legend "rect-known?" 1 legend-entries rect)]))

(define/public (calculate-legend-rect legend-entries rect legend-anchor)
(define/public (calculate-legend-rect legend-entries rect anchor padding)
;; Change font for correct size calculation in calculate-legend-parameters
(define old-size (send (send dc get-font) get-point-size))
(define old-face (send (send dc get-font) get-face))
Expand All @@ -746,7 +758,7 @@
draw-x-size label-x-mins draw-x-mins
draw-y-size label-y-mins
cols? div)
(calculate-legend-parameters legend-entries rect legend-anchor))
(calculate-legend-parameters legend-entries rect anchor padding))

;; Undo change font
(set-font-attribs old-size old-face old-family)
Expand All @@ -755,6 +767,7 @@

(define/public (draw-legend legend-entries rect)
(define legend-anchor (plot-legend-anchor))
(define legend-padding (plot-legend-padding))
(when (not (eq? legend-anchor 'no-legend))
(match-define (list (legend-entry #{labels : (Listof (U String pict))}
#{draw-procs : (Listof Legend-Draw-Proc)})
Expand All @@ -774,7 +787,7 @@
draw-x-size label-x-mins draw-x-mins
draw-y-size label-y-mins
cols? div)
(calculate-legend-parameters legend-entries rect (legend-anchor->anchor legend-anchor)))
(calculate-legend-parameters legend-entries rect (legend-anchor->anchor legend-anchor) legend-padding))

;; legend background
(set-pen (plot-foreground) 1 'transparent)
Expand Down
7 changes: 6 additions & 1 deletion plot-lib/plot/private/common/types.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,12 @@
[draw-arrow-glyph (-> (Vectorof Real) Real Real Void)]
[draw-glyphs (-> (Listof (Vectorof Real)) Point-Sym Nonnegative-Real Void)]
[draw-pict (->* [pict (Vectorof Real)] (Anchor Real) Void)]
[calculate-legend-rect (-> (Listof legend-entry) Rect Anchor Rect)]
[calculate-legend-rect (-> (Listof legend-entry)
Rect
Anchor
(U Nonnegative-Real
(List Nonnegative-Real Nonnegative-Real Nonnegative-Real Nonnegative-Real))
Rect)]
[draw-legend (-> (Listof legend-entry) Rect Void)]))

(require "plotmetrics.rkt")
Expand Down
30 changes: 19 additions & 11 deletions plot-lib/plot/private/plot2d/plot-area.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,8 @@
legend
(vector (ivl dc-x-min (+ dc-x-min dc-x-size))
(ivl dc-y-min (+ dc-y-min dc-y-size)))
(legend-anchor->anchor legend-anchor)))]
(legend-anchor->anchor legend-anchor)
(plot-legend-padding)))]
[gap (pen-gap)]
[make-print
(λ ([get-bounds : (-> (Listof Real))])
Expand Down Expand Up @@ -640,16 +641,23 @@
(define: right : Real 0)
(define: top : Real 0)
(define: bottom : Real 0)
(let-values ([(left-val right-val top-val bottom-val)
(margin-fixpoint 0 dc-x-size 0 dc-y-size
init-left-margin init-right-margin
init-top-margin init-bottom-margin
(λ ([left : Real] [right : Real] [top : Real] [bottom : Real])
(get-param-vs/set-view->dc! left right top bottom)))])
(set! left left-val)
(set! right right-val)
(set! top top-val)
(set! bottom bottom-val))
(let ([inset (plot-inset)])
(let-values ([(left-inset right-inset top-inset bottom-inset)
(if (list? inset)
(values (list-ref inset 0) (list-ref inset 1) (list-ref inset 2) (list-ref inset 3))
(values inset inset inset inset))])
(let-values ([(left-val right-val top-val bottom-val)
(margin-fixpoint
left-inset (- dc-x-size right-inset)
top-inset (- dc-y-size bottom-inset)
init-left-margin init-right-margin
init-top-margin init-bottom-margin
(λ ([left : Real] [right : Real] [top : Real] [bottom : Real])
(get-param-vs/set-view->dc! left right top bottom)))])
(set! left left-val)
(set! right right-val)
(set! top top-val)
(set! bottom bottom-val))))

;; When an aspect ratio has been defined, adjust the margins so that the
;; actual plot area maintains this ratio.
Expand Down
30 changes: 19 additions & 11 deletions plot-lib/plot/private/plot3d/plot-area.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,8 @@
legend
(vector (ivl dc-x-min (+ dc-x-min dc-x-size))
(ivl dc-y-min (+ dc-y-min dc-y-size)))
(legend-anchor->anchor legend-anchor)))]
(legend-anchor->anchor legend-anchor)
(plot-legend-padding)))]
[none (λ () (values 0 0 title-margin 0))])
(cond
[legend-rect
Expand Down Expand Up @@ -978,16 +979,23 @@
(define: right : Real 0)
(define: top : Real 0)
(define: bottom : Real 0)
(let-values ([(left-val right-val top-val bottom-val)
(margin-fixpoint 0 dc-x-size 0 dc-y-size
init-left-margin init-right-margin
init-top-margin init-bottom-margin
(λ ([left : Real] [right : Real] [top : Real] [bottom : Real])
(get-param-vs/set-view->dc! left right top bottom)))])
(set! left left-val)
(set! right right-val)
(set! top top-val)
(set! bottom bottom-val))
(let ([inset (plot-inset)])
(let-values ([(left-inset right-inset top-inset bottom-inset)
(if (list? inset)
(values (list-ref inset 0) (list-ref inset 1) (list-ref inset 2) (list-ref inset 3))
(values inset inset inset inset))])
(let-values ([(left-val right-val top-val bottom-val)
(margin-fixpoint
left-inset (- dc-x-size right-inset)
top-inset (- dc-y-size bottom-inset)
init-left-margin init-right-margin
init-top-margin init-bottom-margin
(λ ([left : Real] [right : Real] [top : Real] [bottom : Real])
(get-param-vs/set-view->dc! left right top bottom)))])
(set! left left-val)
(set! right right-val)
(set! top top-val)
(set! bottom bottom-val))))

;; When an aspect ratio has been defined, adjust the margins so that the
;; actual plot area maintains this ratio.
Expand Down
2 changes: 2 additions & 0 deletions plot-lib/plot/private/utils-and-no-gui.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@
plot-legend-anchor
plot-legend-box-alpha
plot-legend-layout
plot-legend-padding
plot-decorations?
plot-inset
plot-animating?
plot-pen-color-map
plot-brush-color-map
Expand Down
33 changes: 33 additions & 0 deletions plot-test/plot/tests/PRs/124.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#lang racket

(require rackunit
plot racket/runtime-path
"../helpers.rkt")

;; see https://github.com/racket/plot/pull/124

(define-runtime-path pr124-data "./test-data/pr124.dat")

(define (do-plot-pr124 output-fn)
(parameterize
([plot-line-width 15]
[line-width 15]
[plot-inset '(0 10 10 0)]
[plot-pen-color-map 'set1]
[plot-legend-padding '(0 15 0 0)]
[plot-line-cap 'round]
[line-cap 'round])
(output-fn
(list
(function sin -5 5 #:color 0 #:label "sin(x)")
(function cos -5 5 #:color 1 #:label "cos(x)")))))

(define pr124-test-suite
(test-suite
"PR#124: Add plot-inset and plot-legend-padding parameters"
(test-case "pr124"
(check-draw-steps do-plot-pr124 pr124-data))))

(module+ test
(require rackunit/text-ui)
(run-tests pr124-test-suite))
Binary file added plot-test/plot/tests/PRs/test-data/pr124.dat
Binary file not shown.
Binary file added plot-test/plot/tests/PRs/test-data/pr124.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 2417c22

Please sign in to comment.